From 24bc9756666f8f7c70740a6d30a764ba7bc460df Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 5 Jun 2018 13:16:06 -0700 Subject: [PATCH 01/63] Cross target netcoreapp2.1 --- src/ImageSharp/ImageSharp.csproj | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index b1934faa6..390c65506 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -5,7 +5,7 @@ $(packageversion) 0.0.1 Six Labors and contributors - netstandard1.1;netstandard1.3;netstandard2.0 + netstandard1.1;netstandard1.3;netstandard2.0;netcoreapp2.1 true true SixLabors.ImageSharp @@ -29,7 +29,7 @@ portable True IOperation - 7.2 + 7.3 @@ -40,10 +40,14 @@ All + + + + - + From 3ea3c093ce33c182e2917a12e3d169e08e560775 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 5 Jun 2018 13:27:31 -0700 Subject: [PATCH 02/63] Use Encoding.UTF8 overload accepting span --- .../MetaData/Profiles/Exif/ExifReader.cs | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index 4f28449d6..d6f38882b 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -140,26 +140,27 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif private unsafe string ConvertToString(ReadOnlySpan buffer) { -#if NETSTANDARD1_1 - byte[] bytes = buffer.ToArray(); + Span nullChar = stackalloc byte[1] { 0 }; - string result = Encoding.UTF8.GetString(bytes, 0, buffer.Length); + int nullCharIndex = buffer.IndexOf(nullChar); + if (nullCharIndex > -1) + { + buffer = buffer.Slice(0, nullCharIndex); + } + +#if NETSTANDARD1_1 + return Encoding.UTF8.GetString(buffer.ToArray(), 0, buffer.Length); +#elif NETCOREAPP2_1 + return Encoding.UTF8.GetString(buffer); #else string result; fixed (byte* pointer = &MemoryMarshal.GetReference(buffer)) { - result = Encoding.UTF8.GetString(pointer, buffer.Length); + return Encoding.UTF8.GetString(pointer, buffer.Length); } #endif - int nullCharIndex = result.IndexOf('\0'); - if (nullCharIndex != -1) - { - result = result.Substring(0, nullCharIndex); - } - - return result; } /// From 40ea87482bfbf96f4808eadd459f557454d16f4e Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 5 Jun 2018 13:46:42 -0700 Subject: [PATCH 03/63] Remove unused variable --- src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index d6f38882b..d3ea9743f 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -154,8 +154,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif #elif NETCOREAPP2_1 return Encoding.UTF8.GetString(buffer); #else - string result; - fixed (byte* pointer = &MemoryMarshal.GetReference(buffer)) { return Encoding.UTF8.GetString(pointer, buffer.Length); From 23c1f8efd729903676bae6eef5e64605482872b7 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 5 Jun 2018 13:59:18 -0700 Subject: [PATCH 04/63] Use vectorized Span methods in DenseMatrix --- src/ImageSharp/Primitives/DenseMatrix{T}.cs | 39 +++++---------------- 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/src/ImageSharp/Primitives/DenseMatrix{T}.cs b/src/ImageSharp/Primitives/DenseMatrix{T}.cs index 5f3defd11..97fbdb2b3 100644 --- a/src/ImageSharp/Primitives/DenseMatrix{T}.cs +++ b/src/ImageSharp/Primitives/DenseMatrix{T}.cs @@ -105,6 +105,9 @@ namespace SixLabors.ImageSharp.Primitives } } + + public Span Span => new Span(Data); + /// /// Performs an implicit conversion from a to a . /// @@ -146,19 +149,13 @@ namespace SixLabors.ImageSharp.Primitives /// /// The value to fill each item with [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Fill(T value) - { - for (int i = 0; i < this.Data.Length; i++) - { - this.Data[i] = value; - } - } + public void Fill(T value) => this.Span.Fill(value); /// /// Clears the matrix setting each value to the default value for the element type /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Clear() => Array.Clear(this.Data, 0, this.Data.Length); + public void Clear() => this.Span.Clear(); /// /// Checks the coordinates to ensure they are within bounds. @@ -183,28 +180,10 @@ namespace SixLabors.ImageSharp.Primitives } /// - public bool Equals(DenseMatrix other) - { - if (this.Columns != other.Columns) - { - return false; - } - - if (this.Rows != other.Rows) - { - return false; - } - - for (int i = 0; i < this.Data.Length; i++) - { - if (!this.Data[i].Equals(other.Data[i])) - { - return false; - } - } - - return true; - } + public bool Equals(DenseMatrix other) => + this.Columns == other.Columns && + this.Rows == other.Rows && + this.Span.SequenceEqual(other.Span); /// public override bool Equals(object obj) => obj is DenseMatrix other && this.Equals(other); From b5ec02eb40a3c6b8847b0a647c366c5b238fae14 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 5 Jun 2018 14:12:27 -0700 Subject: [PATCH 05/63] Make Exif header a constant --- .../MetaData/Profiles/Exif/ExifConstants.cs | 21 +++++++++++++++++++ .../MetaData/Profiles/Exif/ExifWriter.cs | 19 +++++------------ 2 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 src/ImageSharp/MetaData/Profiles/Exif/ExifConstants.cs diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifConstants.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifConstants.cs new file mode 100644 index 000000000..cca53ba43 --- /dev/null +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifConstants.cs @@ -0,0 +1,21 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.MetaData.Profiles.Exif +{ + internal static class ExifConstants + { + public static readonly byte[] Header = { + (byte)'E', + (byte)'x', + (byte)'i', + (byte)'f', + 0x00, + 0x00, + (byte)'I', + (byte)'I', + 0x2A, + 0x00, + }; + } +} \ No newline at end of file diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs index f7363ef31..8749c0755 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs @@ -90,16 +90,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif byte[] result = new byte[length]; - result[0] = (byte)'E'; - result[1] = (byte)'x'; - result[2] = (byte)'i'; - result[3] = (byte)'f'; - result[4] = 0x00; - result[5] = 0x00; - result[6] = (byte)'I'; - result[7] = (byte)'I'; - result[8] = 0x2A; - result[9] = 0x00; + ExifConstants.Header.AsSpan().CopyTo(result); // 0-9 int i = 10; uint ifdOffset = ((uint)i - StartIndex) + 4; @@ -250,7 +241,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return length; } - private int WriteArray(ExifValue value, byte[] destination, int offset) + private int WriteArray(ExifValue value, Span destination, int offset) { if (value.DataType == ExifDataType.Ascii) { @@ -266,7 +257,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return newOffset; } - private int WriteData(List indexes, byte[] destination, int offset) + private int WriteData(List indexes, Span destination, int offset) { if (this.dataOffsets.Count == 0) { @@ -289,7 +280,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return newOffset; } - private int WriteHeaders(List indexes, byte[] destination, int offset) + private int WriteHeaders(List indexes, Span destination, int offset) { this.dataOffsets = new List(); @@ -370,7 +361,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } } - private int WriteValue(ExifValue value, byte[] destination, int offset) + private int WriteValue(ExifValue value, Span destination, int offset) { if (value.IsArray && value.DataType != ExifDataType.Ascii) { From e0612ad200986645fffa20fa763c22d1ebf4e679 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 5 Jun 2018 14:13:41 -0700 Subject: [PATCH 06/63] Use pattern matching --- src/ImageSharp/PixelFormats/Rgba1010102.cs | 2 +- src/ImageSharp/PixelFormats/Rgba32.cs | 2 +- src/ImageSharp/PixelFormats/Rgba64.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/Rgba1010102.cs index 166936d5e..ee4865e4e 100644 --- a/src/ImageSharp/PixelFormats/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/Rgba1010102.cs @@ -188,7 +188,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return (obj is Rgba1010102) && this.Equals((Rgba1010102)obj); + return obj is Rgba1010102 other && this.Equals(other); } /// diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index f6979aad8..bd014a58f 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -387,7 +387,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return (obj is Rgba32) && this.Equals((Rgba32)obj); + return obj is Rgba32 other && this.Equals(other); } /// diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index 1507a258c..5454e0fc1 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -187,7 +187,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override bool Equals(object obj) { - return (obj is Rgba64) && this.Equals((Rgba64)obj); + return obj is Rgba64 other && this.Equals(other); } /// From 369deb3cf6b29db27df28202d452c48eac4a0cad Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 5 Jun 2018 14:14:12 -0700 Subject: [PATCH 07/63] Remove trailing whitespace --- src/ImageSharp/Primitives/DenseMatrix{T}.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Primitives/DenseMatrix{T}.cs b/src/ImageSharp/Primitives/DenseMatrix{T}.cs index 97fbdb2b3..828aeadfa 100644 --- a/src/ImageSharp/Primitives/DenseMatrix{T}.cs +++ b/src/ImageSharp/Primitives/DenseMatrix{T}.cs @@ -180,9 +180,9 @@ namespace SixLabors.ImageSharp.Primitives } /// - public bool Equals(DenseMatrix other) => - this.Columns == other.Columns && - this.Rows == other.Rows && + public bool Equals(DenseMatrix other) => + this.Columns == other.Columns && + this.Rows == other.Rows && this.Span.SequenceEqual(other.Span); /// From 2f68ee011cf1e08c4d4cc18faceef22383d3f9a5 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 5 Jun 2018 14:27:06 -0700 Subject: [PATCH 08/63] Update dotnet to RTM --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index deb862197..5a146cea6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ matrix: - os: linux # Ubuntu 14.04 dist: trusty sudo: required - dotnet: 2.1.300-rc1-008673 + dotnet: 2.1.300 mono: latest # - os: osx # OSX 10.11 # osx_image: xcode7.3.1 From 128dd1a14741c9ff4172a1a2901bc7221957de09 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 5 Jun 2018 14:49:41 -0700 Subject: [PATCH 09/63] =?UTF-8?q?=F0=9F=91=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ImageSharp/Primitives/DenseMatrix{T}.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Primitives/DenseMatrix{T}.cs b/src/ImageSharp/Primitives/DenseMatrix{T}.cs index 828aeadfa..c890a4129 100644 --- a/src/ImageSharp/Primitives/DenseMatrix{T}.cs +++ b/src/ImageSharp/Primitives/DenseMatrix{T}.cs @@ -89,6 +89,11 @@ namespace SixLabors.ImageSharp.Primitives } } + /// + /// Gets a Span wrapping the Data. + /// + public Span Span => new Span(this.Data); + /// /// Gets or sets the item at the specified position. /// @@ -105,9 +110,6 @@ namespace SixLabors.ImageSharp.Primitives } } - - public Span Span => new Span(Data); - /// /// Performs an implicit conversion from a to a . /// From 5ad7ae5089551f60df6fcdc78b5fdf2686b1c01b Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 8 Jun 2018 11:50:16 -0700 Subject: [PATCH 10/63] Stackalloc bmp header --- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 2b0c90733..e5bf6d9cb 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -66,16 +66,25 @@ namespace SixLabors.ImageSharp.Formats.Bmp reserved: 0, fileSize: 54 + infoHeader.ImageSize); - byte[] buffer = new byte[40]; // TODO: stackalloc - +#if NETCOREAPP2_1 + Span buffer = stackalloc byte[40]; +#else + byte[] buffer = new byte[40]; +#endif fileHeader.WriteTo(buffer); +#if NETCOREAPP2_1 + stream.Write(buffer.Slice(0, BmpFileHeader.Size)); +#else stream.Write(buffer, 0, BmpFileHeader.Size); - +#endif infoHeader.WriteTo(buffer); +#if NETCOREAPP2_1 + stream.Write(buffer.Slice(0, 40)); +#else stream.Write(buffer, 0, 40); - +#endif this.WriteImage(stream, image.Frames.RootFrame); stream.Flush(); From 0a16995fe2f90574965d5a09e877095e7f00be1c Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 8 Jun 2018 11:50:31 -0700 Subject: [PATCH 11/63] Stackalloc LzwDecoder buffer --- src/ImageSharp/Formats/Gif/LzwDecoder.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/ImageSharp/Formats/Gif/LzwDecoder.cs b/src/ImageSharp/Formats/Gif/LzwDecoder.cs index 9f9e070e2..446ebde9a 100644 --- a/src/ImageSharp/Formats/Gif/LzwDecoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwDecoder.cs @@ -112,7 +112,12 @@ namespace SixLabors.ImageSharp.Formats.Gif Unsafe.Add(ref suffixRef, code) = (byte)code; } +#if NETCOREAPP2_1 + Span buffer = stackalloc byte[255]; +#else byte[] buffer = new byte[255]; +#endif + while (xyz < length) { if (top == 0) @@ -221,15 +226,24 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] +#if NETCOREAPP2_1 + private int ReadBlock(Span buffer) +#else private int ReadBlock(byte[] buffer) +#endif { int bufferSize = this.stream.ReadByte(); + if (bufferSize < 1) { return 0; } +#if NETCOREAPP2_1 + int count = this.stream.Read(buffer.Slice(0, bufferSize)); +#else int count = this.stream.Read(buffer, 0, bufferSize); +#endif return count != bufferSize ? 0 : bufferSize; } From 4f80c17297c282ccbc555422c8c10cdb0d3e474a Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 11 Jun 2018 12:00:25 -0700 Subject: [PATCH 12/63] Add stream extensions for Span --- .../Common/Extensions/StreamExtensions.cs | 29 ++++++++++++++++++- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 10 ++----- src/ImageSharp/Formats/Gif/LzwDecoder.cs | 5 +--- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/StreamExtensions.cs b/src/ImageSharp/Common/Extensions/StreamExtensions.cs index 7a9a34ac1..d11ba8ca5 100644 --- a/src/ImageSharp/Common/Extensions/StreamExtensions.cs +++ b/src/ImageSharp/Common/Extensions/StreamExtensions.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Buffers; +using System; using System.IO; namespace SixLabors.ImageSharp @@ -11,6 +11,33 @@ namespace SixLabors.ImageSharp /// internal static class StreamExtensions { +#if NETCOREAPP2_1 + /// + /// Writes data from a stream into the provided buffer. + /// + /// The stream. + /// The buffer. + /// The offset within the buffer to begin writing. + /// The number of bytes to write to the stream. + public static void Write(this Stream stream, Span buffer, int offset, int count) + { + stream.Write(buffer.Slice(offset, count)); + } + + /// + /// Reads data from a stream into the provided buffer. + /// + /// The stream. + /// The buffer.. + /// The offset within the buffer where the bytes are read into. + /// The number of bytes, if available, to read. + /// The actual number of bytes read. + public static int Read(this Stream stream, Span buffer, int offset, int count) + { + return stream.Read(buffer.Slice(offset, count)); + } +#endif + /// /// Skips the number of bytes in the given stream. /// diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index e5bf6d9cb..ed71119d7 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -73,18 +73,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp #endif fileHeader.WriteTo(buffer); -#if NETCOREAPP2_1 - stream.Write(buffer.Slice(0, BmpFileHeader.Size)); -#else stream.Write(buffer, 0, BmpFileHeader.Size); -#endif + infoHeader.WriteTo(buffer); -#if NETCOREAPP2_1 - stream.Write(buffer.Slice(0, 40)); -#else stream.Write(buffer, 0, 40); -#endif + this.WriteImage(stream, image.Frames.RootFrame); stream.Flush(); diff --git a/src/ImageSharp/Formats/Gif/LzwDecoder.cs b/src/ImageSharp/Formats/Gif/LzwDecoder.cs index 446ebde9a..6953e8fcd 100644 --- a/src/ImageSharp/Formats/Gif/LzwDecoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwDecoder.cs @@ -239,11 +239,8 @@ namespace SixLabors.ImageSharp.Formats.Gif return 0; } -#if NETCOREAPP2_1 - int count = this.stream.Read(buffer.Slice(0, bufferSize)); -#else int count = this.stream.Read(buffer, 0, bufferSize); -#endif + return count != bufferSize ? 0 : bufferSize; } From 32cd3f280945e714a85d3123e7d66dc0cdf039bb Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 11 Jun 2018 12:03:09 -0700 Subject: [PATCH 13/63] Eliminate subsample allocation in JpegEncoder --- src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 37279d526..aa624838c 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.IO; using System.Runtime.CompilerServices; @@ -736,16 +737,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private void WriteStartOfFrame(int width, int height, int componentCount) { // "default" to 4:2:0 - byte[] subsamples = { 0x22, 0x11, 0x11 }; + Span subsamples = stackalloc byte[] { 0x22, 0x11, 0x11 }; byte[] chroma = { 0x00, 0x01, 0x01 }; switch (this.subsample) { case JpegSubsample.Ratio444: - subsamples = new byte[] { 0x11, 0x11, 0x11 }; + subsamples = stackalloc byte[] { 0x11, 0x11, 0x11 }; break; case JpegSubsample.Ratio420: - subsamples = new byte[] { 0x22, 0x11, 0x11 }; + subsamples = stackalloc byte[] { 0x22, 0x11, 0x11 }; break; } From 5eaa411166553603928e544b0868ffa83e49f272 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 11 Jun 2018 12:03:29 -0700 Subject: [PATCH 14/63] Eliminate cmd allocation in BmpDecoder --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 26bd97b81..d10b05ce7 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -245,7 +245,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// Buffer for uncompressed data. private void UncompressRle8(int w, Span buffer) { +#if NETCOREAPP2_1 + Span cmd = stackalloc byte[2]; +#else byte[] cmd = new byte[2]; +#endif int count = 0; while (count < buffer.Length) From 337aa3e8c5bf9974fc35e30df04af86ed7930dcc Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 11 Jun 2018 12:12:24 -0700 Subject: [PATCH 15/63] Eliminate allocation reading BMP header --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 13 ++++++++----- src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs | 5 +++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index d10b05ce7..85461c0d2 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers.Binary; using System.IO; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory; @@ -473,12 +474,14 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// private void ReadInfoHeader() { +#if NETCOREAPP2_1 + Span buffer = stackalloc byte[BmpInfoHeader.MaxHeaderSize]; +#else byte[] buffer = new byte[BmpInfoHeader.MaxHeaderSize]; +#endif + this.stream.Read(buffer, 0, BmpInfoHeader.HeaderSizeSize); // read the header size - // read header size - this.stream.Read(buffer, 0, BmpInfoHeader.HeaderSizeSize); - - int headerSize = BitConverter.ToInt32(buffer, 0); + int headerSize = BinaryPrimitives.ReadInt32LittleEndian(buffer); if (headerSize < BmpInfoHeader.CoreSize) { throw new NotSupportedException($"ImageSharp does not support this BMP file. HeaderSize: {headerSize}."); @@ -502,7 +505,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp else if (headerSize >= BmpInfoHeader.Size) { // >= 40 bytes - this.infoHeader = BmpInfoHeader.Parse(buffer.AsSpan(0, 40)); + this.infoHeader = BmpInfoHeader.Parse(buffer); } else { diff --git a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs index a088a9b13..872c24286 100644 --- a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs +++ b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs @@ -132,6 +132,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// public static BmpInfoHeader Parse(ReadOnlySpan data) { + if (data.Length != Size) + { + throw new ArgumentException(nameof(data), $"Must be 40 bytes. Was {data.Length} bytes."); + } + return MemoryMarshal.Cast(data)[0]; } From 2a4ea4aa923eaf47c996dbd14f29cf86a933e566 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 11 Jun 2018 12:18:42 -0700 Subject: [PATCH 16/63] Eliminate allocation processing the identifier in ProcessApp2Marker --- .../Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs index 752e72dd2..cd893900e 100644 --- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs @@ -482,16 +482,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort private void ProcessApp2Marker(int remaining) { // Length is 14 though we only need to check 12. - const int Icclength = 14; - if (remaining < Icclength || this.IgnoreMetadata) + const int IccLength = 14; + if (remaining < IccLength || this.IgnoreMetadata) { this.InputStream.Skip(remaining); return; } - byte[] identifier = new byte[Icclength]; - this.InputStream.Read(identifier, 0, Icclength); - remaining -= Icclength; // We have read it by this point +#if NETCOREAPP2_1 + byte[] identifier = new byte[IccLength]; // 14 bytes +#else + Span identifer = stackalloc byte[IccLength]; +#endif + this.InputStream.Read(identifier, 0, IccLength); + remaining -= IccLength; // We have read it by this point if (ProfileResolver.IsProfile(identifier, ProfileResolver.IccMarker)) { From 0115a0ab30e3e264c766097322d90336aa382794 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 11 Jun 2018 12:31:50 -0700 Subject: [PATCH 17/63] Eliminate allocation reading BMP file header --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 85461c0d2..7528f36bf 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -521,8 +521,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// private void ReadFileHeader() { +#if NETCOREAPP2_1 + Span buffer = stackalloc byte[BmpFileHeader.Size]; +#else byte[] buffer = new byte[BmpFileHeader.Size]; - +#endif this.stream.Read(buffer, 0, BmpFileHeader.Size); this.fileHeader = BmpFileHeader.Parse(buffer); From 069653d61e218450ae285ec21e0e1e5d4c33b526 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 11 Jun 2018 12:39:45 -0700 Subject: [PATCH 18/63] Revert "Eliminate allocation processing the identifier in ProcessApp2Marker" This reverts commit e4bddc786f044eb60aacff5fb88bd292ade677e4. --- .../Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs index cd893900e..752e72dd2 100644 --- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs @@ -482,20 +482,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort private void ProcessApp2Marker(int remaining) { // Length is 14 though we only need to check 12. - const int IccLength = 14; - if (remaining < IccLength || this.IgnoreMetadata) + const int Icclength = 14; + if (remaining < Icclength || this.IgnoreMetadata) { this.InputStream.Skip(remaining); return; } -#if NETCOREAPP2_1 - byte[] identifier = new byte[IccLength]; // 14 bytes -#else - Span identifer = stackalloc byte[IccLength]; -#endif - this.InputStream.Read(identifier, 0, IccLength); - remaining -= IccLength; // We have read it by this point + byte[] identifier = new byte[Icclength]; + this.InputStream.Read(identifier, 0, Icclength); + remaining -= Icclength; // We have read it by this point if (ProfileResolver.IsProfile(identifier, ProfileResolver.IccMarker)) { From b1ea9077de715dcdc4a65e0506bfa3110bd76ba8 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 11 Jun 2018 15:40:04 -0700 Subject: [PATCH 19/63] Make new Span field on DenseMatrix internal This may need to be a method. --- src/ImageSharp/Primitives/DenseMatrix{T}.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Primitives/DenseMatrix{T}.cs b/src/ImageSharp/Primitives/DenseMatrix{T}.cs index c890a4129..ef1abc897 100644 --- a/src/ImageSharp/Primitives/DenseMatrix{T}.cs +++ b/src/ImageSharp/Primitives/DenseMatrix{T}.cs @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.Primitives /// /// Gets a Span wrapping the Data. /// - public Span Span => new Span(this.Data); + internal Span Span => new Span(this.Data); /// /// Gets or sets the item at the specified position. From 154391f97328aac114578a1c07f418ae9a970d3f Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 11 Jun 2018 15:40:41 -0700 Subject: [PATCH 20/63] Enable netcoreapp2.1 tests on AppVeyor --- appveyor.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index d98fa9c6a..83ab8e4c7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,13 +6,11 @@ skip_branch_with_pr: true environment: matrix: - ### TODO: Enable the netcoreapp2.1 target when RC2 has been released! - - #- target_framework: netcoreapp2.1 - # is_32bit: False + - target_framework: netcoreapp2.1 + is_32bit: False - #- target_framework: netcoreapp2.1 - # is_32bit: True + - target_framework: netcoreapp2.1 + is_32bit: True - target_framework: netcoreapp2.0 is_32bit: False From 9cc4fd683d4bf11193ec02a1af89b77111e38c0f Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Tue, 12 Jun 2018 22:26:45 +0100 Subject: [PATCH 21/63] add optermised drawing path with cached glyph rendering --- .../Drawing/Processors/FillRegionProcessor.cs | 19 +- .../Text/DrawTextExtensions.Path.cs | 30 +- .../Processing/Text/DrawTextExtensions.cs | 32 +- .../Processors/DrawTextOnPathProcessor.cs | 140 ++++++ .../Text/Processors/DrawTextProcessor.cs | 458 ++++++++++++++++++ .../Processing/Text/TextGraphicsOptions.cs | 19 + .../ImageSharp.Benchmarks/Drawing/DrawText.cs | 101 ++++ .../OldProcessors/DrawTextProcessorV1.cs | 138 ++++++ .../Drawing/Text/DrawText.Path.cs | 61 +-- .../ImageSharp.Tests/Drawing/Text/DrawText.cs | 101 ++-- .../Drawing/Text/DrawTextOnImageTests.cs | 22 +- .../ImageSharp.Tests/ImageSharp.Tests.csproj | 6 + 12 files changed, 933 insertions(+), 194 deletions(-) create mode 100644 src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextOnPathProcessor.cs create mode 100644 src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs create mode 100644 tests/ImageSharp.Benchmarks/Drawing/DrawText.cs create mode 100644 tests/ImageSharp.Benchmarks/Drawing/OldProcessors/DrawTextProcessorV1.cs diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs index 95ac3fe29..6eb6a15d0 100644 --- a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs @@ -37,22 +37,29 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors } /// - /// Gets the brush. + /// Initializes a new instance of the class. + /// + public FillRegionProcessor() + { + } + + /// + /// Gets or sets the brush. /// - public IBrush Brush { get; } + public IBrush Brush { get; set; } /// - /// Gets the region that this processor applies to. + /// Gets or sets the region that this processor applies to. /// - public Region Region { get; } + public Region Region { get; set; } /// - /// Gets the options. + /// Gets or sets the options. /// /// /// The options. /// - public GraphicsOptions Options { get; } + public GraphicsOptions Options { get; set; } /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) diff --git a/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.Path.cs b/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.Path.cs index 9de73afcc..e0c133d50 100644 --- a/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.Path.cs +++ b/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.Path.cs @@ -6,6 +6,7 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Drawing; using SixLabors.ImageSharp.Processing.Drawing.Brushes; using SixLabors.ImageSharp.Processing.Drawing.Pens; +using SixLabors.ImageSharp.Processing.Text.Processors; using SixLabors.Shapes; namespace SixLabors.ImageSharp.Processing.Text @@ -147,33 +148,6 @@ namespace SixLabors.ImageSharp.Processing.Text /// public static IImageProcessingContext DrawText(this IImageProcessingContext source, TextGraphicsOptions options, string text, Font font, IBrush brush, IPen pen, IPath path) where TPixel : struct, IPixel - { - float dpiX = DefaultTextDpi; - float dpiY = DefaultTextDpi; - - var style = new RendererOptions(font, dpiX, dpiY) - { - ApplyKerning = options.ApplyKerning, - TabWidth = options.TabWidth, - WrappingWidth = options.WrapTextWidth, - HorizontalAlignment = options.HorizontalAlignment, - VerticalAlignment = options.VerticalAlignment - }; - - IPathCollection glyphs = TextBuilder.GenerateGlyphs(text, path, style); - - var pathOptions = (GraphicsOptions)options; - if (brush != null) - { - source.Fill(pathOptions, brush, glyphs); - } - - if (pen != null) - { - source.Draw(pathOptions, pen, glyphs); - } - - return source; - } + => source.ApplyProcessor(new DrawTextOnPathProcessor(options, text, font, brush, pen, path)); } } \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.cs b/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.cs index 8fede9693..ed7a7bbfa 100644 --- a/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.cs @@ -6,6 +6,7 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Drawing; using SixLabors.ImageSharp.Processing.Drawing.Brushes; using SixLabors.ImageSharp.Processing.Drawing.Pens; +using SixLabors.ImageSharp.Processing.Text.Processors; using SixLabors.Primitives; using SixLabors.Shapes; @@ -16,8 +17,6 @@ namespace SixLabors.ImageSharp.Processing.Text /// public static partial class DrawTextExtensions { - private static readonly int DefaultTextDpi = 72; - /// /// Draws the text onto the the image filled via the brush. /// @@ -150,33 +149,6 @@ namespace SixLabors.ImageSharp.Processing.Text /// public static IImageProcessingContext DrawText(this IImageProcessingContext source, TextGraphicsOptions options, string text, Font font, IBrush brush, IPen pen, PointF location) where TPixel : struct, IPixel - { - float dpiX = DefaultTextDpi; - float dpiY = DefaultTextDpi; - - var style = new RendererOptions(font, dpiX, dpiY, location) - { - ApplyKerning = options.ApplyKerning, - TabWidth = options.TabWidth, - WrappingWidth = options.WrapTextWidth, - HorizontalAlignment = options.HorizontalAlignment, - VerticalAlignment = options.VerticalAlignment - }; - - IPathCollection glyphs = TextBuilder.GenerateGlyphs(text, style); - - var pathOptions = (GraphicsOptions)options; - if (brush != null) - { - source.Fill(pathOptions, brush, glyphs); - } - - if (pen != null) - { - source.Draw(pathOptions, pen, glyphs); - } - - return source; - } + => source.ApplyProcessor(new DrawTextProcessor(options, text, font, brush, pen, location)); } } \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextOnPathProcessor.cs b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextOnPathProcessor.cs new file mode 100644 index 000000000..c8a51865c --- /dev/null +++ b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextOnPathProcessor.cs @@ -0,0 +1,140 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Threading.Tasks; +using SixLabors.Fonts; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Primitives; +using SixLabors.ImageSharp.Processing.Drawing.Brushes; +using SixLabors.ImageSharp.Processing.Drawing.Pens; +using SixLabors.ImageSharp.Processing.Drawing.Processors; +using SixLabors.ImageSharp.Processing.Processors; +using SixLabors.Primitives; +using SixLabors.Shapes; + +namespace SixLabors.ImageSharp.Processing.Text.Processors +{ + /// + /// Using the brush as a source of pixels colors blends the brush color with source. + /// + /// The pixel format. + internal class DrawTextOnPathProcessor : ImageProcessor + where TPixel : struct, IPixel + { + private FillRegionProcessor fillRegionProcessor = null; + + /// + /// Initializes a new instance of the class. + /// + /// The options + /// The text we want to render + /// The font we want to render with + /// The brush to source pixel colors from. + /// The pen to outline text with. + /// The path on which to draw the text along. + public DrawTextOnPathProcessor(TextGraphicsOptions options, string text, Font font, IBrush brush, IPen pen, IPath path) + { + this.Brush = brush; + this.Options = options; + this.Text = text; + this.Pen = pen; + this.Font = font; + this.Path = path; + } + + /// + /// Gets or sets the brush. + /// + public IBrush Brush { get; set; } + + /// + /// Gets or sets the options + /// + private TextGraphicsOptions Options { get; set; } + + /// + /// Gets or sets the text + /// + private string Text { get; set; } + + /// + /// Gets or sets the pen used for outlining the text, if Null then we will not outline + /// + public IPen Pen { get; set; } + + /// + /// Gets or sets the font used to render the text. + /// + public Font Font { get; set; } + + /// + /// Gets or sets the path to draw the text along. + /// + public IPath Path { get; set; } + + protected override void BeforeImageApply(Image source, Rectangle sourceRectangle) + { + base.BeforeImageApply(source, sourceRectangle); + + // do everythign at the image level as we are deligating the processing down to other processors + var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY) + { + ApplyKerning = this.Options.ApplyKerning, + TabWidth = this.Options.TabWidth, + WrappingWidth = this.Options.WrapTextWidth, + HorizontalAlignment = this.Options.HorizontalAlignment, + VerticalAlignment = this.Options.VerticalAlignment + }; + + IPathCollection glyphs = TextBuilder.GenerateGlyphs(this.Text, this.Path, style); + + var pathOptions = (GraphicsOptions)this.Options; + if (this.Brush != null) + { + // we will reuse the processor for all fill operations to reduce allocations + if (this.fillRegionProcessor == null) + { + this.fillRegionProcessor = new FillRegionProcessor() + { + Brush = this.Brush, + Options = pathOptions + }; + } + + foreach (IPath p in glyphs) + { + this.fillRegionProcessor.Region = new ShapeRegion(p); + this.fillRegionProcessor.Apply(source, sourceRectangle); + } + } + + if (this.Pen != null) + { + // we will reuse the processor for all fill operations to reduce allocations + if (this.fillRegionProcessor == null) + { + this.fillRegionProcessor = new FillRegionProcessor() + { + Brush = this.Brush, + Options = pathOptions + }; + } + + foreach (IPath p in glyphs) + { + this.fillRegionProcessor.Region = new ShapePath(p, this.Pen); + this.fillRegionProcessor.Apply(source, sourceRectangle); + } + } + } + + /// + protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + { + // this is a no-op as we have processes all as an image, we should be able to pass out of before email apply a skip frames outcome + } + } +} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs new file mode 100644 index 000000000..b029ff516 --- /dev/null +++ b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs @@ -0,0 +1,458 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using SixLabors.Fonts; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Primitives; +using SixLabors.ImageSharp.Processing.Drawing.Brushes; +using SixLabors.ImageSharp.Processing.Drawing.Pens; +using SixLabors.ImageSharp.Processing.Drawing.Processors; +using SixLabors.ImageSharp.Processing.Processors; +using SixLabors.Primitives; +using SixLabors.Shapes; + +namespace SixLabors.ImageSharp.Processing.Text.Processors +{ + /// + /// Using the brush as a source of pixels colors blends the brush color with source. + /// + /// The pixel format. + internal class DrawTextProcessor : ImageProcessor + where TPixel : struct, IPixel + { + private FillRegionProcessor fillRegionProcessor = null; + + private CachingGlyphRenderer textRenderer; + + /// + /// Initializes a new instance of the class. + /// + /// The options + /// The text we want to render + /// The font we want to render with + /// The brush to source pixel colors from. + /// The pen to outline text with. + /// The location on the image to start drawign the text from. + public DrawTextProcessor(TextGraphicsOptions options, string text, Font font, IBrush brush, IPen pen, PointF location) + { + this.Brush = brush; + this.Options = options; + this.Text = text; + this.Pen = pen; + this.Font = font; + this.Location = location; + } + + /// + /// Gets or sets the brush. + /// + public IBrush Brush { get; set; } + + /// + /// Gets or sets the options + /// + public TextGraphicsOptions Options { get; set; } + + /// + /// Gets or sets the text + /// + public string Text { get; set; } + + /// + /// Gets or sets the pen used for outlining the text, if Null then we will not outline + /// + public IPen Pen { get; set; } + + /// + /// Gets or sets the font used to render the text. + /// + public Font Font { get; set; } + + /// + /// Gets or sets the location to draw the text at. + /// + public PointF Location { get; set; } + + protected override void BeforeImageApply(Image source, Rectangle sourceRectangle) + { + base.BeforeImageApply(source, sourceRectangle); + + // user slow path if pen is set and fast render for brush only rendering + + // do everythign at the image level as we are deligating the processing down to other processors + var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY, this.Location) + { + ApplyKerning = this.Options.ApplyKerning, + TabWidth = this.Options.TabWidth, + WrappingWidth = this.Options.WrapTextWidth, + HorizontalAlignment = this.Options.HorizontalAlignment, + VerticalAlignment = this.Options.VerticalAlignment + }; + + if (this.Pen != null) + { + IPathCollection glyphs = TextBuilder.GenerateGlyphs(this.Text, style); + + var pathOptions = (GraphicsOptions)this.Options; + if (this.Brush != null) + { + // we will reuse the processor for all fill operations to reduce allocations + if (this.fillRegionProcessor == null) + { + this.fillRegionProcessor = new FillRegionProcessor() + { + Brush = this.Brush, + Options = pathOptions + }; + } + + foreach (IPath p in glyphs) + { + this.fillRegionProcessor.Region = new ShapeRegion(p); + this.fillRegionProcessor.Apply(source, sourceRectangle); + } + } + + // we will reuse the processor for all fill operations to reduce allocations + if (this.fillRegionProcessor == null) + { + this.fillRegionProcessor = new FillRegionProcessor() + { + Brush = this.Brush, + Options = pathOptions + }; + } + + foreach (IPath p in glyphs) + { + this.fillRegionProcessor.Region = new ShapePath(p, this.Pen); + this.fillRegionProcessor.Apply(source, sourceRectangle); + } + } + else + { + this.textRenderer = new CachingGlyphRenderer(source.GetMemoryManager()); + this.textRenderer.Options = (GraphicsOptions)this.Options; + TextRenderer.RenderTextTo(this.textRenderer, this.Text, style); + } + } + + protected override void AfterImageApply(Image source, Rectangle sourceRectangle) + { + base.AfterImageApply(source, sourceRectangle); + this.textRenderer?.Dispose(); + this.textRenderer = null; + } + + /// + protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + { + // this is a no-op as we have processes all as an image, we should be able to pass out of before email apply a skip frames outcome + if (this.Pen == null && this.Brush != null && this.textRenderer != null && this.textRenderer.Operations.Count > 0) + { + // we have rendered at the image level now we can draw + List operations = this.textRenderer.Operations; + + using (BrushApplicator app = this.Brush.CreateApplicator(source, sourceRectangle, this.textRenderer.Options)) + { + foreach (DrawingOperation operation in operations) + { + IBuffer2D buffer = operation.Map; + int startY = operation.Location.Y; + int startX = operation.Location.X; + int end = operation.Map.Height; + for (int row = 0; row < end; row++) + { + int y = startY + row; + app.Apply(buffer.GetRowSpan(row), startX, y); + } + } + } + } + } + + private struct DrawingOperation + { + public IBuffer2D Map { get; set; } + + public Point Location { get; set; } + } + + private class CachingGlyphRenderer : IGlyphRenderer, IDisposable + { + private PathBuilder builder; + + private Point currentRenderPosition = default(Point); + private int currentRenderingGlyph = 0; + + private PointF currentPoint = default(PointF); + private Dictionary> glyphMap = new Dictionary>(); + + public CachingGlyphRenderer(MemoryManager memoryManager) + { + this.MemoryManager = memoryManager; + this.builder = new PathBuilder(); + } + + public List Operations { get; } = new List(); + + public MemoryManager MemoryManager { get; internal set; } + + public GraphicsOptions Options { get; internal set; } + + public void BeginFigure() + { + this.builder.StartFigure(); + } + + public bool BeginGlyph(RectangleF bounds, int cacheKey) + { + this.currentRenderPosition = Point.Truncate(bounds.Location); + this.currentRenderingGlyph = cacheKey; + + if (this.glyphMap.ContainsKey(this.currentRenderingGlyph)) + { + // we have already drawn the glyph vectors skip trying again + return false; + } + + // we check to see if we have a render cache and if we do then we render else + this.builder.Clear(); + + // ensure all glyphs render around [zero, zero] so offset negative root positions so when we draw the glyph we can offet it back + this.builder.SetOrigin(new PointF(-(int)bounds.X, -(int)bounds.Y)); + + return true; + } + + public void BeginText(RectangleF bounds) + { + // not concerned about this one + this.Operations.Clear(); + } + + public void CubicBezierTo(PointF secondControlPoint, PointF thirdControlPoint, PointF point) + { + this.builder.AddBezier(this.currentPoint, secondControlPoint, thirdControlPoint, point); + this.currentPoint = point; + } + + public void Dispose() + { + foreach (KeyValuePair> m in this.glyphMap) + { + m.Value.Dispose(); + } + } + + public void EndFigure() + { + this.builder.CloseFigure(); + } + + public void EndGlyph() + { + if (!this.glyphMap.ContainsKey(this.currentRenderingGlyph)) + { + this.RenderToCache(); + } + + this.Operations.Add(new DrawingOperation + { + Location = this.currentRenderPosition, + Map = this.glyphMap[this.currentRenderingGlyph] + }); + } + + private void RenderToCache() + { + IPath path = this.builder.Build(); + + var size = Rectangle.Ceiling(path.Bounds); + float subpixelCount = 4; + float offset = 0.5f; + if (this.Options.Antialias) + { + offset = 0f; // we are antialising skip offsetting as real antalising should take care of offset. + subpixelCount = this.Options.AntialiasSubpixelDepth; + if (subpixelCount < 4) + { + subpixelCount = 4; + } + } + + // take the path inside the path builder, scan thing and generate a Buffer2d representing the glyph and cache it. + Buffer2D fullBuffer = this.MemoryManager.Allocate2D(size.Width + 1, size.Height + 1, true); + this.glyphMap.Add(this.currentRenderingGlyph, fullBuffer); + using (IBuffer bufferBacking = this.MemoryManager.Allocate(path.MaxIntersections)) + using (IBuffer rowIntersectionBuffer = this.MemoryManager.Allocate(size.Width)) + { + float subpixelFraction = 1f / subpixelCount; + float subpixelFractionPoint = subpixelFraction / subpixelCount; + + for (int y = 0; y <= size.Height; y++) + { + Span scanline = fullBuffer.GetRowSpan(y); + bool scanlineDirty = false; + float yPlusOne = y + 1; + + for (float subPixel = (float)y; subPixel < yPlusOne; subPixel += subpixelFraction) + { + var start = new PointF(path.Bounds.Left - 1, subPixel); + var end = new PointF(path.Bounds.Right + 1, subPixel); + Span intersectionSpan = rowIntersectionBuffer.Span; + Span buffer = bufferBacking.Span; + int pointsFound = path.FindIntersections(start, end, intersectionSpan); + + if (pointsFound == 0) + { + // nothing on this line skip + continue; + } + + for (int i = 0; i < pointsFound && i < intersectionSpan.Length; i++) + { + buffer[i] = intersectionSpan[i].X; + } + + QuickSort(buffer.Slice(0, pointsFound)); + + for (int point = 0; point < pointsFound; point += 2) + { + // points will be paired up + float scanStart = buffer[point]; + float scanEnd = buffer[point + 1]; + int startX = (int)MathF.Floor(scanStart + offset); + int endX = (int)MathF.Floor(scanEnd + offset); + + if (startX >= 0 && startX < scanline.Length) + { + for (float x = scanStart; x < startX + 1; x += subpixelFraction) + { + scanline[startX] += subpixelFractionPoint; + scanlineDirty = true; + } + } + + if (endX >= 0 && endX < scanline.Length) + { + for (float x = endX; x < scanEnd; x += subpixelFraction) + { + scanline[endX] += subpixelFractionPoint; + scanlineDirty = true; + } + } + + int nextX = startX + 1; + endX = Math.Min(endX, scanline.Length); // reduce to end to the right edge + nextX = Math.Max(nextX, 0); + for (int x = nextX; x < endX; x++) + { + scanline[x] += subpixelFraction; + scanlineDirty = true; + } + } + } + + if (scanlineDirty) + { + if (!this.Options.Antialias) + { + for (int x = 0; x < size.Width; x++) + { + if (scanline[x] >= 0.5) + { + scanline[x] = 1; + } + else + { + scanline[x] = 0; + } + } + } + } + } + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Swap(Span data, int left, int right) + { + float tmp = data[left]; + data[left] = data[right]; + data[right] = tmp; + } + + private static void QuickSort(Span data) + { + QuickSort(data, 0, data.Length - 1); + } + + private static void QuickSort(Span data, int lo, int hi) + { + if (lo < hi) + { + int p = Partition(data, lo, hi); + QuickSort(data, lo, p); + QuickSort(data, p + 1, hi); + } + } + + private static int Partition(Span data, int lo, int hi) + { + float pivot = data[lo]; + int i = lo - 1; + int j = hi + 1; + while (true) + { + do + { + i = i + 1; + } + while (data[i] < pivot && i < hi); + + do + { + j = j - 1; + } + while (data[j] > pivot && j > lo); + + if (i >= j) + { + return j; + } + + Swap(data, i, j); + } + } + + public void EndText() + { + } + + public void LineTo(PointF point) + { + this.builder.AddLine(this.currentPoint, point); + this.currentPoint = point; + } + + public void MoveTo(PointF point) + { + this.builder.StartFigure(); + this.currentPoint = point; + } + + public void QuadraticBezierTo(PointF secondControlPoint, PointF point) + { + this.builder.AddBezier(this.currentPoint, secondControlPoint, point); + this.currentPoint = point; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processing/Text/TextGraphicsOptions.cs b/src/ImageSharp.Drawing/Processing/Text/TextGraphicsOptions.cs index bba473ddb..aaa6dea56 100644 --- a/src/ImageSharp.Drawing/Processing/Text/TextGraphicsOptions.cs +++ b/src/ImageSharp.Drawing/Processing/Text/TextGraphicsOptions.cs @@ -11,6 +11,8 @@ namespace SixLabors.ImageSharp.Processing.Text /// public struct TextGraphicsOptions { + private const int DefaultTextDpi = 72; + /// /// Represents the default . /// @@ -26,11 +28,16 @@ namespace SixLabors.ImageSharp.Processing.Text private float? tabWidth; + private float? dpiX; + + private float? dpiY; + private PixelBlenderMode blenderMode; private float wrapTextWidth; private HorizontalAlignment? horizontalAlignment; + private VerticalAlignment? verticalAlignment; /// @@ -49,6 +56,8 @@ namespace SixLabors.ImageSharp.Processing.Text this.blenderMode = PixelBlenderMode.Normal; this.blendPercentage = 1; this.antialias = enableAntialiasing; + this.dpiX = DefaultTextDpi; + this.dpiY = DefaultTextDpi; } /// @@ -90,6 +99,16 @@ namespace SixLabors.ImageSharp.Processing.Text /// public float WrapTextWidth { get => this.wrapTextWidth; set => this.wrapTextWidth = value; } + /// + /// Gets or sets a value indicating the DPI to render text along the X axis. + /// + public float DpiX { get => this.dpiX ?? DefaultTextDpi; set => this.dpiX = value; } + + /// + /// Gets or sets a value indicating the DPI to render text along the Y axis. + /// + public float DpiY { get => this.dpiY ?? DefaultTextDpi; set => this.dpiY = value; } + /// /// Gets or sets a value indicating how to align the text relative to the rendering space. /// If is greater than zero it will align relative to the space diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawText.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawText.cs new file mode 100644 index 000000000..96912a6df --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawText.cs @@ -0,0 +1,101 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +using System.Drawing; +using System.Drawing.Drawing2D; +using BenchmarkDotNet.Attributes; +using System.IO; +using System.Numerics; + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Text; +using SixLabors.ImageSharp.Processing.Overlays; +using SixLabors.ImageSharp.Processing.Drawing; +using System.Linq; + +namespace SixLabors.ImageSharp.Benchmarks +{ + + [MemoryDiagnoser] + public class DrawText : BenchmarkBase + { + + [Params(10, 100)] + public int TextIterations{ get; set; } + public string TextPhrase { get; set; } = "Hello World"; + public string TextToRender => string.Join(" ", Enumerable.Repeat(TextPhrase, TextIterations)); + + + [Benchmark(Baseline = true, Description = "System.Drawing Draw Text")] + public void DrawTextSystemDrawing() + { + using (Bitmap destination = new Bitmap(800, 800)) + { + + using (Graphics graphics = Graphics.FromImage(destination)) + { + graphics.InterpolationMode = InterpolationMode.Default; + graphics.SmoothingMode = SmoothingMode.AntiAlias; + Pen pen = new Pen(System.Drawing.Color.HotPink, 10); + var font = new Font("Arial", 12, GraphicsUnit.Point); + graphics.DrawString(TextToRender, font, Brushes.HotPink, new RectangleF(10, 10, 780, 780)); + } + } + } + + + [Benchmark(Description = "ImageSharp Draw Text - Cached Glyphs")] + public void DrawTextCore() + { + using (Image image = new Image(800, 800)) + { + var font = SixLabors.Fonts.SystemFonts.CreateFont("Arial", 12); + image.Mutate(x => x.ApplyProcessor(new SixLabors.ImageSharp.Processing.Text.Processors.DrawTextProcessor(new TextGraphicsOptions(true) { WrapTextWidth = 780 }, TextToRender, font, SixLabors.ImageSharp.Processing.Drawing.Brushes.Brushes.Solid(Rgba32.HotPink), null, new SixLabors.Primitives.PointF(10, 10)))); + } + } + + [Benchmark(Description = "ImageSharp Draw Text - Nieve")] + public void DrawTextCoreOld() + { + using (Image image = new Image(800, 800)) + { + var font = SixLabors.Fonts.SystemFonts.CreateFont("Arial", 12); + image.Mutate(x => DrawTextOldVersion(x, new TextGraphicsOptions(true) { WrapTextWidth = 780 }, TextToRender, font, SixLabors.ImageSharp.Processing.Drawing.Brushes.Brushes.Solid(Rgba32.HotPink), null, new SixLabors.Primitives.PointF(10, 10))); + } + + IImageProcessingContext DrawTextOldVersion(IImageProcessingContext source, TextGraphicsOptions options, string text, SixLabors.Fonts.Font font, SixLabors.ImageSharp.Processing.Drawing.Brushes.IBrush brush, SixLabors.ImageSharp.Processing.Drawing.Pens.IPen pen, SixLabors.Primitives.PointF location) + where TPixel : struct, IPixel + { + float dpiX = 72; + float dpiY = 72; + + var style = new SixLabors.Fonts.RendererOptions(font, dpiX, dpiY, location) + { + ApplyKerning = options.ApplyKerning, + TabWidth = options.TabWidth, + WrappingWidth = options.WrapTextWidth, + HorizontalAlignment = options.HorizontalAlignment, + VerticalAlignment = options.VerticalAlignment + }; + + Shapes.IPathCollection glyphs = Shapes.TextBuilder.GenerateGlyphs(text, style); + + var pathOptions = (GraphicsOptions)options; + if (brush != null) + { + source.Fill(pathOptions, brush, glyphs); + } + + if (pen != null) + { + source.Draw(pathOptions, pen, glyphs); + } + + return source; + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Drawing/OldProcessors/DrawTextProcessorV1.cs b/tests/ImageSharp.Benchmarks/Drawing/OldProcessors/DrawTextProcessorV1.cs new file mode 100644 index 000000000..3faaec2c2 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Drawing/OldProcessors/DrawTextProcessorV1.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.Text; +using SixLabors.Fonts; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Primitives; +using SixLabors.ImageSharp.Processing.Drawing.Brushes; +using SixLabors.ImageSharp.Processing.Drawing.Pens; +using SixLabors.ImageSharp.Processing.Drawing.Processors; +using SixLabors.ImageSharp.Processing.Processors; +using SixLabors.ImageSharp.Processing.Text; +using SixLabors.Primitives; +using SixLabors.Shapes; + +namespace SixLabors.ImageSharp.Benchmarks.Drawing.OldProcessors +{ + + /// + /// Using the brush as a source of pixels colors blends the brush color with source. + /// + /// The pixel format. + internal class DrawTextProcessor : ImageProcessor + where TPixel : struct, IPixel + { + private FillRegionProcessor fillRegionProcessor = null; + + /// + /// Initializes a new instance of the class. + /// + /// The options + /// The text we want to render + /// The font we want to render with + /// The brush to source pixel colors from. + /// The pen to outline text with. + /// The location on the image to start drawign the text from. + public DrawTextProcessor(TextGraphicsOptions options, string text, Font font, IBrush brush, IPen pen, PointF location) + { + this.Brush = brush; + this.Options = options; + this.Text = text; + this.Pen = pen; + this.Font = font; + this.Location = location; + } + + /// + /// Gets or sets the brush. + /// + public IBrush Brush { get; set; } + + /// + /// Gets or sets the options + /// + public TextGraphicsOptions Options { get; set; } + + /// + /// Gets or sets the text + /// + public string Text { get; set; } + + /// + /// Gets or sets the pen used for outlining the text, if Null then we will not outline + /// + public IPen Pen { get; set; } + + /// + /// Gets or sets the font used to render the text. + /// + public Font Font { get; set; } + + /// + /// Gets or sets the location to draw the text at. + /// + public PointF Location { get; set; } + + protected override void BeforeImageApply(Image source, Rectangle sourceRectangle) + { + base.BeforeImageApply(source, sourceRectangle); + + // do everythign at the image level as we are deligating the processing down to other processors + var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY, this.Location) + { + ApplyKerning = this.Options.ApplyKerning, + TabWidth = this.Options.TabWidth, + WrappingWidth = this.Options.WrapTextWidth, + HorizontalAlignment = this.Options.HorizontalAlignment, + VerticalAlignment = this.Options.VerticalAlignment + }; + + IPathCollection glyphs = TextBuilder.GenerateGlyphs(this.Text, style); + + var pathOptions = (GraphicsOptions)this.Options; + if (this.Brush != null) + { + // we will reuse the processor for all fill operations to reduce allocations + if (this.fillRegionProcessor == null) + { + this.fillRegionProcessor = new FillRegionProcessor() + { + Brush = this.Brush, + Options = pathOptions + }; + } + + foreach (IPath p in glyphs) + { + this.fillRegionProcessor.Region = new ShapeRegion(p); + this.fillRegionProcessor.Apply(source, sourceRectangle); + } + } + + if (this.Pen != null) + { + // we will reuse the processor for all fill operations to reduce allocations + if (this.fillRegionProcessor == null) + { + this.fillRegionProcessor = new FillRegionProcessor() + { + Brush = this.Brush, + Options = pathOptions + }; + } + + foreach (IPath p in glyphs) + { + this.fillRegionProcessor.Region = new ShapePath(p, this.Pen); + this.fillRegionProcessor.Apply(source, sourceRectangle); + } + } + } + + /// + protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + { + // this is a no-op as we have processes all as an image, we should be able to pass out of before email apply a skip frames outcome + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawText.Path.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawText.Path.cs index 4649bee6b..d352489b8 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawText.Path.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawText.Path.cs @@ -8,6 +8,7 @@ using SixLabors.ImageSharp.Processing.Drawing.Brushes; using SixLabors.ImageSharp.Processing.Drawing.Pens; using SixLabors.ImageSharp.Processing.Drawing.Processors; using SixLabors.ImageSharp.Processing.Text; +using SixLabors.ImageSharp.Processing.Text.Processors; using SixLabors.Shapes; using Xunit; @@ -44,9 +45,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text null, this.path); - this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + this.Verify>(0); } [Fact] @@ -54,9 +53,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { this.operations.DrawText("123", this.Font, Brushes.Solid(Rgba32.Red), null, this.path); - this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + this.Verify>(0); } [Fact] @@ -64,9 +61,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { this.operations.DrawText(new TextGraphicsOptions(true), "123", this.Font, Brushes.Solid(Rgba32.Red), this.path); - this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + this.Verify>(0); } [Fact] @@ -74,9 +69,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { this.operations.DrawText("123", this.Font, Brushes.Solid(Rgba32.Red), this.path); - this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + this.Verify>(0); } [Fact] @@ -84,9 +77,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { this.operations.DrawText(new TextGraphicsOptions(true), "123", this.Font, Rgba32.Red, this.path); - var processor = this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + var processor = this.Verify>(0); SolidBrush brush = Assert.IsType>(processor.Brush); Assert.Equal(Rgba32.Red, brush.Color); @@ -97,9 +88,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { this.operations.DrawText("123", this.Font, Rgba32.Red, this.path); - FillRegionProcessor processor = this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + DrawTextOnPathProcessor processor = this.Verify>(0); SolidBrush brush = Assert.IsType>(processor.Brush); Assert.Equal(Rgba32.Red, brush.Color); @@ -116,9 +105,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text Pens.Dash(Rgba32.Red, 1), this.path); - var processor = this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + var processor = this.Verify>(0); } [Fact] @@ -126,9 +113,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { this.operations.DrawText("123", this.Font, null, Pens.Dash(Rgba32.Red, 1), this.path); - var processor = this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + var processor = this.Verify>(0); } [Fact] @@ -136,9 +121,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { this.operations.DrawText(new TextGraphicsOptions(true), "123", this.Font, Pens.Dash(Rgba32.Red, 1), this.path); - var processor = this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + var processor = this.Verify>(0); } [Fact] @@ -146,9 +129,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { this.operations.DrawText("123", this.Font, Pens.Dash(Rgba32.Red, 1), this.path); - FillRegionProcessor processor = this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + DrawTextOnPathProcessor processor = this.Verify>(0); } [Fact] @@ -162,12 +143,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text Pens.Dash(Rgba32.Red, 1), this.path); - var processor = this.Verify>(0); - this.Verify>(1); - this.Verify>(2); - this.Verify>(3); - this.Verify>(4); - this.Verify>(5); + var processor = this.Verify>(0); } [Fact] @@ -175,12 +151,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { this.operations.DrawText("123", this.Font, Brushes.Solid(Rgba32.Red), Pens.Dash(Rgba32.Red, 1), this.path); - var processor = this.Verify>(0); - this.Verify>(1); - this.Verify>(2); - this.Verify>(3); - this.Verify>(4); - this.Verify>(5); + var processor = this.Verify>(0); } [Fact] @@ -194,8 +165,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text Pens.Dash(Rgba32.Red, 1), this.path); - var processor = this.Verify>(0); - this.Verify>(1); + var processor = this.Verify>(0); } [Fact] @@ -203,8 +173,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { this.operations.DrawText("1", this.Font, Brushes.Solid(Rgba32.Red), Pens.Dash(Rgba32.Red, 1), this.path); - var processor = this.Verify>(0); - this.Verify>(1); + var processor = this.Verify>(0); } } } diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs index 88b650a3e..2a03eb415 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs @@ -8,6 +8,8 @@ using SixLabors.ImageSharp.Processing.Drawing.Brushes; using SixLabors.ImageSharp.Processing.Drawing.Pens; using SixLabors.ImageSharp.Processing.Drawing.Processors; using SixLabors.ImageSharp.Processing.Text; +using SixLabors.ImageSharp.Processing.Text.Processors; +using SixLabors.Primitives; using SixLabors.Shapes; using Xunit; @@ -44,9 +46,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text null, Vector2.Zero); - this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + this.Verify>(0); } [Fact] @@ -54,9 +54,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { this.operations.DrawText("123", this.Font, Brushes.Solid(Rgba32.Red), null, Vector2.Zero); - this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + this.Verify>(0); } [Fact] @@ -64,9 +62,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { this.operations.DrawText(new TextGraphicsOptions(true), "123", this.Font, Brushes.Solid(Rgba32.Red), Vector2.Zero); - this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + this.Verify>(0); } [Fact] @@ -74,9 +70,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { this.operations.DrawText("123", this.Font, Brushes.Solid(Rgba32.Red), Vector2.Zero); - this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + this.Verify>(0); } [Fact] @@ -84,9 +78,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { this.operations.DrawText(new TextGraphicsOptions(true), "123", this.Font, Rgba32.Red, Vector2.Zero); - var processor = this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + var processor = this.Verify>(0); SolidBrush brush = Assert.IsType>(processor.Brush); Assert.Equal(Rgba32.Red, brush.Color); @@ -97,9 +89,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { this.operations.DrawText("123", this.Font, Rgba32.Red, Vector2.Zero); - var processor = this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + var processor = this.Verify>(0); SolidBrush brush = Assert.IsType>(processor.Brush); Assert.Equal(Rgba32.Red, brush.Color); @@ -116,9 +106,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text Pens.Dash(Rgba32.Red, 1), Vector2.Zero); - var processor = this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + var processor = this.Verify>(0); } [Fact] @@ -126,9 +114,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { this.operations.DrawText("123", this.Font, null, Pens.Dash(Rgba32.Red, 1), Vector2.Zero); - var processor = this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + var processor = this.Verify>(0); } [Fact] @@ -136,9 +122,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { this.operations.DrawText(new TextGraphicsOptions(true), "123", this.Font, Pens.Dash(Rgba32.Red, 1), Vector2.Zero); - var processor = this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + var processor = this.Verify>(0); } [Fact] @@ -146,9 +130,14 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { this.operations.DrawText("123", this.Font, Pens.Dash(Rgba32.Red, 1), Vector2.Zero); - var processor = this.Verify>(0); - this.Verify>(1); - this.Verify>(2); + var processor = this.Verify>(0); + + Assert.Equal("123", processor.Text); + Assert.Equal(this.Font, processor.Font); + var penBrush = Assert.IsType>(processor.Pen.StrokeFill); + Assert.Equal(Rgba32.Red, penBrush.Color); + Assert.Equal(1, processor.Pen.StrokeWidth); + Assert.Equal(PointF.Empty, processor.Location); } [Fact] @@ -162,50 +151,16 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text Pens.Dash(Rgba32.Red, 1), Vector2.Zero); - var processor = this.Verify>(0); - this.Verify>(1); - this.Verify>(2); - - this.Verify>(3); - this.Verify>(4); - this.Verify>(5); - } - - [Fact] - public void DrawForEachACharachterWhenPenSetAndFillFroEachWhenBrushSetDefaultOptions() - { - this.operations.DrawText("123", this.Font, Brushes.Solid(Rgba32.Red), Pens.Dash(Rgba32.Red, 1), Vector2.Zero); - - var processor = this.Verify>(0); - this.Verify>(1); - this.Verify>(2); - this.Verify>(3); - this.Verify>(4); - this.Verify>(5); - } - - [Fact] - public void BrushAppliesBeforePen() - { - this.operations.DrawText( - new TextGraphicsOptions(true), - "1", - this.Font, - Brushes.Solid(Rgba32.Red), - Pens.Dash(Rgba32.Red, 1), - Vector2.Zero); - - var processor = this.Verify>(0); - this.Verify>(1); - } + var processor = this.Verify>(0); - [Fact] - public void BrushAppliesBeforPenDefaultOptions() - { - this.operations.DrawText("1", this.Font, Brushes.Solid(Rgba32.Red), Pens.Dash(Rgba32.Red, 1), Vector2.Zero); - - var processor = this.Verify>(0); - this.Verify>(1); + Assert.Equal("123", processor.Text); + Assert.Equal(this.Font, processor.Font); + var brush = Assert.IsType>(processor.Brush); + Assert.Equal(Rgba32.Red, brush.Color); + Assert.Equal(PointF.Empty, processor.Location); + var penBrush = Assert.IsType>(processor.Pen.StrokeFill); + Assert.Equal(Rgba32.Red, penBrush.Color); + Assert.Equal(1, processor.Pen.StrokeWidth); } } } diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs index a9c7a6ebb..f90d5996e 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text using System; using System.Linq; using System.Text; - + using SixLabors.ImageSharp.Processing.Drawing.Brushes.GradientBrushes; using SixLabors.Primitives; [GroupOutput("Drawing/Text")] @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text private const string TestText2 = "THISISTESTWORDS "; - + [Theory] [WithSolidFilledImages(200, 100, "White", PixelTypes.Rgba32, 50, 0, 0, "SixLaborsSampleAB.woff", AB)] [WithSolidFilledImages(900, 100, "White", PixelTypes.Rgba32, 50, 0, 0, "OpenSans-Regular.ttf", TestText)] @@ -51,9 +51,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text provider.VerifyOperation( img => - { - img.Mutate(c => c.DrawText(text, new Font(font, fontSize), color, new PointF(x, y))); - }, + { + img.Mutate(c => c.DrawText(text, new Font(font, fontSize), color, new PointF(x, y))); + }, $"{fontName}-{fontSize}-{fnDisplayText}-({x},{y})", appendPixelTypeToFileName: false, appendSourceFileOrDescription: true); @@ -84,12 +84,12 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text } var textOptions = new TextGraphicsOptions - { - Antialias = true, - ApplyKerning = true, - VerticalAlignment = VerticalAlignment.Top, - HorizontalAlignment = HorizontalAlignment.Left, - }; + { + Antialias = true, + ApplyKerning = true, + VerticalAlignment = VerticalAlignment.Top, + HorizontalAlignment = HorizontalAlignment.Left, + }; TPixel color = NamedColors.Black; provider.VerifyOperation( diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 139df3972..fa165de5f 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -45,6 +45,12 @@ + + PreserveNewest + + + PreserveNewest + PreserveNewest From 6d92b4f83ac3172cad6a110b986ba7533e4bc55d Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Wed, 13 Jun 2018 18:23:43 +0100 Subject: [PATCH 22/63] update reference images --- tests/Images/External | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Images/External b/tests/Images/External index eb40b3c03..802ffbae9 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit eb40b3c039dd8c8ca448cb8073a59ca178901e9f +Subproject commit 802ffbae9af22d986226bc1c20d7d96aaf25d6b9 From 02baa60e89134b4baf89e6ca866f87315f66a278 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Wed, 13 Jun 2018 18:47:31 +0100 Subject: [PATCH 23/63] really update reference images this time --- tests/Images/External | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Images/External b/tests/Images/External index 802ffbae9..443db93ff 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 802ffbae9af22d986226bc1c20d7d96aaf25d6b9 +Subproject commit 443db93ffdb175dd0ef67eb8f0c525cc9ad59083 From 400b9e4366ed8f3a5cc590faf4137b6a5c321d01 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Thu, 14 Jun 2018 07:52:37 -0700 Subject: [PATCH 24/63] Interpolate Size --- src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs index 872c24286..b5b4d39b1 100644 --- a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs +++ b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { if (data.Length != Size) { - throw new ArgumentException(nameof(data), $"Must be 40 bytes. Was {data.Length} bytes."); + throw new ArgumentException(nameof(data), $"Must be {Size} bytes. Was {data.Length} bytes."); } return MemoryMarshal.Cast(data)[0]; From 1b38d48c4f0a3b3569674c1d01c902fdd77ca455 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Thu, 14 Jun 2018 07:52:50 -0700 Subject: [PATCH 25/63] stackalloc chroma --- src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index aa624838c..9ffd40c93 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -738,7 +738,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg { // "default" to 4:2:0 Span subsamples = stackalloc byte[] { 0x22, 0x11, 0x11 }; - byte[] chroma = { 0x00, 0x01, 0x01 }; + Span chroma = stackalloc byte[] { 0x00, 0x01, 0x01 }; switch (this.subsample) { From a573ee0a6e8947c3caf4dba6ec041a00cc4e009c Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Thu, 14 Jun 2018 08:29:21 -0700 Subject: [PATCH 26/63] Manually reference System.Runtime.CompilerServices.Unsafe in tests --- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 139df3972..09e915ce8 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -28,6 +28,7 @@ + From 4e43db783a41d637c937f5351816bab6a9c56594 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Thu, 14 Jun 2018 10:47:04 -0700 Subject: [PATCH 27/63] Enable AutoGenerateBindingRedirects for tests --- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 09e915ce8..7ecf1baca 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -9,6 +9,7 @@ SixLabors.ImageSharp.Tests SixLabors.ImageSharp.Tests AnyCPU;x64;x86 + true true From 121f1edce6c5d10317fb6888c1aa1f78f0144035 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Thu, 14 Jun 2018 22:11:05 +0100 Subject: [PATCH 28/63] ensure pen code path is tested --- .../Text/Processors/DrawTextProcessor.cs | 2 +- .../Drawing/Text/DrawTextOnImageTests.cs | 30 +++++++++++++++++++ tests/Images/External | 2 +- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs index b029ff516..8d51f4f44 100644 --- a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors { this.fillRegionProcessor = new FillRegionProcessor() { - Brush = this.Brush, + Brush = this.Pen.StrokeFill, Options = pathOptions }; } diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs index f90d5996e..5440eb8db 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs @@ -18,6 +18,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text using System.Linq; using System.Text; using SixLabors.ImageSharp.Processing.Drawing.Brushes.GradientBrushes; + using SixLabors.ImageSharp.Processing.Drawing.Pens; using SixLabors.Primitives; [GroupOutput("Drawing/Text")] @@ -101,6 +102,35 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text false); } + [Theory] + [WithSolidFilledImages(200, 100, "White", PixelTypes.Rgba32, 50, 0, 0, "SixLaborsSampleAB.woff", AB)] + [WithSolidFilledImages(900, 100, "White", PixelTypes.Rgba32, 50, 0, 0, "OpenSans-Regular.ttf", TestText)] + [WithSolidFilledImages(400, 40, "White", PixelTypes.Rgba32, 20, 0, 0, "OpenSans-Regular.ttf", TestText)] + [WithSolidFilledImages(1100, 200, "White", PixelTypes.Rgba32, 50, 150, 100, "OpenSans-Regular.ttf", TestText)] + public void FontShapesAreRenderedCorrectlyWithAPen( + TestImageProvider provider, + int fontSize, + int x, + int y, + string fontName, + string text) + where TPixel : struct, IPixel + { + Font font = CreateFont(fontName, fontSize); + string fnDisplayText = text.Replace("\n", ""); + fnDisplayText = fnDisplayText.Substring(0, Math.Min(fnDisplayText.Length, 4)); + TPixel color = NamedColors.Black; + + provider.VerifyOperation( + img => + { + img.Mutate(c => c.DrawText(text, new Font(font, fontSize),null, Pens.Solid(color, 1), new PointF(x, y))); + }, + $"pen_{fontName}-{fontSize}-{fnDisplayText}-({x},{y})", + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: true); + } + private static string Repeat(string str, int times) => string.Concat(Enumerable.Repeat(str, times)); private static Font CreateFont(string fontName, int size) diff --git a/tests/Images/External b/tests/Images/External index 443db93ff..07cdbcfca 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 443db93ffdb175dd0ef67eb8f0c525cc9ad59083 +Subproject commit 07cdbcfca121081eae97d6a9cd0e230c653eeb39 From f1d931a67ca265ecf58ae12b9a444b934e5f2a87 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 15 Jun 2018 08:07:35 -0700 Subject: [PATCH 29/63] Specify the runtime when running tests for netcoreapp2.1 [take 1] --- run-tests.ps1 | 5 +++++ tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/run-tests.ps1 b/run-tests.ps1 index d774f7a61..3218d9d67 100644 --- a/run-tests.ps1 +++ b/run-tests.ps1 @@ -75,6 +75,11 @@ else { $xunitArgs += " --fx-version 2.0.0" } + if ($targetFramework -eq "netcoreapp2.1") { + # There were issues matching the correct installed runtime if we do not specify it explicitly: + $xunitArgs += " --fx-version 2.1.0" + } + if ($is32Bit -eq "True") { $xunitArgs += " -x86" } diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 7ecf1baca..139df3972 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -9,7 +9,6 @@ SixLabors.ImageSharp.Tests SixLabors.ImageSharp.Tests AnyCPU;x64;x86 - true true @@ -29,7 +28,6 @@ - From db88844711b60b890d2e7a4c5b6b35445a85cbb1 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 15 Jun 2018 18:07:02 +0100 Subject: [PATCH 30/63] increase tolerance on tests --- tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs index 5440eb8db..8af374435 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs @@ -19,6 +19,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text using System.Text; using SixLabors.ImageSharp.Processing.Drawing.Brushes.GradientBrushes; using SixLabors.ImageSharp.Processing.Drawing.Pens; + using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.Primitives; [GroupOutput("Drawing/Text")] @@ -122,6 +123,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text TPixel color = NamedColors.Black; provider.VerifyOperation( + ImageComparer.Tolerant(perPixelManhattanThreshold: 16), img => { img.Mutate(c => c.DrawText(text, new Font(font, fontSize),null, Pens.Solid(color, 1), new PointF(x, y))); From e43a8dbc2c554ecdbafebf265831442f7a5ea0b6 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 15 Jun 2018 21:46:58 +0100 Subject: [PATCH 31/63] apply optermised font rendering path to glyphs outlines --- .../ImageSharp.Drawing.csproj | 2 +- .../Text/Processors/DrawTextProcessor.cs | 190 ++++++++++-------- .../Drawing/DrawTextOutline.cs | 99 +++++++++ .../Drawing/Text/DrawTextOnImageTests.cs | 3 +- 4 files changed, 209 insertions(+), 85 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index 30ca57b59..3776830ae 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -39,7 +39,7 @@ - + All diff --git a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs index 8d51f4f44..a8b5e863b 100644 --- a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs @@ -26,8 +26,6 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors internal class DrawTextProcessor : ImageProcessor where TPixel : struct, IPixel { - private FillRegionProcessor fillRegionProcessor = null; - private CachingGlyphRenderer textRenderer; /// @@ -83,8 +81,6 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors { base.BeforeImageApply(source, sourceRectangle); - // user slow path if pen is set and fast render for brush only rendering - // do everythign at the image level as we are deligating the processing down to other processors var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY, this.Location) { @@ -95,52 +91,9 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors VerticalAlignment = this.Options.VerticalAlignment }; - if (this.Pen != null) - { - IPathCollection glyphs = TextBuilder.GenerateGlyphs(this.Text, style); - - var pathOptions = (GraphicsOptions)this.Options; - if (this.Brush != null) - { - // we will reuse the processor for all fill operations to reduce allocations - if (this.fillRegionProcessor == null) - { - this.fillRegionProcessor = new FillRegionProcessor() - { - Brush = this.Brush, - Options = pathOptions - }; - } - - foreach (IPath p in glyphs) - { - this.fillRegionProcessor.Region = new ShapeRegion(p); - this.fillRegionProcessor.Apply(source, sourceRectangle); - } - } - - // we will reuse the processor for all fill operations to reduce allocations - if (this.fillRegionProcessor == null) - { - this.fillRegionProcessor = new FillRegionProcessor() - { - Brush = this.Pen.StrokeFill, - Options = pathOptions - }; - } - - foreach (IPath p in glyphs) - { - this.fillRegionProcessor.Region = new ShapePath(p, this.Pen); - this.fillRegionProcessor.Apply(source, sourceRectangle); - } - } - else - { - this.textRenderer = new CachingGlyphRenderer(source.GetMemoryManager()); - this.textRenderer.Options = (GraphicsOptions)this.Options; - TextRenderer.RenderTextTo(this.textRenderer, this.Text, style); - } + this.textRenderer = new CachingGlyphRenderer(source.GetMemoryManager(), this.Text.Length, this.Pen, this.Brush != null); + this.textRenderer.Options = (GraphicsOptions)this.Options; + TextRenderer.RenderTextTo(this.textRenderer, this.Text, style); } protected override void AfterImageApply(Image source, Rectangle sourceRectangle) @@ -154,23 +107,26 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { // this is a no-op as we have processes all as an image, we should be able to pass out of before email apply a skip frames outcome - if (this.Pen == null && this.Brush != null && this.textRenderer != null && this.textRenderer.Operations.Count > 0) - { - // we have rendered at the image level now we can draw - List operations = this.textRenderer.Operations; + Draw(this.textRenderer.FillOperations, this.Brush); + Draw(this.textRenderer.OutlineOperations, this.Pen?.StrokeFill); - using (BrushApplicator app = this.Brush.CreateApplicator(source, sourceRectangle, this.textRenderer.Options)) + void Draw(List operations, IBrush brush) + { + if (operations?.Count > 0) { - foreach (DrawingOperation operation in operations) + using (BrushApplicator app = brush.CreateApplicator(source, sourceRectangle, this.textRenderer.Options)) { - IBuffer2D buffer = operation.Map; - int startY = operation.Location.Y; - int startX = operation.Location.X; - int end = operation.Map.Height; - for (int row = 0; row < end; row++) + foreach (DrawingOperation operation in operations) { - int y = startY + row; - app.Apply(buffer.GetRowSpan(row), startX, y); + IBuffer2D buffer = operation.Map; + int startY = operation.Location.Y; + int startX = operation.Location.X; + int end = operation.Map.Height; + for (int row = 0; row < end; row++) + { + int y = startY + row; + app.Apply(buffer.GetRowSpan(row), startX, y); + } } } } @@ -192,18 +148,42 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors private int currentRenderingGlyph = 0; private PointF currentPoint = default(PointF); - private Dictionary> glyphMap = new Dictionary>(); - - public CachingGlyphRenderer(MemoryManager memoryManager) + private HashSet renderedGlyphs = new HashSet(); + private Dictionary> glyphMap; + private Dictionary> glyphMapPen; + private bool renderOutline = false; + private bool renderFill = false; + private bool raterizationRequired = false; + + public CachingGlyphRenderer(MemoryManager memoryManager, int size, IPen pen, bool renderFill) { this.MemoryManager = memoryManager; + this.Pen = pen; + this.renderFill = renderFill; + this.renderOutline = pen != null; + if (this.renderFill) + { + this.FillOperations = new List(size); + this.glyphMap = new Dictionary>(); + } + + if (this.renderOutline) + { + this.OutlineOperations = new List(size); + this.glyphMapPen = new Dictionary>(); + } + this.builder = new PathBuilder(); } - public List Operations { get; } = new List(); + public List FillOperations { get; } + + public List OutlineOperations { get; } public MemoryManager MemoryManager { get; internal set; } + public IPen Pen { get; internal set; } + public GraphicsOptions Options { get; internal set; } public void BeginFigure() @@ -215,10 +195,10 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors { this.currentRenderPosition = Point.Truncate(bounds.Location); this.currentRenderingGlyph = cacheKey; - - if (this.glyphMap.ContainsKey(this.currentRenderingGlyph)) + if (this.renderedGlyphs.Contains(cacheKey)) { // we have already drawn the glyph vectors skip trying again + this.raterizationRequired = false; return false; } @@ -228,13 +208,15 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors // ensure all glyphs render around [zero, zero] so offset negative root positions so when we draw the glyph we can offet it back this.builder.SetOrigin(new PointF(-(int)bounds.X, -(int)bounds.Y)); + this.raterizationRequired = true; return true; } public void BeginText(RectangleF bounds) { // not concerned about this one - this.Operations.Clear(); + this.OutlineOperations?.Clear(); + this.FillOperations?.Clear(); } public void CubicBezierTo(PointF secondControlPoint, PointF thirdControlPoint, PointF point) @@ -245,9 +227,20 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors public void Dispose() { - foreach (KeyValuePair> m in this.glyphMap) + if (this.renderFill) + { + foreach (KeyValuePair> m in this.glyphMap) + { + m.Value.Dispose(); + } + } + + if (this.renderOutline) { - m.Value.Dispose(); + foreach (KeyValuePair> m in this.glyphMapPen) + { + m.Value.Dispose(); + } } } @@ -258,22 +251,53 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors public void EndGlyph() { - if (!this.glyphMap.ContainsKey(this.currentRenderingGlyph)) + // has the glyoh been rendedered already???? + if (this.raterizationRequired) { - this.RenderToCache(); + IPath path = this.builder.Build(); + if (this.renderFill) + { + this.glyphMap[this.currentRenderingGlyph] = this.Render(path); + } + + if (this.renderOutline) + { + if (this.Pen.StrokePattern.Length == 0) + { + path = path.GenerateOutline(this.Pen.StrokeWidth); + } + else + { + path = path.GenerateOutline(this.Pen.StrokeWidth, this.Pen.StrokePattern); + } + + this.glyphMapPen[this.currentRenderingGlyph] = this.Render(path); + } + + this.renderedGlyphs.Add(this.currentRenderingGlyph); } - this.Operations.Add(new DrawingOperation + if (this.renderFill) { - Location = this.currentRenderPosition, - Map = this.glyphMap[this.currentRenderingGlyph] - }); + this.FillOperations.Add(new DrawingOperation + { + Location = this.currentRenderPosition, + Map = this.glyphMap[this.currentRenderingGlyph] + }); + } + + if (this.renderOutline) + { + this.OutlineOperations.Add(new DrawingOperation + { + Location = this.currentRenderPosition, + Map = this.glyphMapPen[this.currentRenderingGlyph] + }); + } } - private void RenderToCache() + private Buffer2D Render(IPath path) { - IPath path = this.builder.Build(); - var size = Rectangle.Ceiling(path.Bounds); float subpixelCount = 4; float offset = 0.5f; @@ -289,7 +313,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors // take the path inside the path builder, scan thing and generate a Buffer2d representing the glyph and cache it. Buffer2D fullBuffer = this.MemoryManager.Allocate2D(size.Width + 1, size.Height + 1, true); - this.glyphMap.Add(this.currentRenderingGlyph, fullBuffer); + using (IBuffer bufferBacking = this.MemoryManager.Allocate(path.MaxIntersections)) using (IBuffer rowIntersectionBuffer = this.MemoryManager.Allocate(size.Width)) { @@ -379,6 +403,8 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors } } } + + return fullBuffer; } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs new file mode 100644 index 000000000..e85e33235 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs @@ -0,0 +1,99 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +using System.Drawing; +using System.Drawing.Drawing2D; +using BenchmarkDotNet.Attributes; +using System.IO; +using System.Numerics; + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Text; +using SixLabors.ImageSharp.Processing.Overlays; +using SixLabors.ImageSharp.Processing.Drawing; +using System.Linq; + +namespace SixLabors.ImageSharp.Benchmarks +{ + + [MemoryDiagnoser] + public class DrawTextOutline : BenchmarkBase + { + + [Params(10, 100)] + public int TextIterations{ get; set; } + public string TextPhrase { get; set; } = "Hello World"; + public string TextToRender => string.Join(" ", Enumerable.Repeat(TextPhrase, TextIterations)); + + + [Benchmark(Baseline = true, Description = "System.Drawing Draw Text Outline")] + public void DrawTextSystemDrawing() + { + using (Bitmap destination = new Bitmap(800, 800)) + { + + using (Graphics graphics = Graphics.FromImage(destination)) + { + graphics.InterpolationMode = InterpolationMode.Default; + graphics.SmoothingMode = SmoothingMode.AntiAlias; + Pen pen = new Pen(System.Drawing.Color.HotPink, 10); + var font = new Font("Arial", 12, GraphicsUnit.Point); + var gp = new GraphicsPath(); + gp.AddString(TextToRender, font.FontFamily, (int)font.Style, font.Size, new RectangleF(10, 10, 780, 780), new StringFormat()); + graphics.DrawPath(pen, gp); + } + } + } + + [Benchmark(Description = "ImageSharp Draw Text Outline - Cached Glyphs")] + public void DrawTextCore() + { + using (Image image = new Image(800, 800)) + { + var font = SixLabors.Fonts.SystemFonts.CreateFont("Arial", 12); + image.Mutate(x => x.ApplyProcessor(new SixLabors.ImageSharp.Processing.Text.Processors.DrawTextProcessor(new TextGraphicsOptions(true) { WrapTextWidth = 780 }, TextToRender, font, null, SixLabors.ImageSharp.Processing.Drawing.Pens.Pens.Solid(Rgba32.HotPink, 10), new SixLabors.Primitives.PointF(10, 10)))); + } + } + + [Benchmark(Description = "ImageSharp Draw Text Outline - Nieve")] + public void DrawTextCoreOld() + { + using (Image image = new Image(800, 800)) + { + var font = SixLabors.Fonts.SystemFonts.CreateFont("Arial", 12); + image.Mutate(x => DrawTextOldVersion(x, new TextGraphicsOptions(true) { WrapTextWidth = 780 }, TextToRender, font, null, SixLabors.ImageSharp.Processing.Drawing.Pens.Pens.Solid(Rgba32.HotPink, 10), new SixLabors.Primitives.PointF(10, 10))); + } + + IImageProcessingContext DrawTextOldVersion(IImageProcessingContext source, TextGraphicsOptions options, string text, SixLabors.Fonts.Font font, SixLabors.ImageSharp.Processing.Drawing.Brushes.IBrush brush, SixLabors.ImageSharp.Processing.Drawing.Pens.IPen pen, SixLabors.Primitives.PointF location) + where TPixel : struct, IPixel + { + var style = new SixLabors.Fonts.RendererOptions(font, options.DpiX, options.DpiY, location) + { + ApplyKerning = options.ApplyKerning, + TabWidth = options.TabWidth, + WrappingWidth = options.WrapTextWidth, + HorizontalAlignment = options.HorizontalAlignment, + VerticalAlignment = options.VerticalAlignment + }; + + Shapes.IPathCollection glyphs = Shapes.TextBuilder.GenerateGlyphs(text, style); + + var pathOptions = (GraphicsOptions)options; + if (brush != null) + { + source.Fill(pathOptions, brush, glyphs); + } + + if (pen != null) + { + source.Draw(pathOptions, pen, glyphs); + } + + return source; + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs index 8af374435..cc7d8622a 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs @@ -106,7 +106,6 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text [Theory] [WithSolidFilledImages(200, 100, "White", PixelTypes.Rgba32, 50, 0, 0, "SixLaborsSampleAB.woff", AB)] [WithSolidFilledImages(900, 100, "White", PixelTypes.Rgba32, 50, 0, 0, "OpenSans-Regular.ttf", TestText)] - [WithSolidFilledImages(400, 40, "White", PixelTypes.Rgba32, 20, 0, 0, "OpenSans-Regular.ttf", TestText)] [WithSolidFilledImages(1100, 200, "White", PixelTypes.Rgba32, 50, 150, 100, "OpenSans-Regular.ttf", TestText)] public void FontShapesAreRenderedCorrectlyWithAPen( TestImageProvider provider, @@ -123,7 +122,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text TPixel color = NamedColors.Black; provider.VerifyOperation( - ImageComparer.Tolerant(perPixelManhattanThreshold: 16), + ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20), img => { img.Mutate(c => c.DrawText(text, new Font(font, fontSize),null, Pens.Solid(color, 1), new PointF(x, y))); From c3bf1664ab701e2ceaa3b06f1ee83a81b66fd2ef Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 15 Jun 2018 16:21:54 -0700 Subject: [PATCH 32/63] Eliminate reference to System.Runtime.CompilerServices.Unsafe on .NETCOREAPP2.1 --- src/ImageSharp/ImageSharp.csproj | 2 +- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 390c65506..baf0551f1 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -40,12 +40,12 @@ All - + diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 139df3972..e0f13fb21 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -25,6 +25,11 @@ + + + + + From 8b856093200b7976eb8bbd47fdb3b01f1782bdb2 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 15 Jun 2018 16:37:24 -0700 Subject: [PATCH 33/63] Downgrade Unsafe package [test] --- src/ImageSharp/ImageSharp.csproj | 4 ++++ .../Drawing/Text/DrawTextOnImageTests.cs | 13 ++++--------- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 4 ---- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index baf0551f1..299586abc 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -47,6 +47,10 @@ + + + + diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs index a9c7a6ebb..c3a2bf17f 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs @@ -1,25 +1,20 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Numerics; - +using System; +using System.Linq; +using System.Text; using SixLabors.Fonts; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; -using SixLabors.ImageSharp.Processing.Drawing; using SixLabors.ImageSharp.Processing.Text; +using SixLabors.Primitives; using Xunit; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Drawing.Text { - using System; - using System.Linq; - using System.Text; - - using SixLabors.Primitives; - [GroupOutput("Drawing/Text")] public class DrawTextOnImageTests { diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index e0f13fb21..6add99c05 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -25,10 +25,6 @@ - - - - From 3896723bfbdaa0d0d483819cbb394048735c46d4 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 17 Jun 2018 10:59:17 +0100 Subject: [PATCH 34/63] additional tests around pen rendering with patterns --- .../Text/Processors/DrawTextProcessor.cs | 35 ++++++++++++++++--- .../Drawing/Text/DrawTextOnImageTests.cs | 33 ++++++++++++++++- tests/Images/External | 2 +- 3 files changed, 63 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs index a8b5e863b..5681405bf 100644 --- a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs @@ -121,11 +121,29 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors IBuffer2D buffer = operation.Map; int startY = operation.Location.Y; int startX = operation.Location.X; + int offSetSpan = 0; + if (startX < 0) + { + offSetSpan = -startX; + startX = 0; + } + + int fistRow = 0; + if (startY < 0) + { + fistRow = -startY; + } + int end = operation.Map.Height; - for (int row = 0; row < end; row++) + + int maxHeight = source.Height - startY; + end = Math.Min(end, maxHeight); + + for (int row = fistRow; row < end; row++) { int y = startY + row; - app.Apply(buffer.GetRowSpan(row), startX, y); + Span span = buffer.GetRowSpan(row).Slice(offSetSpan); + app.Apply(span, startX, y); } } } @@ -146,7 +164,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors private Point currentRenderPosition = default(Point); private int currentRenderingGlyph = 0; - + private int offset = 0; private PointF currentPoint = default(PointF); private HashSet renderedGlyphs = new HashSet(); private Dictionary> glyphMap; @@ -161,6 +179,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors this.Pen = pen; this.renderFill = renderFill; this.renderOutline = pen != null; + this.offset = 2; if (this.renderFill) { this.FillOperations = new List(size); @@ -169,6 +188,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors if (this.renderOutline) { + this.offset = (int)MathF.Ceiling((pen.StrokeWidth * 2) + 2); this.OutlineOperations = new List(size); this.glyphMapPen = new Dictionary>(); } @@ -194,6 +214,9 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors public bool BeginGlyph(RectangleF bounds, int cacheKey) { this.currentRenderPosition = Point.Truncate(bounds.Location); + + // we have offset our rendering origion a little bit down to prevent edge cropping, move the draw origin up to compensate + this.currentRenderPosition = new Point(this.currentRenderPosition.X - this.offset, this.currentRenderPosition.Y - this.offset); this.currentRenderingGlyph = cacheKey; if (this.renderedGlyphs.Contains(cacheKey)) { @@ -206,7 +229,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors this.builder.Clear(); // ensure all glyphs render around [zero, zero] so offset negative root positions so when we draw the glyph we can offet it back - this.builder.SetOrigin(new PointF(-(int)bounds.X, -(int)bounds.Y)); + this.builder.SetOrigin(new PointF(-(int)bounds.X + this.offset, -(int)bounds.Y + this.offset)); this.raterizationRequired = true; return true; @@ -298,7 +321,9 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors private Buffer2D Render(IPath path) { - var size = Rectangle.Ceiling(path.Bounds); + Size size = Rectangle.Ceiling(path.Bounds).Size; + size = new Size(size.Width + (this.offset * 2), size.Height + (this.offset * 2)); + float subpixelCount = 4; float offset = 0.5f; if (this.Options.Antialias) diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs index cc7d8622a..400917f7a 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs @@ -52,6 +52,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text TPixel color = NamedColors.Black; provider.VerifyOperation( + ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20), img => { img.Mutate(c => c.DrawText(text, new Font(font, fontSize), color, new PointF(x, y))); @@ -95,6 +96,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text TPixel color = NamedColors.Black; provider.VerifyOperation( + ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20), img => { img.Mutate(c => c.DrawText(textOptions, sb.ToString(), font, color, new PointF(10, 5))); @@ -125,7 +127,36 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20), img => { - img.Mutate(c => c.DrawText(text, new Font(font, fontSize),null, Pens.Solid(color, 1), new PointF(x, y))); + img.Mutate(c => c.DrawText(text, new Font(font, fontSize), null, Pens.Solid(color, 1), new PointF(x, y))); + }, + $"pen_{fontName}-{fontSize}-{fnDisplayText}-({x},{y})", + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: true); + } + + [Theory] + [WithSolidFilledImages(200, 100, "White", PixelTypes.Rgba32, 50, 0, 0, "SixLaborsSampleAB.woff", AB)] + [WithSolidFilledImages(900, 100, "White", PixelTypes.Rgba32, 50, 0, 0, "OpenSans-Regular.ttf", TestText)] + [WithSolidFilledImages(1100, 200, "White", PixelTypes.Rgba32, 50, 150, 100, "OpenSans-Regular.ttf", TestText)] + public void FontShapesAreRenderedCorrectlyWithAPenPatterned( + TestImageProvider provider, + int fontSize, + int x, + int y, + string fontName, + string text) + where TPixel : struct, IPixel + { + Font font = CreateFont(fontName, fontSize); + string fnDisplayText = text.Replace("\n", ""); + fnDisplayText = fnDisplayText.Substring(0, Math.Min(fnDisplayText.Length, 4)); + TPixel color = NamedColors.Black; + + provider.VerifyOperation( + ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20), + img => + { + img.Mutate(c => c.DrawText(text, new Font(font, fontSize), null, Pens.DashDot(color, 3), new PointF(x, y))); }, $"pen_{fontName}-{fontSize}-{fnDisplayText}-({x},{y})", appendPixelTypeToFileName: false, diff --git a/tests/Images/External b/tests/Images/External index 07cdbcfca..09059fae2 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 07cdbcfca121081eae97d6a9cd0e230c653eeb39 +Subproject commit 09059fae2d8bea3a4c9288ab10fb184f1b648f40 From 886038928ba9439275bb06651657a23e6448cec2 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 17 Jun 2018 10:59:27 +0100 Subject: [PATCH 35/63] increase coverage on drawing path collections --- .../Drawing/Paths/DrawPathCollection.cs | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 tests/ImageSharp.Tests/Drawing/Paths/DrawPathCollection.cs diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawPathCollection.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawPathCollection.cs new file mode 100644 index 000000000..ecdfd03e5 --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Paths/DrawPathCollection.cs @@ -0,0 +1,117 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Primitives; +using SixLabors.ImageSharp.Processing.Drawing; +using SixLabors.ImageSharp.Processing.Drawing.Brushes; +using SixLabors.ImageSharp.Processing.Drawing.Pens; +using SixLabors.ImageSharp.Processing.Drawing.Processors; +using SixLabors.Shapes; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Drawing.Paths +{ + public class DrawPathCollection : BaseImageOperationsExtensionTest + { + GraphicsOptions noneDefault = new GraphicsOptions(); + Rgba32 color = Rgba32.HotPink; + Pen pen = Pens.Solid(Rgba32.HotPink, 1); + IPath path1 = new Path(new LinearLineSegment(new SixLabors.Primitives.PointF[] { + new Vector2(10,10), + new Vector2(20,10), + new Vector2(20,10), + new Vector2(30,10), + })); + IPath path2 = new Path(new LinearLineSegment(new SixLabors.Primitives.PointF[] { + new Vector2(10,10), + new Vector2(20,10), + new Vector2(20,10), + new Vector2(30,10), + })); + + IPathCollection pathCollection; + + public DrawPathCollection() + { + this.pathCollection = new PathCollection(this.path1, this.path2); + } + + [Fact] + public void CorrectlySetsBrushAndPath() + { + this.operations.Draw(this.pen, this.pathCollection); + + for (int i = 0; i < 2; i++) + { + FillRegionProcessor processor = this.Verify>(i); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + ShapePath region = Assert.IsType(processor.Region); + + // path is converted to a polygon before filling + ComplexPolygon polygon = Assert.IsType(region.Shape); + + Assert.Equal(this.pen.StrokeFill, processor.Brush); + } + } + + [Fact] + public void CorrectlySetsBrushPathOptions() + { + this.operations.Draw(this.noneDefault, this.pen, this.pathCollection); + + for (int i = 0; i < 2; i++) + { + FillRegionProcessor processor = this.Verify>(i); + + Assert.Equal(this.noneDefault, processor.Options); + + ShapePath region = Assert.IsType(processor.Region); + ComplexPolygon polygon = Assert.IsType(region.Shape); + + Assert.Equal(this.pen.StrokeFill, processor.Brush); + } + } + + [Fact] + public void CorrectlySetsColorAndPath() + { + this.operations.Draw(this.color, 1, this.pathCollection); + + for (int i = 0; i < 2; i++) + { + FillRegionProcessor processor = this.Verify>(i); + + Assert.Equal(GraphicsOptions.Default, processor.Options); + + ShapePath region = Assert.IsType(processor.Region); + ComplexPolygon polygon = Assert.IsType(region.Shape); + + SolidBrush brush = Assert.IsType>(processor.Brush); + Assert.Equal(this.color, brush.Color); + } + } + + [Fact] + public void CorrectlySetsColorPathAndOptions() + { + this.operations.Draw(this.noneDefault, this.color, 1, this.pathCollection); + + for (int i = 0; i < 2; i++) + { + FillRegionProcessor processor = this.Verify>(i); + + Assert.Equal(this.noneDefault, processor.Options); + + ShapePath region = Assert.IsType(processor.Region); + ComplexPolygon polygon = Assert.IsType(region.Shape); + + SolidBrush brush = Assert.IsType>(processor.Brush); + Assert.Equal(this.color, brush.Color); + } + } + } +} From 5609f1bdb3df4a30d8ff54c3c53652c84345fe4c Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 17 Jun 2018 11:07:24 +0100 Subject: [PATCH 36/63] fix api changes due to MemoryManager->MemoryAllocator rename --- .../Text/Processors/DrawTextOnPathProcessor.cs | 2 -- .../Processing/Text/Processors/DrawTextProcessor.cs | 12 ++++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextOnPathProcessor.cs b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextOnPathProcessor.cs index c8a51865c..6c33d306b 100644 --- a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextOnPathProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextOnPathProcessor.cs @@ -4,8 +4,6 @@ using System; using System.Threading.Tasks; using SixLabors.Fonts; -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Processing.Drawing.Brushes; diff --git a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs index 5681405bf..d00cba8a3 100644 --- a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs @@ -7,13 +7,13 @@ using System.Runtime.CompilerServices; using System.Threading.Tasks; using SixLabors.Fonts; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Processing.Drawing.Brushes; using SixLabors.ImageSharp.Processing.Drawing.Pens; using SixLabors.ImageSharp.Processing.Drawing.Processors; using SixLabors.ImageSharp.Processing.Processors; +using SixLabors.Memory; using SixLabors.Primitives; using SixLabors.Shapes; @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors VerticalAlignment = this.Options.VerticalAlignment }; - this.textRenderer = new CachingGlyphRenderer(source.GetMemoryManager(), this.Text.Length, this.Pen, this.Brush != null); + this.textRenderer = new CachingGlyphRenderer(source.GetMemoryAllocator(), this.Text.Length, this.Pen, this.Brush != null); this.textRenderer.Options = (GraphicsOptions)this.Options; TextRenderer.RenderTextTo(this.textRenderer, this.Text, style); } @@ -173,7 +173,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors private bool renderFill = false; private bool raterizationRequired = false; - public CachingGlyphRenderer(MemoryManager memoryManager, int size, IPen pen, bool renderFill) + public CachingGlyphRenderer(MemoryAllocator memoryManager, int size, IPen pen, bool renderFill) { this.MemoryManager = memoryManager; this.Pen = pen; @@ -200,7 +200,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors public List OutlineOperations { get; } - public MemoryManager MemoryManager { get; internal set; } + public MemoryAllocator MemoryManager { get; internal set; } public IPen Pen { get; internal set; } @@ -355,8 +355,8 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors { var start = new PointF(path.Bounds.Left - 1, subPixel); var end = new PointF(path.Bounds.Right + 1, subPixel); - Span intersectionSpan = rowIntersectionBuffer.Span; - Span buffer = bufferBacking.Span; + Span intersectionSpan = rowIntersectionBuffer.GetSpan(); + Span buffer = bufferBacking.GetSpan(); int pointsFound = path.FindIntersections(start, end, intersectionSpan); if (pointsFound == 0) From 77bf952bbd69ba5ac77d0dfdc641a43abe07d353 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 17 Jun 2018 13:50:12 +0100 Subject: [PATCH 37/63] test drawing along path --- .../Primitives/ShapePath.cs | 2 +- .../Processors/DrawTextOnPathProcessor.cs | 25 +++-------- .../Drawing/Text/DrawTextOnImageTests.cs | 41 +++++++++++++++++++ tests/Images/External | 2 +- 4 files changed, 48 insertions(+), 22 deletions(-) diff --git a/src/ImageSharp.Drawing/Primitives/ShapePath.cs b/src/ImageSharp.Drawing/Primitives/ShapePath.cs index 2a569f061..7aae2bf8e 100644 --- a/src/ImageSharp.Drawing/Primitives/ShapePath.cs +++ b/src/ImageSharp.Drawing/Primitives/ShapePath.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Primitives /// The pen to apply to the shape. // TODO: SixLabors.shape will be moving to a Span/ReadOnlySpan based API shortly use ToArray for now. public ShapePath(IPath shape, IPen pen) - : base(shape.GenerateOutline(pen.StrokeWidth, pen.StrokePattern.ToArray())) + : base(shape.GenerateOutline(pen.StrokeWidth, pen.StrokePattern)) { } } diff --git a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextOnPathProcessor.cs b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextOnPathProcessor.cs index 6c33d306b..1e703d1cc 100644 --- a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextOnPathProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextOnPathProcessor.cs @@ -82,25 +82,18 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors { ApplyKerning = this.Options.ApplyKerning, TabWidth = this.Options.TabWidth, - WrappingWidth = this.Options.WrapTextWidth, + WrappingWidth = this.Path.Length, HorizontalAlignment = this.Options.HorizontalAlignment, VerticalAlignment = this.Options.VerticalAlignment }; IPathCollection glyphs = TextBuilder.GenerateGlyphs(this.Text, this.Path, style); + this.fillRegionProcessor = new FillRegionProcessor(); + this.fillRegionProcessor.Options = (GraphicsOptions)this.Options; - var pathOptions = (GraphicsOptions)this.Options; if (this.Brush != null) { - // we will reuse the processor for all fill operations to reduce allocations - if (this.fillRegionProcessor == null) - { - this.fillRegionProcessor = new FillRegionProcessor() - { - Brush = this.Brush, - Options = pathOptions - }; - } + this.fillRegionProcessor.Brush = this.Brush; foreach (IPath p in glyphs) { @@ -111,15 +104,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors if (this.Pen != null) { - // we will reuse the processor for all fill operations to reduce allocations - if (this.fillRegionProcessor == null) - { - this.fillRegionProcessor = new FillRegionProcessor() - { - Brush = this.Brush, - Options = pathOptions - }; - } + this.fillRegionProcessor.Brush = this.Pen.StrokeFill; foreach (IPath p in glyphs) { diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs index 400917f7a..a1a9b0222 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs @@ -17,10 +17,12 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text using System; using System.Linq; using System.Text; + using SixLabors.ImageSharp.Processing.Drawing.Brushes; using SixLabors.ImageSharp.Processing.Drawing.Brushes.GradientBrushes; using SixLabors.ImageSharp.Processing.Drawing.Pens; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.Primitives; + using SixLabors.Shapes; [GroupOutput("Drawing/Text")] public class DrawTextOnImageTests @@ -163,6 +165,45 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text appendSourceFileOrDescription: true); } + + [Theory] + [WithSolidFilledImages(200, 100, "White", PixelTypes.Rgba32, 50, "SixLaborsSampleAB.woff", AB)] + [WithSolidFilledImages(900, 100, "White", PixelTypes.Rgba32, 50, "OpenSans-Regular.ttf", TestText)] + public void FontShapesAreRenderedCorrectlyAlongAPath( + TestImageProvider provider, + int fontSize, + string fontName, + string text) + where TPixel : struct, IPixel + { + + Font font = CreateFont(fontName, fontSize); + string fnDisplayText = text.Replace("\n", ""); + fnDisplayText = fnDisplayText.Substring(0, Math.Min(fnDisplayText.Length, 4)); + TPixel colorOutline = NamedColors.Black; + TPixel colorFill = NamedColors.Gray; + + provider.VerifyOperation( + ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20), + img => + { + + IPath path = new Path(new LinearLineSegment(new Point(0, img.Height), new Point(img.Width, 0))); + img.Mutate(c => c.DrawText( + new TextGraphicsOptions { + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Top + } , + text, new Font(font, fontSize), + Brushes.Solid(colorFill) + , Pens.DashDot(colorOutline, 3), + path)); + }, + $"pen_{fontName}-{fontSize}-{fnDisplayText}", + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: true); + } + private static string Repeat(string str, int times) => string.Concat(Enumerable.Repeat(str, times)); private static Font CreateFont(string fontName, int size) diff --git a/tests/Images/External b/tests/Images/External index 09059fae2..83f6cbab9 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 09059fae2d8bea3a4c9288ab10fb184f1b648f40 +Subproject commit 83f6cbab9a08b550c84bf931c95188341140516a From 31ce2836c047e8f3cd15a4cbada5fe5956bb45b1 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 17 Jun 2018 15:06:18 +0200 Subject: [PATCH 38/63] format long lines in DrawTextExtensions.Path.cs --- .../Text/DrawTextExtensions.Path.cs | 94 ++++++++++++++----- 1 file changed, 70 insertions(+), 24 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.Path.cs b/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.Path.cs index e0c133d50..827d6b95f 100644 --- a/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.Path.cs +++ b/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.Path.cs @@ -28,9 +28,14 @@ namespace SixLabors.ImageSharp.Processing.Text /// /// The . /// - public static IImageProcessingContext DrawText(this IImageProcessingContext source, string text, Font font, TPixel color, IPath path) - where TPixel : struct, IPixel - => source.DrawText(TextGraphicsOptions.Default, text, font, color, path); + public static IImageProcessingContext DrawText( + this IImageProcessingContext source, + string text, + Font font, + TPixel color, + IPath path) + where TPixel : struct, IPixel => + source.DrawText(TextGraphicsOptions.Default, text, font, color, path); /// /// Draws the text onto the the image filled via the brush. @@ -45,9 +50,15 @@ namespace SixLabors.ImageSharp.Processing.Text /// /// The . /// - public static IImageProcessingContext DrawText(this IImageProcessingContext source, TextGraphicsOptions options, string text, Font font, TPixel color, IPath path) - where TPixel : struct, IPixel - => source.DrawText(options, text, font, Brushes.Solid(color), null, path); + public static IImageProcessingContext DrawText( + this IImageProcessingContext source, + TextGraphicsOptions options, + string text, + Font font, + TPixel color, + IPath path) + where TPixel : struct, IPixel => + source.DrawText(options, text, font, Brushes.Solid(color), null, path); /// /// Draws the text onto the the image filled via the brush. @@ -61,9 +72,14 @@ namespace SixLabors.ImageSharp.Processing.Text /// /// The . /// - public static IImageProcessingContext DrawText(this IImageProcessingContext source, string text, Font font, IBrush brush, IPath path) - where TPixel : struct, IPixel - => source.DrawText(TextGraphicsOptions.Default, text, font, brush, path); + public static IImageProcessingContext DrawText( + this IImageProcessingContext source, + string text, + Font font, + IBrush brush, + IPath path) + where TPixel : struct, IPixel => + source.DrawText(TextGraphicsOptions.Default, text, font, brush, path); /// /// Draws the text onto the the image filled via the brush. @@ -78,9 +94,15 @@ namespace SixLabors.ImageSharp.Processing.Text /// /// The . /// - public static IImageProcessingContext DrawText(this IImageProcessingContext source, TextGraphicsOptions options, string text, Font font, IBrush brush, IPath path) - where TPixel : struct, IPixel - => source.DrawText(options, text, font, brush, null, path); + public static IImageProcessingContext DrawText( + this IImageProcessingContext source, + TextGraphicsOptions options, + string text, + Font font, + IBrush brush, + IPath path) + where TPixel : struct, IPixel => + source.DrawText(options, text, font, brush, null, path); /// /// Draws the text onto the the image outlined via the pen. @@ -94,9 +116,14 @@ namespace SixLabors.ImageSharp.Processing.Text /// /// The . /// - public static IImageProcessingContext DrawText(this IImageProcessingContext source, string text, Font font, IPen pen, IPath path) - where TPixel : struct, IPixel - => source.DrawText(TextGraphicsOptions.Default, text, font, pen, path); + public static IImageProcessingContext DrawText( + this IImageProcessingContext source, + string text, + Font font, + IPen pen, + IPath path) + where TPixel : struct, IPixel => + source.DrawText(TextGraphicsOptions.Default, text, font, pen, path); /// /// Draws the text onto the the image outlined via the pen. @@ -111,9 +138,15 @@ namespace SixLabors.ImageSharp.Processing.Text /// /// The . /// - public static IImageProcessingContext DrawText(this IImageProcessingContext source, TextGraphicsOptions options, string text, Font font, IPen pen, IPath path) - where TPixel : struct, IPixel - => source.DrawText(options, text, font, null, pen, path); + public static IImageProcessingContext DrawText( + this IImageProcessingContext source, + TextGraphicsOptions options, + string text, + Font font, + IPen pen, + IPath path) + where TPixel : struct, IPixel => + source.DrawText(options, text, font, null, pen, path); /// /// Draws the text onto the the image filled via the brush then outlined via the pen. @@ -128,9 +161,15 @@ namespace SixLabors.ImageSharp.Processing.Text /// /// The . /// - public static IImageProcessingContext DrawText(this IImageProcessingContext source, string text, Font font, IBrush brush, IPen pen, IPath path) - where TPixel : struct, IPixel - => source.DrawText(TextGraphicsOptions.Default, text, font, brush, pen, path); + public static IImageProcessingContext DrawText( + this IImageProcessingContext source, + string text, + Font font, + IBrush brush, + IPen pen, + IPath path) + where TPixel : struct, IPixel => + source.DrawText(TextGraphicsOptions.Default, text, font, brush, pen, path); /// /// Draws the text onto the the image filled via the brush then outlined via the pen. @@ -146,8 +185,15 @@ namespace SixLabors.ImageSharp.Processing.Text /// /// The . /// - public static IImageProcessingContext DrawText(this IImageProcessingContext source, TextGraphicsOptions options, string text, Font font, IBrush brush, IPen pen, IPath path) - where TPixel : struct, IPixel - => source.ApplyProcessor(new DrawTextOnPathProcessor(options, text, font, brush, pen, path)); + public static IImageProcessingContext DrawText( + this IImageProcessingContext source, + TextGraphicsOptions options, + string text, + Font font, + IBrush brush, + IPen pen, + IPath path) + where TPixel : struct, IPixel => + source.ApplyProcessor(new DrawTextOnPathProcessor(options, text, font, brush, pen, path)); } } \ No newline at end of file From 8a14fa0ab7ab7656f4d4992d123dbcf7a7e94048 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 17 Jun 2018 16:21:50 +0200 Subject: [PATCH 39/63] add FontShapesAreRenderedCorrectlyAlongACirclePath() --- .../Drawing/Text/DrawTextOnImageTests.cs | 89 ++++++++++++++----- 1 file changed, 69 insertions(+), 20 deletions(-) diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs index a1a9b0222..6922213f2 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs @@ -150,8 +150,6 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text where TPixel : struct, IPixel { Font font = CreateFont(fontName, fontSize); - string fnDisplayText = text.Replace("\n", ""); - fnDisplayText = fnDisplayText.Substring(0, Math.Min(fnDisplayText.Length, 4)); TPixel color = NamedColors.Black; provider.VerifyOperation( @@ -160,15 +158,14 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text { img.Mutate(c => c.DrawText(text, new Font(font, fontSize), null, Pens.DashDot(color, 3), new PointF(x, y))); }, - $"pen_{fontName}-{fontSize}-{fnDisplayText}-({x},{y})", + $"pen_{fontName}-{fontSize}-{ToTestOutputDisplayText(text)}-({x},{y})", appendPixelTypeToFileName: false, appendSourceFileOrDescription: true); } - [Theory] [WithSolidFilledImages(200, 100, "White", PixelTypes.Rgba32, 50, "SixLaborsSampleAB.woff", AB)] - [WithSolidFilledImages(900, 100, "White", PixelTypes.Rgba32, 50, "OpenSans-Regular.ttf", TestText)] + [WithSolidFilledImages(900, 100, "White", PixelTypes.Rgba32, 50, "OpenSans-Regular.ttf", TestText)] public void FontShapesAreRenderedCorrectlyAlongAPath( TestImageProvider provider, int fontSize, @@ -176,36 +173,88 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text string text) where TPixel : struct, IPixel { - Font font = CreateFont(fontName, fontSize); - string fnDisplayText = text.Replace("\n", ""); - fnDisplayText = fnDisplayText.Substring(0, Math.Min(fnDisplayText.Length, 4)); - TPixel colorOutline = NamedColors.Black; TPixel colorFill = NamedColors.Gray; + TPixel colorOutline = NamedColors.Black; + IBrush fillBrush = Brushes.Solid(colorFill); + IPen outlinePen = Pens.DashDot(colorOutline, 3); + provider.VerifyOperation( + ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20), + img => + { + IPath path = new Path(new LinearLineSegment(new Point(0, img.Height), new Point(img.Width, 0))); + img.Mutate( + c => + { + c.DrawText( + new TextGraphicsOptions + { + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Top + }, + text, + new Font(font, fontSize), + fillBrush, + outlinePen, + path); + }); + }, + $"pen_{fontName}-{fontSize}-{ToTestOutputDisplayText(text)}", + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: true); + } + + [Theory] + [WithSolidFilledImages(600, 600, "White", PixelTypes.Rgba32, 50, "OpenSans-Regular.ttf", TestText)] + public void FontShapesAreRenderedCorrectlyAlongACirclePath( + TestImageProvider provider, + int fontSize, + string fontName, + string text) + where TPixel : struct, IPixel + { + + Font font = CreateFont(fontName, fontSize); + TPixel colorFill = NamedColors.Black; + IBrush fillBrush = Brushes.Solid(colorFill); + provider.VerifyOperation( ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20), img => { + int w = (int)(img.Width * 0.6); + int h = (int)(img.Height * 0.6); + IPath path = new EllipsePolygon(img.Width/2, img.Height/2, w, h); - IPath path = new Path(new LinearLineSegment(new Point(0, img.Height), new Point(img.Width, 0))); - img.Mutate(c => c.DrawText( - new TextGraphicsOptions { - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Top - } , - text, new Font(font, fontSize), - Brushes.Solid(colorFill) - , Pens.DashDot(colorOutline, 3), - path)); + img.Mutate(c => + { + c.DrawText( + new TextGraphicsOptions + { + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Top + }, + text, + new Font(font, fontSize), + fillBrush, + path); + }); }, - $"pen_{fontName}-{fontSize}-{fnDisplayText}", + $"pen_{fontName}-{fontSize}-{ToTestOutputDisplayText(text)}", appendPixelTypeToFileName: false, appendSourceFileOrDescription: true); } private static string Repeat(string str, int times) => string.Concat(Enumerable.Repeat(str, times)); + private static string ToTestOutputDisplayText(string text) + { + string fnDisplayText = text.Replace("\n", ""); + fnDisplayText = fnDisplayText.Substring(0, Math.Min(fnDisplayText.Length, 4)); + return fnDisplayText; + } + private static Font CreateFont(string fontName, int size) { var fontCollection = new FontCollection(); From ed1a70d0524fa45543e56532d896b3e4a1176f1e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 17 Jun 2018 16:28:52 +0200 Subject: [PATCH 40/63] update submodule, fine-tune test tolerance --- .../Drawing/Text/DrawTextOnImageTests.cs | 23 ++++++++----------- tests/Images/External | 2 +- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs index 6922213f2..ef6dc40f0 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs @@ -34,6 +34,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text private const string TestText2 = "THISISTESTWORDS "; + public static ImageComparer TextDrawingComparer = ImageComparer.TolerantPercentage(0.01f); + [Theory] [WithSolidFilledImages(200, 100, "White", PixelTypes.Rgba32, 50, 0, 0, "SixLaborsSampleAB.woff", AB)] [WithSolidFilledImages(900, 100, "White", PixelTypes.Rgba32, 50, 0, 0, "OpenSans-Regular.ttf", TestText)] @@ -49,17 +51,15 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text where TPixel : struct, IPixel { Font font = CreateFont(fontName, fontSize); - string fnDisplayText = text.Replace("\n", ""); - fnDisplayText = fnDisplayText.Substring(0, Math.Min(fnDisplayText.Length, 4)); TPixel color = NamedColors.Black; provider.VerifyOperation( - ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20), + TextDrawingComparer, img => { img.Mutate(c => c.DrawText(text, new Font(font, fontSize), color, new PointF(x, y))); }, - $"{fontName}-{fontSize}-{fnDisplayText}-({x},{y})", + $"{fontName}-{fontSize}-{ToTestOutputDisplayText(text)}-({x},{y})", appendPixelTypeToFileName: false, appendSourceFileOrDescription: true); } @@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text TPixel color = NamedColors.Black; provider.VerifyOperation( - ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20), + TextDrawingComparer, img => { img.Mutate(c => c.DrawText(textOptions, sb.ToString(), font, color, new PointF(10, 5))); @@ -121,17 +121,15 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text where TPixel : struct, IPixel { Font font = CreateFont(fontName, fontSize); - string fnDisplayText = text.Replace("\n", ""); - fnDisplayText = fnDisplayText.Substring(0, Math.Min(fnDisplayText.Length, 4)); TPixel color = NamedColors.Black; provider.VerifyOperation( - ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20), + TextDrawingComparer, img => { img.Mutate(c => c.DrawText(text, new Font(font, fontSize), null, Pens.Solid(color, 1), new PointF(x, y))); }, - $"pen_{fontName}-{fontSize}-{fnDisplayText}-({x},{y})", + $"pen_{fontName}-{fontSize}-{ToTestOutputDisplayText(text)}-({x},{y})", appendPixelTypeToFileName: false, appendSourceFileOrDescription: true); } @@ -153,7 +151,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text TPixel color = NamedColors.Black; provider.VerifyOperation( - ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20), + TextDrawingComparer, img => { img.Mutate(c => c.DrawText(text, new Font(font, fontSize), null, Pens.DashDot(color, 3), new PointF(x, y))); @@ -180,7 +178,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text IPen outlinePen = Pens.DashDot(colorOutline, 3); provider.VerifyOperation( - ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20), + TextDrawingComparer, img => { IPath path = new Path(new LinearLineSegment(new Point(0, img.Height), new Point(img.Width, 0))); @@ -214,13 +212,12 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text string text) where TPixel : struct, IPixel { - Font font = CreateFont(fontName, fontSize); TPixel colorFill = NamedColors.Black; IBrush fillBrush = Brushes.Solid(colorFill); provider.VerifyOperation( - ImageComparer.Tolerant(imageThreshold: 0.1f, perPixelManhattanThreshold: 20), + TextDrawingComparer, img => { int w = (int)(img.Width * 0.6); diff --git a/tests/Images/External b/tests/Images/External index 83f6cbab9..0e6407be7 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 83f6cbab9a08b550c84bf931c95188341140516a +Subproject commit 0e6407be7081341526f815a4d70e7912db276a98 From 38ba1f2dfc5c55e8f815e1d3c4bcbc44bdfecf73 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 17 Jun 2018 16:41:37 +0200 Subject: [PATCH 41/63] fix build after merge --- .../Processing/Text/Processors/DrawTextProcessor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs index d00cba8a3..0d534dc39 100644 --- a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors { foreach (DrawingOperation operation in operations) { - IBuffer2D buffer = operation.Map; + Buffer2D buffer = operation.Map; int startY = operation.Location.Y; int startX = operation.Location.X; int offSetSpan = 0; @@ -153,7 +153,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors private struct DrawingOperation { - public IBuffer2D Map { get; set; } + public Buffer2D Map { get; set; } public Point Location { get; set; } } From 36298f43e7b6c6f6cbb12fb06bda2a63e709144a Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 17 Jun 2018 16:48:06 +0200 Subject: [PATCH 42/63] fine tune tolerance --- .../Drawing/Text/DrawTextOnImageTests.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs index ef6dc40f0..abb384ffb 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs @@ -31,10 +31,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text private const string TestText = "Sphinx of black quartz, judge my vow\n0123456789"; - private const string TestText2 = - "THISISTESTWORDS "; - public static ImageComparer TextDrawingComparer = ImageComparer.TolerantPercentage(0.01f); + public static ImageComparer OutlinedTextDrawingComparer = ImageComparer.TolerantPercentage(0.5f, 3); [Theory] [WithSolidFilledImages(200, 100, "White", PixelTypes.Rgba32, 50, 0, 0, "SixLaborsSampleAB.woff", AB)] @@ -124,7 +122,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text TPixel color = NamedColors.Black; provider.VerifyOperation( - TextDrawingComparer, + OutlinedTextDrawingComparer, img => { img.Mutate(c => c.DrawText(text, new Font(font, fontSize), null, Pens.Solid(color, 1), new PointF(x, y))); @@ -151,7 +149,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text TPixel color = NamedColors.Black; provider.VerifyOperation( - TextDrawingComparer, + OutlinedTextDrawingComparer, img => { img.Mutate(c => c.DrawText(text, new Font(font, fontSize), null, Pens.DashDot(color, 3), new PointF(x, y))); @@ -178,7 +176,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text IPen outlinePen = Pens.DashDot(colorOutline, 3); provider.VerifyOperation( - TextDrawingComparer, + OutlinedTextDrawingComparer, img => { IPath path = new Path(new LinearLineSegment(new Point(0, img.Height), new Point(img.Width, 0))); From 717bf96d555858dac2cd1f0e64f53f70a25715ea Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 17 Jun 2018 21:07:53 +0100 Subject: [PATCH 43/63] drop resolved todo comment --- src/ImageSharp.Drawing/Primitives/ShapePath.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ImageSharp.Drawing/Primitives/ShapePath.cs b/src/ImageSharp.Drawing/Primitives/ShapePath.cs index 7aae2bf8e..7a8c9e895 100644 --- a/src/ImageSharp.Drawing/Primitives/ShapePath.cs +++ b/src/ImageSharp.Drawing/Primitives/ShapePath.cs @@ -16,7 +16,6 @@ namespace SixLabors.ImageSharp.Primitives /// /// The shape. /// The pen to apply to the shape. - // TODO: SixLabors.shape will be moving to a Span/ReadOnlySpan based API shortly use ToArray for now. public ShapePath(IPath shape, IPen pen) : base(shape.GenerateOutline(pen.StrokeWidth, pen.StrokePattern)) { From c13fb2cd1d8733430474a3829c1b8428bb2d9cd6 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 17 Jun 2018 21:11:37 +0100 Subject: [PATCH 44/63] make processors immutable again --- .../Drawing/Processors/FillRegionProcessor.cs | 19 +-- .../Text/Processors/DrawTextProcessor.cs | 35 +++-- .../OldProcessors/DrawTextProcessorV1.cs | 138 ------------------ 3 files changed, 27 insertions(+), 165 deletions(-) delete mode 100644 tests/ImageSharp.Benchmarks/Drawing/OldProcessors/DrawTextProcessorV1.cs diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs index 598e696ba..c81f4028b 100644 --- a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs @@ -37,29 +37,22 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors } /// - /// Initializes a new instance of the class. - /// - public FillRegionProcessor() - { - } - - /// - /// Gets or sets the brush. + /// Gets the brush. /// - public IBrush Brush { get; set; } + public IBrush Brush { get; } /// - /// Gets or sets the region that this processor applies to. + /// Gets the region that this processor applies to. /// - public Region Region { get; set; } + public Region Region { get; } /// - /// Gets or sets the options. + /// Gets the options. /// /// /// The options. /// - public GraphicsOptions Options { get; set; } + public GraphicsOptions Options { get; } /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) diff --git a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs index 0d534dc39..f6a66b566 100644 --- a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs @@ -39,43 +39,50 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors /// The location on the image to start drawign the text from. public DrawTextProcessor(TextGraphicsOptions options, string text, Font font, IBrush brush, IPen pen, PointF location) { - this.Brush = brush; + Guard.NotNull(text, nameof(text)); + Guard.NotNull(font, nameof(font)); + if (brush == null && pen == null) + { + throw new ArgumentNullException($"at least one of {nameof(brush)} or {nameof(pen)} must not be null"); + } + this.Options = options; this.Text = text; - this.Pen = pen; this.Font = font; this.Location = location; + this.Brush = brush; + this.Pen = pen; } /// - /// Gets or sets the brush. + /// Gets the brush. /// - public IBrush Brush { get; set; } + public IBrush Brush { get; } /// - /// Gets or sets the options + /// Gets the options /// - public TextGraphicsOptions Options { get; set; } + public TextGraphicsOptions Options { get; } /// - /// Gets or sets the text + /// Gets the text /// - public string Text { get; set; } + public string Text { get; } /// - /// Gets or sets the pen used for outlining the text, if Null then we will not outline + /// Gets the pen used for outlining the text, if Null then we will not outline /// - public IPen Pen { get; set; } + public IPen Pen { get; } /// - /// Gets or sets the font used to render the text. + /// Gets the font used to render the text. /// - public Font Font { get; set; } + public Font Font { get; } /// - /// Gets or sets the location to draw the text at. + /// Gets the location to draw the text at. /// - public PointF Location { get; set; } + public PointF Location { get; } protected override void BeforeImageApply(Image source, Rectangle sourceRectangle) { diff --git a/tests/ImageSharp.Benchmarks/Drawing/OldProcessors/DrawTextProcessorV1.cs b/tests/ImageSharp.Benchmarks/Drawing/OldProcessors/DrawTextProcessorV1.cs deleted file mode 100644 index 3faaec2c2..000000000 --- a/tests/ImageSharp.Benchmarks/Drawing/OldProcessors/DrawTextProcessorV1.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using SixLabors.Fonts; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Primitives; -using SixLabors.ImageSharp.Processing.Drawing.Brushes; -using SixLabors.ImageSharp.Processing.Drawing.Pens; -using SixLabors.ImageSharp.Processing.Drawing.Processors; -using SixLabors.ImageSharp.Processing.Processors; -using SixLabors.ImageSharp.Processing.Text; -using SixLabors.Primitives; -using SixLabors.Shapes; - -namespace SixLabors.ImageSharp.Benchmarks.Drawing.OldProcessors -{ - - /// - /// Using the brush as a source of pixels colors blends the brush color with source. - /// - /// The pixel format. - internal class DrawTextProcessor : ImageProcessor - where TPixel : struct, IPixel - { - private FillRegionProcessor fillRegionProcessor = null; - - /// - /// Initializes a new instance of the class. - /// - /// The options - /// The text we want to render - /// The font we want to render with - /// The brush to source pixel colors from. - /// The pen to outline text with. - /// The location on the image to start drawign the text from. - public DrawTextProcessor(TextGraphicsOptions options, string text, Font font, IBrush brush, IPen pen, PointF location) - { - this.Brush = brush; - this.Options = options; - this.Text = text; - this.Pen = pen; - this.Font = font; - this.Location = location; - } - - /// - /// Gets or sets the brush. - /// - public IBrush Brush { get; set; } - - /// - /// Gets or sets the options - /// - public TextGraphicsOptions Options { get; set; } - - /// - /// Gets or sets the text - /// - public string Text { get; set; } - - /// - /// Gets or sets the pen used for outlining the text, if Null then we will not outline - /// - public IPen Pen { get; set; } - - /// - /// Gets or sets the font used to render the text. - /// - public Font Font { get; set; } - - /// - /// Gets or sets the location to draw the text at. - /// - public PointF Location { get; set; } - - protected override void BeforeImageApply(Image source, Rectangle sourceRectangle) - { - base.BeforeImageApply(source, sourceRectangle); - - // do everythign at the image level as we are deligating the processing down to other processors - var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY, this.Location) - { - ApplyKerning = this.Options.ApplyKerning, - TabWidth = this.Options.TabWidth, - WrappingWidth = this.Options.WrapTextWidth, - HorizontalAlignment = this.Options.HorizontalAlignment, - VerticalAlignment = this.Options.VerticalAlignment - }; - - IPathCollection glyphs = TextBuilder.GenerateGlyphs(this.Text, style); - - var pathOptions = (GraphicsOptions)this.Options; - if (this.Brush != null) - { - // we will reuse the processor for all fill operations to reduce allocations - if (this.fillRegionProcessor == null) - { - this.fillRegionProcessor = new FillRegionProcessor() - { - Brush = this.Brush, - Options = pathOptions - }; - } - - foreach (IPath p in glyphs) - { - this.fillRegionProcessor.Region = new ShapeRegion(p); - this.fillRegionProcessor.Apply(source, sourceRectangle); - } - } - - if (this.Pen != null) - { - // we will reuse the processor for all fill operations to reduce allocations - if (this.fillRegionProcessor == null) - { - this.fillRegionProcessor = new FillRegionProcessor() - { - Brush = this.Brush, - Options = pathOptions - }; - } - - foreach (IPath p in glyphs) - { - this.fillRegionProcessor.Region = new ShapePath(p, this.Pen); - this.fillRegionProcessor.Apply(source, sourceRectangle); - } - } - } - - /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) - { - // this is a no-op as we have processes all as an image, we should be able to pass out of before email apply a skip frames outcome - } - } -} From 948ea7e80b5f588c0893834b4464e051b7db46a3 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 17 Jun 2018 21:13:47 +0100 Subject: [PATCH 45/63] remove draw text along path --- .../Text/DrawTextExtensions.Path.cs | 199 ------------------ .../Processors/DrawTextOnPathProcessor.cs | 123 ----------- .../Drawing/Text/DrawText.Path.cs | 179 ---------------- .../Drawing/Text/DrawTextOnImageTests.cs | 82 -------- 4 files changed, 583 deletions(-) delete mode 100644 src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.Path.cs delete mode 100644 src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextOnPathProcessor.cs delete mode 100644 tests/ImageSharp.Tests/Drawing/Text/DrawText.Path.cs diff --git a/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.Path.cs b/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.Path.cs deleted file mode 100644 index 827d6b95f..000000000 --- a/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.Path.cs +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using SixLabors.Fonts; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Drawing; -using SixLabors.ImageSharp.Processing.Drawing.Brushes; -using SixLabors.ImageSharp.Processing.Drawing.Pens; -using SixLabors.ImageSharp.Processing.Text.Processors; -using SixLabors.Shapes; - -namespace SixLabors.ImageSharp.Processing.Text -{ - /// - /// Adds extensions that allow the drawing of text along given paths to the type. - /// - public static partial class DrawTextExtensions - { - /// - /// Draws the text onto the the image filled via the brush. - /// - /// The type of the color. - /// The image this method extends. - /// The text. - /// The font. - /// The color. - /// The path. - /// - /// The . - /// - public static IImageProcessingContext DrawText( - this IImageProcessingContext source, - string text, - Font font, - TPixel color, - IPath path) - where TPixel : struct, IPixel => - source.DrawText(TextGraphicsOptions.Default, text, font, color, path); - - /// - /// Draws the text onto the the image filled via the brush. - /// - /// The type of the color. - /// The image this method extends. - /// The options. - /// The text. - /// The font. - /// The color. - /// The path. - /// - /// The . - /// - public static IImageProcessingContext DrawText( - this IImageProcessingContext source, - TextGraphicsOptions options, - string text, - Font font, - TPixel color, - IPath path) - where TPixel : struct, IPixel => - source.DrawText(options, text, font, Brushes.Solid(color), null, path); - - /// - /// Draws the text onto the the image filled via the brush. - /// - /// The type of the color. - /// The image this method extends. - /// The text. - /// The font. - /// The brush. - /// The location. - /// - /// The . - /// - public static IImageProcessingContext DrawText( - this IImageProcessingContext source, - string text, - Font font, - IBrush brush, - IPath path) - where TPixel : struct, IPixel => - source.DrawText(TextGraphicsOptions.Default, text, font, brush, path); - - /// - /// Draws the text onto the the image filled via the brush. - /// - /// The type of the color. - /// The image this method extends. - /// The options. - /// The text. - /// The font. - /// The brush. - /// The path. - /// - /// The . - /// - public static IImageProcessingContext DrawText( - this IImageProcessingContext source, - TextGraphicsOptions options, - string text, - Font font, - IBrush brush, - IPath path) - where TPixel : struct, IPixel => - source.DrawText(options, text, font, brush, null, path); - - /// - /// Draws the text onto the the image outlined via the pen. - /// - /// The type of the color. - /// The image this method extends. - /// The text. - /// The font. - /// The pen. - /// The path. - /// - /// The . - /// - public static IImageProcessingContext DrawText( - this IImageProcessingContext source, - string text, - Font font, - IPen pen, - IPath path) - where TPixel : struct, IPixel => - source.DrawText(TextGraphicsOptions.Default, text, font, pen, path); - - /// - /// Draws the text onto the the image outlined via the pen. - /// - /// The type of the color. - /// The image this method extends. - /// The options. - /// The text. - /// The font. - /// The pen. - /// The path. - /// - /// The . - /// - public static IImageProcessingContext DrawText( - this IImageProcessingContext source, - TextGraphicsOptions options, - string text, - Font font, - IPen pen, - IPath path) - where TPixel : struct, IPixel => - source.DrawText(options, text, font, null, pen, path); - - /// - /// Draws the text onto the the image filled via the brush then outlined via the pen. - /// - /// The type of the color. - /// The image this method extends. - /// The text. - /// The font. - /// The brush. - /// The pen. - /// The path. - /// - /// The . - /// - public static IImageProcessingContext DrawText( - this IImageProcessingContext source, - string text, - Font font, - IBrush brush, - IPen pen, - IPath path) - where TPixel : struct, IPixel => - source.DrawText(TextGraphicsOptions.Default, text, font, brush, pen, path); - - /// - /// Draws the text onto the the image filled via the brush then outlined via the pen. - /// - /// The type of the color. - /// The image this method extends. - /// The options. - /// The text. - /// The font. - /// The brush. - /// The pen. - /// The path. - /// - /// The . - /// - public static IImageProcessingContext DrawText( - this IImageProcessingContext source, - TextGraphicsOptions options, - string text, - Font font, - IBrush brush, - IPen pen, - IPath path) - where TPixel : struct, IPixel => - source.ApplyProcessor(new DrawTextOnPathProcessor(options, text, font, brush, pen, path)); - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextOnPathProcessor.cs b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextOnPathProcessor.cs deleted file mode 100644 index 1e703d1cc..000000000 --- a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextOnPathProcessor.cs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Threading.Tasks; -using SixLabors.Fonts; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Primitives; -using SixLabors.ImageSharp.Processing.Drawing.Brushes; -using SixLabors.ImageSharp.Processing.Drawing.Pens; -using SixLabors.ImageSharp.Processing.Drawing.Processors; -using SixLabors.ImageSharp.Processing.Processors; -using SixLabors.Primitives; -using SixLabors.Shapes; - -namespace SixLabors.ImageSharp.Processing.Text.Processors -{ - /// - /// Using the brush as a source of pixels colors blends the brush color with source. - /// - /// The pixel format. - internal class DrawTextOnPathProcessor : ImageProcessor - where TPixel : struct, IPixel - { - private FillRegionProcessor fillRegionProcessor = null; - - /// - /// Initializes a new instance of the class. - /// - /// The options - /// The text we want to render - /// The font we want to render with - /// The brush to source pixel colors from. - /// The pen to outline text with. - /// The path on which to draw the text along. - public DrawTextOnPathProcessor(TextGraphicsOptions options, string text, Font font, IBrush brush, IPen pen, IPath path) - { - this.Brush = brush; - this.Options = options; - this.Text = text; - this.Pen = pen; - this.Font = font; - this.Path = path; - } - - /// - /// Gets or sets the brush. - /// - public IBrush Brush { get; set; } - - /// - /// Gets or sets the options - /// - private TextGraphicsOptions Options { get; set; } - - /// - /// Gets or sets the text - /// - private string Text { get; set; } - - /// - /// Gets or sets the pen used for outlining the text, if Null then we will not outline - /// - public IPen Pen { get; set; } - - /// - /// Gets or sets the font used to render the text. - /// - public Font Font { get; set; } - - /// - /// Gets or sets the path to draw the text along. - /// - public IPath Path { get; set; } - - protected override void BeforeImageApply(Image source, Rectangle sourceRectangle) - { - base.BeforeImageApply(source, sourceRectangle); - - // do everythign at the image level as we are deligating the processing down to other processors - var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY) - { - ApplyKerning = this.Options.ApplyKerning, - TabWidth = this.Options.TabWidth, - WrappingWidth = this.Path.Length, - HorizontalAlignment = this.Options.HorizontalAlignment, - VerticalAlignment = this.Options.VerticalAlignment - }; - - IPathCollection glyphs = TextBuilder.GenerateGlyphs(this.Text, this.Path, style); - this.fillRegionProcessor = new FillRegionProcessor(); - this.fillRegionProcessor.Options = (GraphicsOptions)this.Options; - - if (this.Brush != null) - { - this.fillRegionProcessor.Brush = this.Brush; - - foreach (IPath p in glyphs) - { - this.fillRegionProcessor.Region = new ShapeRegion(p); - this.fillRegionProcessor.Apply(source, sourceRectangle); - } - } - - if (this.Pen != null) - { - this.fillRegionProcessor.Brush = this.Pen.StrokeFill; - - foreach (IPath p in glyphs) - { - this.fillRegionProcessor.Region = new ShapePath(p, this.Pen); - this.fillRegionProcessor.Apply(source, sourceRectangle); - } - } - } - - /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) - { - // this is a no-op as we have processes all as an image, we should be able to pass out of before email apply a skip frames outcome - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawText.Path.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawText.Path.cs deleted file mode 100644 index d352489b8..000000000 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawText.Path.cs +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using SixLabors.Fonts; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Drawing.Brushes; -using SixLabors.ImageSharp.Processing.Drawing.Pens; -using SixLabors.ImageSharp.Processing.Drawing.Processors; -using SixLabors.ImageSharp.Processing.Text; -using SixLabors.ImageSharp.Processing.Text.Processors; -using SixLabors.Shapes; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Drawing.Text -{ - public class DrawText_Path : BaseImageOperationsExtensionTest - { - Rgba32 color = Rgba32.HotPink; - - SolidBrush brush = Brushes.Solid(Rgba32.HotPink); - - IPath path = new SixLabors.Shapes.Path( - new LinearLineSegment( - new SixLabors.Primitives.PointF[] { new Vector2(10, 10), new Vector2(20, 10), new Vector2(20, 10), new Vector2(30, 10), })); - - private readonly FontCollection FontCollection; - - private readonly Font Font; - - public DrawText_Path() - { - this.FontCollection = new FontCollection(); - this.Font = this.FontCollection.Install(TestFontUtilities.GetPath("SixLaborsSampleAB.woff")).CreateFont(12); - } - - [Fact] - public void FillsForEachACharachterWhenBrushSetAndNotPen() - { - this.operations.DrawText( - new TextGraphicsOptions(true), - "123", - this.Font, - Brushes.Solid(Rgba32.Red), - null, - this.path); - - this.Verify>(0); - } - - [Fact] - public void FillsForEachACharachterWhenBrushSetAndNotPenDefaultOptions() - { - this.operations.DrawText("123", this.Font, Brushes.Solid(Rgba32.Red), null, this.path); - - this.Verify>(0); - } - - [Fact] - public void FillsForEachACharachterWhenBrushSet() - { - this.operations.DrawText(new TextGraphicsOptions(true), "123", this.Font, Brushes.Solid(Rgba32.Red), this.path); - - this.Verify>(0); - } - - [Fact] - public void FillsForEachACharachterWhenBrushSetDefaultOptions() - { - this.operations.DrawText("123", this.Font, Brushes.Solid(Rgba32.Red), this.path); - - this.Verify>(0); - } - - [Fact] - public void FillsForEachACharachterWhenColorSet() - { - this.operations.DrawText(new TextGraphicsOptions(true), "123", this.Font, Rgba32.Red, this.path); - - var processor = this.Verify>(0); - - SolidBrush brush = Assert.IsType>(processor.Brush); - Assert.Equal(Rgba32.Red, brush.Color); - } - - [Fact] - public void FillsForEachACharachterWhenColorSetDefaultOptions() - { - this.operations.DrawText("123", this.Font, Rgba32.Red, this.path); - - DrawTextOnPathProcessor processor = this.Verify>(0); - - SolidBrush brush = Assert.IsType>(processor.Brush); - Assert.Equal(Rgba32.Red, brush.Color); - } - - [Fact] - public void DrawForEachACharachterWhenPenSetAndNotBrush() - { - this.operations.DrawText( - new TextGraphicsOptions(true), - "123", - this.Font, - null, - Pens.Dash(Rgba32.Red, 1), - this.path); - - var processor = this.Verify>(0); - } - - [Fact] - public void DrawForEachACharachterWhenPenSetAndNotBrushDefaultOptions() - { - this.operations.DrawText("123", this.Font, null, Pens.Dash(Rgba32.Red, 1), this.path); - - var processor = this.Verify>(0); - } - - [Fact] - public void DrawForEachACharachterWhenPenSet() - { - this.operations.DrawText(new TextGraphicsOptions(true), "123", this.Font, Pens.Dash(Rgba32.Red, 1), this.path); - - var processor = this.Verify>(0); - } - - [Fact] - public void DrawForEachACharachterWhenPenSetDefaultOptions() - { - this.operations.DrawText("123", this.Font, Pens.Dash(Rgba32.Red, 1), this.path); - - DrawTextOnPathProcessor processor = this.Verify>(0); - } - - [Fact] - public void DrawForEachACharachterWhenPenSetAndFillFroEachWhenBrushSet() - { - this.operations.DrawText( - new TextGraphicsOptions(true), - "123", - this.Font, - Brushes.Solid(Rgba32.Red), - Pens.Dash(Rgba32.Red, 1), - this.path); - - var processor = this.Verify>(0); - } - - [Fact] - public void DrawForEachACharachterWhenPenSetAndFillFroEachWhenBrushSetDefaultOptions() - { - this.operations.DrawText("123", this.Font, Brushes.Solid(Rgba32.Red), Pens.Dash(Rgba32.Red, 1), this.path); - - var processor = this.Verify>(0); - } - - [Fact] - public void BrushAppliesBeforPen() - { - this.operations.DrawText( - new TextGraphicsOptions(true), - "1", - this.Font, - Brushes.Solid(Rgba32.Red), - Pens.Dash(Rgba32.Red, 1), - this.path); - - var processor = this.Verify>(0); - } - - [Fact] - public void BrushAppliesBeforPenDefaultOptions() - { - this.operations.DrawText("1", this.Font, Brushes.Solid(Rgba32.Red), Pens.Dash(Rgba32.Red, 1), this.path); - - var processor = this.Verify>(0); - } - } -} diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs index abb384ffb..3ceba0838 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs @@ -159,88 +159,6 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text appendSourceFileOrDescription: true); } - [Theory] - [WithSolidFilledImages(200, 100, "White", PixelTypes.Rgba32, 50, "SixLaborsSampleAB.woff", AB)] - [WithSolidFilledImages(900, 100, "White", PixelTypes.Rgba32, 50, "OpenSans-Regular.ttf", TestText)] - public void FontShapesAreRenderedCorrectlyAlongAPath( - TestImageProvider provider, - int fontSize, - string fontName, - string text) - where TPixel : struct, IPixel - { - Font font = CreateFont(fontName, fontSize); - TPixel colorFill = NamedColors.Gray; - TPixel colorOutline = NamedColors.Black; - IBrush fillBrush = Brushes.Solid(colorFill); - IPen outlinePen = Pens.DashDot(colorOutline, 3); - - provider.VerifyOperation( - OutlinedTextDrawingComparer, - img => - { - IPath path = new Path(new LinearLineSegment(new Point(0, img.Height), new Point(img.Width, 0))); - img.Mutate( - c => - { - c.DrawText( - new TextGraphicsOptions - { - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Top - }, - text, - new Font(font, fontSize), - fillBrush, - outlinePen, - path); - }); - }, - $"pen_{fontName}-{fontSize}-{ToTestOutputDisplayText(text)}", - appendPixelTypeToFileName: false, - appendSourceFileOrDescription: true); - } - - [Theory] - [WithSolidFilledImages(600, 600, "White", PixelTypes.Rgba32, 50, "OpenSans-Regular.ttf", TestText)] - public void FontShapesAreRenderedCorrectlyAlongACirclePath( - TestImageProvider provider, - int fontSize, - string fontName, - string text) - where TPixel : struct, IPixel - { - Font font = CreateFont(fontName, fontSize); - TPixel colorFill = NamedColors.Black; - IBrush fillBrush = Brushes.Solid(colorFill); - - provider.VerifyOperation( - TextDrawingComparer, - img => - { - int w = (int)(img.Width * 0.6); - int h = (int)(img.Height * 0.6); - IPath path = new EllipsePolygon(img.Width/2, img.Height/2, w, h); - - img.Mutate(c => - { - c.DrawText( - new TextGraphicsOptions - { - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Top - }, - text, - new Font(font, fontSize), - fillBrush, - path); - }); - }, - $"pen_{fontName}-{fontSize}-{ToTestOutputDisplayText(text)}", - appendPixelTypeToFileName: false, - appendSourceFileOrDescription: true); - } - private static string Repeat(string str, int times) => string.Concat(Enumerable.Repeat(str, times)); private static string ToTestOutputDisplayText(string text) From b270cbbc6d4e08d4e8d2b96630271f3da350af94 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Mon, 18 Jun 2018 19:28:44 +0100 Subject: [PATCH 46/63] drop the Shapes.Text dependency --- .../ImageSharp.Drawing.csproj | 3 ++- .../Text/Processors/DrawTextProcessor.cs | 24 +++++++++---------- .../ImageSharp.Benchmarks.csproj | 1 + 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index 3776830ae..661f33e08 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -39,7 +39,8 @@ - + + All diff --git a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs index f6a66b566..a38a0c320 100644 --- a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs @@ -169,13 +169,13 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors { private PathBuilder builder; - private Point currentRenderPosition = default(Point); - private int currentRenderingGlyph = 0; + private Point currentRenderPosition = default; + private GlyphRendererParameters currentRenderingGlyph = default; private int offset = 0; private PointF currentPoint = default(PointF); - private HashSet renderedGlyphs = new HashSet(); - private Dictionary> glyphMap; - private Dictionary> glyphMapPen; + private HashSet renderedGlyphs = new HashSet(); + private Dictionary> glyphMap; + private Dictionary> glyphMapPen; private bool renderOutline = false; private bool renderFill = false; private bool raterizationRequired = false; @@ -190,14 +190,14 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors if (this.renderFill) { this.FillOperations = new List(size); - this.glyphMap = new Dictionary>(); + this.glyphMap = new Dictionary>(); } if (this.renderOutline) { this.offset = (int)MathF.Ceiling((pen.StrokeWidth * 2) + 2); this.OutlineOperations = new List(size); - this.glyphMapPen = new Dictionary>(); + this.glyphMapPen = new Dictionary>(); } this.builder = new PathBuilder(); @@ -218,14 +218,14 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors this.builder.StartFigure(); } - public bool BeginGlyph(RectangleF bounds, int cacheKey) + public bool BeginGlyph(RectangleF bounds, GlyphRendererParameters paramters) { this.currentRenderPosition = Point.Truncate(bounds.Location); // we have offset our rendering origion a little bit down to prevent edge cropping, move the draw origin up to compensate this.currentRenderPosition = new Point(this.currentRenderPosition.X - this.offset, this.currentRenderPosition.Y - this.offset); - this.currentRenderingGlyph = cacheKey; - if (this.renderedGlyphs.Contains(cacheKey)) + this.currentRenderingGlyph = paramters; + if (this.renderedGlyphs.Contains(paramters)) { // we have already drawn the glyph vectors skip trying again this.raterizationRequired = false; @@ -259,7 +259,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors { if (this.renderFill) { - foreach (KeyValuePair> m in this.glyphMap) + foreach (KeyValuePair> m in this.glyphMap) { m.Value.Dispose(); } @@ -267,7 +267,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors if (this.renderOutline) { - foreach (KeyValuePair> m in this.glyphMapPen) + foreach (KeyValuePair> m in this.glyphMapPen) { m.Value.Dispose(); } diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 9a58f350a..67faa7213 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -18,6 +18,7 @@ + From ecf160e5bbde7d16fa8af8d29dc25ace5529dd9b Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 18 Jun 2018 23:28:54 +0200 Subject: [PATCH 47/63] refactor QuickSort to a common utility class --- .../Drawing/Processors/FillRegionProcessor.cs | 69 +-------------- .../Processing/Text/DrawTextExtensions.cs | 2 - .../Text/Processors/DrawTextProcessor.cs | 58 +------------ src/ImageSharp.Drawing/Utils/QuickSort.cs | 84 +++++++++++++++++++ .../ImageSharp.Tests/Drawing/BeziersTests.cs | 3 +- .../Drawing/Utils/QuickSortTests.cs | 51 +++++++++++ 6 files changed, 140 insertions(+), 127 deletions(-) create mode 100644 src/ImageSharp.Drawing/Utils/QuickSort.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Utils/QuickSortTests.cs diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs index c81f4028b..1e968b97e 100644 --- a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillRegionProcessor.cs @@ -2,11 +2,11 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Processing.Drawing.Brushes; using SixLabors.ImageSharp.Processing.Processors; +using SixLabors.ImageSharp.Utils; using SixLabors.Memory; using SixLabors.Primitives; @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors continue; } - QuickSort(buffer.Slice(0, pointsFound)); + QuickSort.Sort(buffer.Slice(0, pointsFound)); for (int point = 0; point < pointsFound; point += 2) { @@ -186,70 +186,5 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors } } } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void Swap(ref float left, ref float right) - { - float tmp = left; - left = right; - right = tmp; - } - - private static void QuickSort(Span data) - { - if (data.Length < 2) - { - return; - } - else if (data.Length == 2) - { - if (data[0] > data[1]) - { - Swap(ref data[0], ref data[1]); - } - - return; - } - - QuickSort(ref data[0], 0, data.Length - 1); - } - - private static void QuickSort(ref float data0, int lo, int hi) - { - if (lo < hi) - { - int p = Partition(ref data0, lo, hi); - QuickSort(ref data0, lo, p); - QuickSort(ref data0, p + 1, hi); - } - } - - private static int Partition(ref float data0, int lo, int hi) - { - float pivot = Unsafe.Add(ref data0, lo); - int i = lo - 1; - int j = hi + 1; - while (true) - { - do - { - i = i + 1; - } - while (Unsafe.Add(ref data0, i) < pivot && i < hi); - - do - { - j = j - 1; - } - while (Unsafe.Add(ref data0, j) > pivot && j > lo); - - if (i >= j) - { - return j; - } - - Swap(ref Unsafe.Add(ref data0, i), ref Unsafe.Add(ref data0, j)); - } - } } } \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.cs b/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.cs index ed7a7bbfa..a20d7f730 100644 --- a/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/Text/DrawTextExtensions.cs @@ -3,12 +3,10 @@ using SixLabors.Fonts; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Drawing; using SixLabors.ImageSharp.Processing.Drawing.Brushes; using SixLabors.ImageSharp.Processing.Drawing.Pens; using SixLabors.ImageSharp.Processing.Text.Processors; using SixLabors.Primitives; -using SixLabors.Shapes; namespace SixLabors.ImageSharp.Processing.Text { diff --git a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs index a38a0c320..f86bd827f 100644 --- a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs @@ -3,16 +3,13 @@ using System; using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; using SixLabors.Fonts; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Processing.Drawing.Brushes; using SixLabors.ImageSharp.Processing.Drawing.Pens; -using SixLabors.ImageSharp.Processing.Drawing.Processors; using SixLabors.ImageSharp.Processing.Processors; +using SixLabors.ImageSharp.Utils; using SixLabors.Memory; using SixLabors.Primitives; using SixLabors.Shapes; @@ -377,7 +374,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors buffer[i] = intersectionSpan[i].X; } - QuickSort(buffer.Slice(0, pointsFound)); + QuickSort.Sort(buffer.Slice(0, pointsFound)); for (int point = 0; point < pointsFound; point += 2) { @@ -439,57 +436,6 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors return fullBuffer; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void Swap(Span data, int left, int right) - { - float tmp = data[left]; - data[left] = data[right]; - data[right] = tmp; - } - - private static void QuickSort(Span data) - { - QuickSort(data, 0, data.Length - 1); - } - - private static void QuickSort(Span data, int lo, int hi) - { - if (lo < hi) - { - int p = Partition(data, lo, hi); - QuickSort(data, lo, p); - QuickSort(data, p + 1, hi); - } - } - - private static int Partition(Span data, int lo, int hi) - { - float pivot = data[lo]; - int i = lo - 1; - int j = hi + 1; - while (true) - { - do - { - i = i + 1; - } - while (data[i] < pivot && i < hi); - - do - { - j = j - 1; - } - while (data[j] > pivot && j > lo); - - if (i >= j) - { - return j; - } - - Swap(data, i, j); - } - } - public void EndText() { } diff --git a/src/ImageSharp.Drawing/Utils/QuickSort.cs b/src/ImageSharp.Drawing/Utils/QuickSort.cs new file mode 100644 index 000000000..ca1da5505 --- /dev/null +++ b/src/ImageSharp.Drawing/Utils/QuickSort.cs @@ -0,0 +1,84 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.Utils +{ + /// + /// Optimized quick sort implementation for Span{float} input + /// + internal class QuickSort + { + /// + /// Sorts the elements of in ascending order + /// + /// The items to sort + public static void Sort(Span data) + { + if (data.Length < 2) + { + return; + } + + if (data.Length == 2) + { + if (data[0] > data[1]) + { + Swap(ref data[0], ref data[1]); + } + + return; + } + + Sort(ref data[0], 0, data.Length - 1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Swap(ref float left, ref float right) + { + float tmp = left; + left = right; + right = tmp; + } + + private static void Sort(ref float data0, int lo, int hi) + { + if (lo < hi) + { + int p = Partition(ref data0, lo, hi); + Sort(ref data0, lo, p); + Sort(ref data0, p + 1, hi); + } + } + + private static int Partition(ref float data0, int lo, int hi) + { + float pivot = Unsafe.Add(ref data0, lo); + int i = lo - 1; + int j = hi + 1; + while (true) + { + do + { + i = i + 1; + } + while (Unsafe.Add(ref data0, i) < pivot && i < hi); + + do + { + j = j - 1; + } + while (Unsafe.Add(ref data0, j) > pivot && j > lo); + + if (i >= j) + { + return j; + } + + Swap(ref Unsafe.Add(ref data0, i), ref Unsafe.Add(ref data0, j)); + } + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/BeziersTests.cs b/tests/ImageSharp.Tests/Drawing/BeziersTests.cs index 6dc2fae89..a5fda7958 100644 --- a/tests/ImageSharp.Tests/Drawing/BeziersTests.cs +++ b/tests/ImageSharp.Tests/Drawing/BeziersTests.cs @@ -7,12 +7,11 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Drawing; using SixLabors.ImageSharp.Processing.Overlays; +using SixLabors.Memory; using Xunit; namespace SixLabors.ImageSharp.Tests.Drawing { - using SixLabors.Memory; - public class Beziers : FileTestBase { [Fact] diff --git a/tests/ImageSharp.Tests/Drawing/Utils/QuickSortTests.cs b/tests/ImageSharp.Tests/Drawing/Utils/QuickSortTests.cs new file mode 100644 index 000000000..6660cd87a --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Utils/QuickSortTests.cs @@ -0,0 +1,51 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Tests.Drawing.Utils +{ + using System; + using System.Linq; + + using SixLabors.ImageSharp.Utils; + + using Xunit; + + public class QuickSortTests + { + public static readonly TheoryData Data = new TheoryData() + { + new float[]{ 3, 2, 1 }, + new float[0], + new float[] { 42}, + new float[] { 1, 2}, + new float[] { 2, 1}, + new float[] { 5, 1, 2, 3, 0} + }; + + [Theory] + [MemberData(nameof(Data))] + public void Sort(float[] data) + { + float[] expected = data.ToArray(); + + Array.Sort(expected); + + QuickSort.Sort(data); + + Assert.Equal(expected, data); + } + + [Fact] + public void SortSlice() + { + float[] data = { 3, 2, 1, 0, -1 }; + + Span slice = data.AsSpan(1, 3); + QuickSort.Sort(slice); + float[] actual = slice.ToArray(); + float[] expected = { 0, 1, 2 }; + + Assert.Equal(actual, expected); + } + } +} \ No newline at end of file From bd65fc543cd38ea48afc508d4f60c6bc6df5ef56 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 18 Jun 2018 23:50:41 +0200 Subject: [PATCH 48/63] CachingGlyphRenderer: use a 1 dictionary instead of 3 --- .../Text/Processors/DrawTextProcessor.cs | 71 +++++++++++-------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs index f86bd827f..9327f9449 100644 --- a/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Text/Processors/DrawTextProcessor.cs @@ -167,19 +167,19 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors private PathBuilder builder; private Point currentRenderPosition = default; - private GlyphRendererParameters currentRenderingGlyph = default; + private GlyphRendererParameters currentGlyphRenderParams = default; private int offset = 0; private PointF currentPoint = default(PointF); - private HashSet renderedGlyphs = new HashSet(); - private Dictionary> glyphMap; - private Dictionary> glyphMapPen; + + private readonly Dictionary glyphData = new Dictionary(); + private bool renderOutline = false; private bool renderFill = false; private bool raterizationRequired = false; - public CachingGlyphRenderer(MemoryAllocator memoryManager, int size, IPen pen, bool renderFill) + public CachingGlyphRenderer(MemoryAllocator memoryAllocator, int size, IPen pen, bool renderFill) { - this.MemoryManager = memoryManager; + this.MemoryAllocator = memoryAllocator; this.Pen = pen; this.renderFill = renderFill; this.renderOutline = pen != null; @@ -187,14 +187,12 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors if (this.renderFill) { this.FillOperations = new List(size); - this.glyphMap = new Dictionary>(); } if (this.renderOutline) { this.offset = (int)MathF.Ceiling((pen.StrokeWidth * 2) + 2); this.OutlineOperations = new List(size); - this.glyphMapPen = new Dictionary>(); } this.builder = new PathBuilder(); @@ -204,7 +202,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors public List OutlineOperations { get; } - public MemoryAllocator MemoryManager { get; internal set; } + public MemoryAllocator MemoryAllocator { get; internal set; } public IPen Pen { get; internal set; } @@ -221,8 +219,8 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors // we have offset our rendering origion a little bit down to prevent edge cropping, move the draw origin up to compensate this.currentRenderPosition = new Point(this.currentRenderPosition.X - this.offset, this.currentRenderPosition.Y - this.offset); - this.currentRenderingGlyph = paramters; - if (this.renderedGlyphs.Contains(paramters)) + this.currentGlyphRenderParams = paramters; + if (this.glyphData.ContainsKey(paramters)) { // we have already drawn the glyph vectors skip trying again this.raterizationRequired = false; @@ -254,21 +252,12 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors public void Dispose() { - if (this.renderFill) + foreach (KeyValuePair kv in this.glyphData) { - foreach (KeyValuePair> m in this.glyphMap) - { - m.Value.Dispose(); - } + kv.Value.Dispose(); } - if (this.renderOutline) - { - foreach (KeyValuePair> m in this.glyphMapPen) - { - m.Value.Dispose(); - } - } + this.glyphData.Clear(); } public void EndFigure() @@ -278,13 +267,16 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors public void EndGlyph() { + GlyphRenderData renderData = default; + // has the glyoh been rendedered already???? if (this.raterizationRequired) { IPath path = this.builder.Build(); + if (this.renderFill) { - this.glyphMap[this.currentRenderingGlyph] = this.Render(path); + renderData.FillMap = this.Render(path); } if (this.renderOutline) @@ -298,10 +290,14 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors path = path.GenerateOutline(this.Pen.StrokeWidth, this.Pen.StrokePattern); } - this.glyphMapPen[this.currentRenderingGlyph] = this.Render(path); + renderData.OutlineMap = this.Render(path); } - this.renderedGlyphs.Add(this.currentRenderingGlyph); + this.glyphData[this.currentGlyphRenderParams] = renderData; + } + else + { + renderData = this.glyphData[this.currentGlyphRenderParams]; } if (this.renderFill) @@ -309,7 +305,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors this.FillOperations.Add(new DrawingOperation { Location = this.currentRenderPosition, - Map = this.glyphMap[this.currentRenderingGlyph] + Map = renderData.FillMap }); } @@ -318,7 +314,7 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors this.OutlineOperations.Add(new DrawingOperation { Location = this.currentRenderPosition, - Map = this.glyphMapPen[this.currentRenderingGlyph] + Map = renderData.OutlineMap }); } } @@ -341,10 +337,10 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors } // take the path inside the path builder, scan thing and generate a Buffer2d representing the glyph and cache it. - Buffer2D fullBuffer = this.MemoryManager.Allocate2D(size.Width + 1, size.Height + 1, true); + Buffer2D fullBuffer = this.MemoryAllocator.Allocate2D(size.Width + 1, size.Height + 1, true); - using (IBuffer bufferBacking = this.MemoryManager.Allocate(path.MaxIntersections)) - using (IBuffer rowIntersectionBuffer = this.MemoryManager.Allocate(size.Width)) + using (IBuffer bufferBacking = this.MemoryAllocator.Allocate(path.MaxIntersections)) + using (IBuffer rowIntersectionBuffer = this.MemoryAllocator.Allocate(size.Width)) { float subpixelFraction = 1f / subpixelCount; float subpixelFractionPoint = subpixelFraction / subpixelCount; @@ -457,6 +453,19 @@ namespace SixLabors.ImageSharp.Processing.Text.Processors this.builder.AddBezier(this.currentPoint, secondControlPoint, point); this.currentPoint = point; } + + private struct GlyphRenderData : IDisposable + { + public Buffer2D FillMap; + + public Buffer2D OutlineMap; + + public void Dispose() + { + this.FillMap?.Dispose(); + this.OutlineMap?.Dispose(); + } + } } } } \ No newline at end of file From 0eb76940dee88772bdad9788f06d1e61cef6beae Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 19 Jun 2018 07:58:11 -0700 Subject: [PATCH 49/63] Use non-preview appveyor image The main image was updated to 15.7.3 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 83ab8e4c7..3e6b79bfc 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,5 @@ version: 1.0.0.{build} -image: Visual Studio 2017 Preview +image: Visual Studio 2017 # prevent the double build when a branch has an active PR skip_branch_with_pr: true From e306f914be42083845b3464c0ce0c248a2e86599 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 19 Jun 2018 13:30:19 -0700 Subject: [PATCH 50/63] Fix merge conflict --- tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs index ea97dd76d..7c04d090b 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs @@ -7,7 +7,9 @@ using System.Text; using SixLabors.Fonts; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Drawing.Pens; using SixLabors.ImageSharp.Processing.Text; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.Primitives; using Xunit; From 85a16c0bf84a9c8e1fb01953b58c9a539db633c3 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 20 Jun 2018 01:25:00 +0200 Subject: [PATCH 51/63] Make sure that netcoreapp2.1 test execution is testing the netcoreapp2.1 build of ImageSharp --- src/ImageSharp/Common/Helpers/TestHelpers.cs | 24 +++++++++++++++++ .../TestUtilities/TestEnvironment.cs | 21 +++++++++++++++ .../Tests/TestEnvironmentTests.cs | 26 +++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 src/ImageSharp/Common/Helpers/TestHelpers.cs diff --git a/src/ImageSharp/Common/Helpers/TestHelpers.cs b/src/ImageSharp/Common/Helpers/TestHelpers.cs new file mode 100644 index 000000000..14e5835b4 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/TestHelpers.cs @@ -0,0 +1,24 @@ +// Copyright(c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Common.Helpers +{ + /// + /// Internal utilities intended to be only used in tests. + /// + internal static class TestHelpers + { + /// + /// This constant is useful to verify the target framework ImageSharp has been built against. + /// Only intended to be used in tests! + /// + internal const string ImageSharpBuiltAgainst = +#if NETSTANDARD1_1 + "netstandard1.1"; +#elif NETCOREAPP2_1 + "netcoreapp2.1"; +#else + "netstandard2.0"; +#endif + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs index 4cee650e8..e9f519aba 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs @@ -30,6 +30,13 @@ namespace SixLabors.ImageSharp.Tests return Boolean.TryParse(Environment.GetEnvironmentVariable("CI"), out isCi) && isCi; }); + private static readonly Lazy NetCoreVersionLazy = new Lazy(GetNetCoreVersion); + + /// + /// Gets the .NET Core version, if running on .NET Core, otherwise returns null. + /// + internal static string NetCoreVersion => NetCoreVersionLazy.Value; + // ReSharper disable once InconsistentNaming /// /// Gets a value indicating whether test execution runs on CI. @@ -123,5 +130,19 @@ namespace SixLabors.ImageSharp.Tests return path; } + + /// + /// Solution borrowed from: + /// https://github.com/dotnet/BenchmarkDotNet/issues/448#issuecomment-308424100 + /// + private static string GetNetCoreVersion() + { + Assembly assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly; + string[] assemblyPath = assembly.CodeBase.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries); + int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App"); + if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2) + return assemblyPath[netCoreAppIndex + 1]; + return ""; + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs index 9db55281e..4a2c63beb 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs @@ -4,6 +4,7 @@ using System; using System.IO; +using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Formats.Gif; @@ -13,9 +14,11 @@ using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; using Xunit; using Xunit.Abstractions; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests { + public class TestEnvironmentTests { public TestEnvironmentTests(ITestOutputHelper output) @@ -31,6 +34,29 @@ namespace SixLabors.ImageSharp.Tests Assert.True(Directory.Exists(path)); } + /// + /// We need this test to make sure that the netcoreapp2.1 test execution actually covers the netcoreapp2.1 build configuration of ImageSharp. + /// + [Fact] + public void ImageSharpAssemblyUnderTest_MatchesExpectedTargetFramework() + { + this.Output.WriteLine("NetCoreVersion: " + TestEnvironment.NetCoreVersion); + this.Output.WriteLine("ImageSharpBuiltAgainst: " + TestHelpers.ImageSharpBuiltAgainst); + + if (string.IsNullOrEmpty(TestEnvironment.NetCoreVersion)) + { + this.Output.WriteLine("Not running under .NET Core!"); + } + else if (TestEnvironment.NetCoreVersion.StartsWith("2.1")) + { + Assert.Equal("netcoreapp2.1", TestHelpers.ImageSharpBuiltAgainst); + } + else + { + Assert.Equal("netstandard2.0", TestHelpers.ImageSharpBuiltAgainst); + } + } + [Fact] public void SolutionDirectoryFullPath() { From c41fb827826e2d31417aecf986560e9775415867 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 20 Jun 2018 01:32:59 +0200 Subject: [PATCH 52/63] correct doc comment --- tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs index e9f519aba..b07a383b7 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Tests private static readonly Lazy NetCoreVersionLazy = new Lazy(GetNetCoreVersion); /// - /// Gets the .NET Core version, if running on .NET Core, otherwise returns null. + /// Gets the .NET Core version, if running on .NET Core, otherwise returns an empty string. /// internal static string NetCoreVersion => NetCoreVersionLazy.Value; From 7ae25f84f4c4de7bf22c82f4e48f4d3a77dc580a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 22 Jun 2018 21:40:37 +1000 Subject: [PATCH 53/63] Fix #624 --- .../Formats/Jpeg/GolangPort/GolangJpegDecoderCore.cs | 3 ++- .../Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs | 6 +----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoderCore.cs index 34a6e2f0f..61ab47bdf 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoderCore.cs @@ -338,6 +338,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort break; case JpegConstants.Markers.DHT: + if (metadataOnly) { this.InputProcessor.Skip(remaining); @@ -721,7 +722,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort { if (remaining < 17) { - throw new ImageFormatException("DHT has wrong length"); + throw new ImageFormatException($"DHT has wrong length. {remaining}"); } this.InputProcessor.ReadFull(this.Temp, 0, 17); diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs index 937439ed0..55435e3be 100644 --- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs @@ -270,6 +270,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort } case JpegConstants.Markers.DHT: + if (metadataOnly) { this.InputStream.Skip(remaining); @@ -698,11 +699,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort /// The remaining bytes in the segment block. private void ProcessDefineHuffmanTablesMarker(int remaining) { - if (remaining < 17) - { - throw new ImageFormatException($"DHT has wrong length: {remaining}"); - } - using (IManagedByteBuffer huffmanData = this.configuration.MemoryAllocator.AllocateCleanManagedByteBuffer(256)) { ref byte huffmanDataRef = ref MemoryMarshal.GetReference(huffmanData.GetSpan()); From 1811524d434b7a3b867fdaa869556e634496f40a Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 22 Jun 2018 16:36:24 -0700 Subject: [PATCH 54/63] Remove remaining null checks on structs --- .../Conversion/ColorSpaceConverter.Adapt.cs | 18 ------------- .../Conversion/ColorSpaceConverter.CieLab.cs | 8 ------ .../Conversion/ColorSpaceConverter.CieLch.cs | 2 -- .../Conversion/ColorSpaceConverter.CieXyy.cs | 26 ------------------ .../Conversion/ColorSpaceConverter.CieXyz.cs | 27 ------------------- .../Conversion/ColorSpaceConverter.Hsv.cs | 27 ------------------- .../ColorSpaceConverter.LinearRgb.cs | 2 -- 7 files changed, 110 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs index 80f9e6789..4bb537aeb 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -21,9 +20,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The adapted color public CieXyz Adapt(CieXyz color, CieXyz sourceWhitePoint) { - Guard.NotNull(color, nameof(color)); - Guard.NotNull(sourceWhitePoint, nameof(sourceWhitePoint)); - if (!this.IsChromaticAdaptationPerformed) { throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."); @@ -39,8 +35,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The adapted color public CieLab Adapt(CieLab color) { - Guard.NotNull(color, nameof(color)); - if (!this.IsChromaticAdaptationPerformed) { throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."); @@ -62,8 +56,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The adapted color public CieLch Adapt(CieLch color) { - Guard.NotNull(color, nameof(color)); - if (!this.IsChromaticAdaptationPerformed) { throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."); @@ -85,8 +77,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The adapted color public CieLchuv Adapt(CieLchuv color) { - Guard.NotNull(color, nameof(color)); - if (!this.IsChromaticAdaptationPerformed) { throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."); @@ -108,8 +98,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The adapted color public CieLuv Adapt(CieLuv color) { - Guard.NotNull(color, nameof(color)); - if (!this.IsChromaticAdaptationPerformed) { throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."); @@ -131,8 +119,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The adapted color public HunterLab Adapt(HunterLab color) { - Guard.NotNull(color, nameof(color)); - if (!this.IsChromaticAdaptationPerformed) { throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."); @@ -154,8 +140,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The adapted color public LinearRgb Adapt(LinearRgb color) { - Guard.NotNull(color, nameof(color)); - if (!this.IsChromaticAdaptationPerformed) { throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."); @@ -185,8 +169,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The adapted color public Rgb Adapt(Rgb color) { - Guard.NotNull(color, nameof(color)); - LinearRgb linearInput = this.ToLinearRgb(color); LinearRgb linearOutput = this.Adapt(linearInput); return this.ToRgb(linearOutput); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs index 3f5c2e246..16e3ec707 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs @@ -23,8 +23,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieLab ToCieLab(CieLch color) { - Guard.NotNull(color, nameof(color)); - // Conversion (perserving white point) CieLab unadapted = CieLchToCieLabConverter.Convert(color); @@ -77,8 +75,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieLab ToCieLab(CieXyz color) { - Guard.NotNull(color, nameof(color)); - // Adaptation CieXyz adapted = !this.WhitePoint.Equals(this.TargetLabWhitePoint) && this.IsChromaticAdaptationPerformed ? this.ChromaticAdaptation.Transform(color, this.WhitePoint, this.TargetLabWhitePoint) @@ -96,8 +92,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieLab ToCieLab(Cmyk color) { - Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); return this.ToCieLab(xyzColor); } @@ -120,8 +114,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieLab ToCieLab(Hsv color) { - Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); return this.ToCieLab(xyzColor); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs index 469875c02..b13580209 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs @@ -80,8 +80,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieLch ToCieLch(Cmyk color) { - Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); return this.ToCieLch(xyzColor); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs index 31e1e218e..5f6aaea6b 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs @@ -19,8 +19,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyy ToCieXyy(CieLab color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToCieXyy(xyzColor); @@ -33,8 +31,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyy ToCieXyy(CieLch color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToCieXyy(xyzColor); @@ -47,8 +43,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyy ToCieXyy(CieLchuv color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToCieXyy(xyzColor); @@ -61,8 +55,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyy ToCieXyy(CieLuv color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToCieXyy(xyzColor); @@ -75,8 +67,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyy ToCieXyy(CieXyz color) { - Guard.NotNull(color, nameof(color)); - return CieXyzAndCieXyyConverter.Convert(color); } @@ -87,8 +77,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyy ToCieXyy(Cmyk color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToCieXyy(xyzColor); @@ -101,8 +89,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyy ToCieXyy(Hsl color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToCieXyy(xyzColor); @@ -115,8 +101,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyy ToCieXyy(Hsv color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToCieXyy(xyzColor); @@ -129,8 +113,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyy ToCieXyy(HunterLab color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToCieXyy(xyzColor); @@ -143,8 +125,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyy ToCieXyy(LinearRgb color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToCieXyy(xyzColor); @@ -157,8 +137,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyy ToCieXyy(Lms color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToCieXyy(xyzColor); @@ -171,8 +149,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyy ToCieXyy(Rgb color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToCieXyy(xyzColor); @@ -185,8 +161,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyy ToCieXyy(YCbCr color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToCieXyy(xyzColor); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs index e6847beaf..cd3f7f3c8 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLabColorSapce; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLuvColorSapce; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HunterLabColorSapce; @@ -29,8 +28,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyz ToCieXyz(CieLab color) { - Guard.NotNull(color, nameof(color)); - // Conversion CieXyz unadapted = CieLabToCieXyzConverter.Convert(color); @@ -49,8 +46,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyz ToCieXyz(CieLch color) { - Guard.NotNull(color, nameof(color)); - // Conversion to Lab CieLab labColor = CieLchToCieLabConverter.Convert(color); @@ -65,8 +60,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyz ToCieXyz(CieLchuv color) { - Guard.NotNull(color, nameof(color)); - // Conversion to Luv CieLuv luvColor = CieLchuvToCieLuvConverter.Convert(color); @@ -81,8 +74,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyz ToCieXyz(CieLuv color) { - Guard.NotNull(color, nameof(color)); - // Conversion CieXyz unadapted = CieLuvToCieXyzConverter.Convert(color); @@ -101,8 +92,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyz ToCieXyz(CieXyy color) { - Guard.NotNull(color, nameof(color)); - // Conversion return CieXyzAndCieXyyConverter.Convert(color); } @@ -114,8 +103,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyz ToCieXyz(Cmyk color) { - Guard.NotNull(color, nameof(color)); - // Conversion var rgb = this.ToRgb(color); @@ -129,8 +116,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyz ToCieXyz(Hsl color) { - Guard.NotNull(color, nameof(color)); - // Conversion var rgb = this.ToRgb(color); @@ -144,8 +129,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyz ToCieXyz(Hsv color) { - Guard.NotNull(color, nameof(color)); - // Conversion var rgb = this.ToRgb(color); @@ -159,8 +142,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyz ToCieXyz(HunterLab color) { - Guard.NotNull(color, nameof(color)); - // Conversion CieXyz unadapted = HunterLabToCieXyzConverter.Convert(color); @@ -179,8 +160,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyz ToCieXyz(LinearRgb color) { - Guard.NotNull(color, nameof(color)); - // Conversion LinearRgbToCieXyzConverter converter = this.GetLinearRgbToCieXyzConverter(color.WorkingSpace); CieXyz unadapted = converter.Convert(color); @@ -198,8 +177,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyz ToCieXyz(Lms color) { - Guard.NotNull(color, nameof(color)); - // Conversion return this.cachedCieXyzAndLmsConverter.Convert(color); } @@ -211,8 +188,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyz ToCieXyz(Rgb color) { - Guard.NotNull(color, nameof(color)); - // Conversion LinearRgb linear = RgbToLinearRgbConverter.Convert(color); return this.ToCieXyz(linear); @@ -225,8 +200,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieXyz ToCieXyz(YCbCr color) { - Guard.NotNull(color, nameof(color)); - // Conversion var rgb = this.ToRgb(color); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs index 640461505..0aa644567 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HsvColorSapce; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -20,8 +19,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public Hsv ToHsv(CieLab color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToHsv(xyzColor); @@ -34,8 +31,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public Hsv ToHsv(CieLch color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToHsv(xyzColor); @@ -48,8 +43,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public Hsv ToHsv(CieLchuv color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToHsv(xyzColor); @@ -62,8 +55,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public Hsv ToHsv(CieLuv color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToHsv(xyzColor); @@ -76,8 +67,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public Hsv ToHsv(CieXyy color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToHsv(xyzColor); @@ -90,8 +79,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public Hsv ToHsv(CieXyz color) { - Guard.NotNull(color, nameof(color)); - var rgb = this.ToRgb(color); return HsvAndRgbConverter.Convert(rgb); @@ -104,8 +91,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public Hsv ToHsv(Cmyk color) { - Guard.NotNull(color, nameof(color)); - var rgb = this.ToRgb(color); return HsvAndRgbConverter.Convert(rgb); @@ -118,8 +103,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public Hsv ToHsv(Hsl color) { - Guard.NotNull(color, nameof(color)); - var rgb = this.ToRgb(color); return HsvAndRgbConverter.Convert(rgb); @@ -132,8 +115,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public Hsv ToHsv(HunterLab color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToHsv(xyzColor); @@ -146,8 +127,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public Hsv ToHsv(LinearRgb color) { - Guard.NotNull(color, nameof(color)); - var rgb = this.ToRgb(color); return HsvAndRgbConverter.Convert(rgb); @@ -160,8 +139,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public Hsv ToHsv(Lms color) { - Guard.NotNull(color, nameof(color)); - var xyzColor = this.ToCieXyz(color); return this.ToHsv(xyzColor); @@ -174,8 +151,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public Hsv ToHsv(Rgb color) { - Guard.NotNull(color, nameof(color)); - return HsvAndRgbConverter.Convert(color); } @@ -186,8 +161,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public Hsv ToHsv(YCbCr color) { - Guard.NotNull(color, nameof(color)); - var rgb = this.ToRgb(color); return HsvAndRgbConverter.Convert(rgb); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs index 91c78b3ea..92d2cd861 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs @@ -115,8 +115,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public LinearRgb ToLinearRgb(Hsv color) { - Guard.NotNull(color, nameof(color)); - var rgb = this.ToRgb(color); return this.ToLinearRgb(rgb); } From 7454d8aaae147b4c6bce3a5569eaad4ecd1d0086 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 22 Jun 2018 16:46:56 -0700 Subject: [PATCH 55/63] Prefer type names on left side --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 4 +- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 4 +- .../Formats/Jpeg/Components/Block8x8.cs | 2 +- .../Formats/Jpeg/Components/Block8x8F.cs | 6 +-- .../JpegColorConverter.FromYCbCrSimdAvx2.cs | 6 +-- .../GolangJpegScanDecoder.ComputationData.cs | 2 +- .../Jpeg/GolangPort/GolangJpegDecoderCore.cs | 2 +- .../Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs | 2 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 15 ++++--- src/ImageSharp/PixelFormats/Bgr24.cs | 2 +- .../PorterDuffFunctions.Generated.cs | 42 +++++++++---------- .../PorterDuffFunctions.Generated.tt | 2 +- src/ImageSharp/PixelFormats/Rgb24.cs | 2 +- .../BinaryErrorDiffusionProcessor.cs | 2 +- .../BinaryOrderedDitherProcessor.cs | 2 +- .../Processors/BinaryThresholdProcessor.cs | 2 +- .../Processors/Convolution2PassProcessor.cs | 2 +- .../ErrorDiffusionPaletteProcessor.cs | 2 +- .../OrderedDitherPaletteProcessor.cs | 2 +- .../Processors/PaletteDitherProcessorBase.cs | 4 +- .../OctreeFrameQuantizer{TPixel}.cs | 8 ++-- .../WuFrameQuantizer{TPixel}.cs | 4 +- 22 files changed, 59 insertions(+), 60 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 8a2ece4be..b4e5c094c 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -153,8 +153,8 @@ namespace SixLabors.ImageSharp { int width = bitmap.Width; int height = bitmap.Height; - var topLeft = default(Point); - var bottomRight = default(Point); + Point topLeft = default; + Point bottomRight = default; Func, int, int, float, bool> delegateFunc; diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 2ddf4ace4..20175613e 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -217,7 +217,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp private void ReadRle8(Buffer2D pixels, byte[] colors, int width, int height, bool inverted) where TPixel : struct, IPixel { - var color = default(TPixel); + TPixel color = default; var rgba = new Rgba32(0, 0, 0, 255); using (Buffer2D buffer = this.memoryAllocator.AllocateClean2D(width, height)) @@ -397,7 +397,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { int padding = CalculatePadding(width, 2); int stride = (width * 2) + padding; - var color = default(TPixel); + TPixel color = default; var rgba = new Rgba32(0, 0, 0, 255); using (IManagedByteBuffer buffer = this.memoryAllocator.AllocateManagedByteBuffer(stride)) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs index cb73ee947..5601a9436 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs @@ -184,7 +184,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// public Block8x8F AsFloatBlock() { - var result = default(Block8x8F); + Block8x8F result = default; result.LoadFrom(ref this); return result; } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index 38974cc76..59fc234c4 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -134,14 +134,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components public static Block8x8F Load(Span data) { - var result = default(Block8x8F); + Block8x8F result = default; result.LoadFrom(data); return result; } public static Block8x8F Load(Span data) { - var result = default(Block8x8F); + Block8x8F result = default; result.LoadFrom(data); return result; } @@ -461,7 +461,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components public Block8x8 RoundAsInt16Block() { - var result = default(Block8x8); + Block8x8 result = default; this.RoundInto(ref result); return result; } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs index c43713bf4..25342f4d6 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs @@ -62,9 +62,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // Walking 8 elements at one step: int n = result.Length / 8; - var rr = default(Vector4Pair); - var gg = default(Vector4Pair); - var bb = default(Vector4Pair); + Vector4Pair rr = default; + Vector4Pair gg = default; + Vector4Pair bb = default; ref Vector rrRefAsVector = ref Unsafe.As>(ref rr); ref Vector ggRefAsVector = ref Unsafe.As>(ref gg); diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.ComputationData.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.ComputationData.cs index f1dd2526a..f3c8aa91b 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.ComputationData.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/GolangJpegScanDecoder.ComputationData.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder /// The public static ComputationData Create() { - var data = default(ComputationData); + ComputationData data = default; data.Unzig = ZigZag.CreateUnzigTable(); return data; } diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoderCore.cs index 61ab47bdf..46cdcddb4 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/GolangJpegDecoderCore.cs @@ -773,7 +773,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort /// private void ProcessStartOfScanMarker(int remaining) { - var scan = default(GolangJpegScanDecoder); + GolangJpegScanDecoder scan = default; GolangJpegScanDecoder.InitStreamReading(&scan, this, remaining); this.InputProcessor.Bits = default; scan.DecodeBlocks(this); diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs index 55435e3be..bd1d84ecc 100644 --- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs @@ -786,7 +786,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort int spectralStart = this.temp[0]; int spectralEnd = this.temp[1]; int successiveApproximation = this.temp[2]; - var scanDecoder = default(PdfJsScanDecoder); + PdfJsScanDecoder scanDecoder = default; scanDecoder.DecodeScan( this.Frame, diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 67e32f212..363d51ef9 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -670,7 +670,7 @@ namespace SixLabors.ImageSharp.Formats.Png private void ProcessDefilteredScanline(ReadOnlySpan defilteredScanline, ImageFrame pixels) where TPixel : struct, IPixel { - var color = default(TPixel); + TPixel color = default; Span rowSpan = pixels.GetPixelRowSpan(this.currentRow); // Trim the first marker byte from the buffer @@ -753,7 +753,7 @@ namespace SixLabors.ImageSharp.Formats.Png for (int x = 0; x < this.header.Width; x++) { ref Rgb24 rgb24 = ref rgb24Span[x]; - var rgba32 = default(Rgba32); + Rgba32 rgba32 = default; rgba32.Rgb = rgb24; rgba32.A = (byte)(rgb24.Equals(this.rgb24Trans) ? 0 : 255); @@ -768,7 +768,7 @@ namespace SixLabors.ImageSharp.Formats.Png for (int x = 0; x < this.header.Width; x++) { ref readonly Rgb24 rgb24 = ref rgb24Span[x]; - var rgba32 = default(Rgba32); + Rgba32 rgba32 = default; rgba32.Rgb = rgb24; rgba32.A = (byte)(rgb24.Equals(this.rgb24Trans) ? 0 : 255); @@ -854,9 +854,8 @@ namespace SixLabors.ImageSharp.Formats.Png { ReadOnlySpan newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth); ReadOnlySpan pal = MemoryMarshal.Cast(this.palette); - var color = default(TPixel); - - var rgba = default(Rgba32); + TPixel color = default; + Rgba32 rgba = default; if (this.paletteAlpha != null && this.paletteAlpha.Length > 0) { @@ -900,7 +899,7 @@ namespace SixLabors.ImageSharp.Formats.Png private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defilteredScanline, Span rowSpan, int pixelOffset = 0, int increment = 1) where TPixel : struct, IPixel { - var color = default(TPixel); + TPixel color = default; // Trim the first marker byte from the buffer ReadOnlySpan scanlineBuffer = defilteredScanline.Slice(1, defilteredScanline.Length - 1); @@ -943,7 +942,7 @@ namespace SixLabors.ImageSharp.Formats.Png case PngColorType.Palette: ReadOnlySpan newScanline = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); - var rgba = default(Rgba32); + Rgba32 rgba = default; Span pal = MemoryMarshal.Cast(this.palette); if (this.paletteAlpha != null && this.paletteAlpha.Length > 0) diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs index b099bab1c..ff913923e 100644 --- a/src/ImageSharp/PixelFormats/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/Bgr24.cs @@ -121,7 +121,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromVector4(Vector4 vector) { - var rgba = default(Rgba32); + Rgba32 rgba = default; rgba.PackFromVector4(vector); this.PackFromRgba32(rgba); } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs index e948c05ca..66cc427de 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs @@ -261,7 +261,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel Normal(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(Normal(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -270,7 +270,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel Multiply(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(Multiply(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -279,7 +279,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel Add(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(Add(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -288,7 +288,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel Subtract(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(Subtract(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -297,7 +297,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel Screen(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(Screen(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -306,7 +306,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel Darken(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(Darken(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -315,7 +315,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel Lighten(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(Lighten(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -324,7 +324,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel Overlay(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(Overlay(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -333,7 +333,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel HardLight(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(HardLight(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -342,7 +342,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel Src(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(Src(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -351,7 +351,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel Atop(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(Atop(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -360,7 +360,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel Over(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(Over(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -369,7 +369,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel In(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(In(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -378,7 +378,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel Out(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(Out(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -387,7 +387,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel Dest(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(Dest(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -396,7 +396,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel DestAtop(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(DestAtop(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -405,7 +405,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel DestOver(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(DestOver(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -414,7 +414,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel DestIn(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(DestIn(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -423,7 +423,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel DestOut(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(DestOut(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -432,7 +432,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel Clear(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(Clear(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } @@ -441,7 +441,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel Xor(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(Xor(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt index 940b585aa..4cbc06861 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel <#=blender#>(TPixel backdrop, TPixel source, float amount) where TPixel : struct, IPixel { - TPixel dest = default(TPixel); + TPixel dest = default; dest.PackFromVector4(<#=blender#>(backdrop.ToVector4(), source.ToVector4(), amount)); return dest; } diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/Rgb24.cs index c540a7d12..faee3bbbd 100644 --- a/src/ImageSharp/PixelFormats/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/Rgb24.cs @@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromVector4(Vector4 vector) { - var rgba = default(Rgba32); + Rgba32 rgba = default; rgba.PackFromVector4(vector); this.PackFromRgba32(rgba); } diff --git a/src/ImageSharp/Processing/Binarization/Processors/BinaryErrorDiffusionProcessor.cs b/src/ImageSharp/Processing/Binarization/Processors/BinaryErrorDiffusionProcessor.cs index 6588bbe5b..64763b657 100644 --- a/src/ImageSharp/Processing/Binarization/Processors/BinaryErrorDiffusionProcessor.cs +++ b/src/ImageSharp/Processing/Binarization/Processors/BinaryErrorDiffusionProcessor.cs @@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Processing.Binarization.Processors protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { float threshold = this.Threshold * 255F; - var rgba = default(Rgba32); + Rgba32 rgba = default; bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); diff --git a/src/ImageSharp/Processing/Binarization/Processors/BinaryOrderedDitherProcessor.cs b/src/ImageSharp/Processing/Binarization/Processors/BinaryOrderedDitherProcessor.cs index bd4b3660a..3fe56ff44 100644 --- a/src/ImageSharp/Processing/Binarization/Processors/BinaryOrderedDitherProcessor.cs +++ b/src/ImageSharp/Processing/Binarization/Processors/BinaryOrderedDitherProcessor.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Processing.Binarization.Processors /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - var rgba = default(Rgba32); + Rgba32 rgba = default; bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); diff --git a/src/ImageSharp/Processing/Binarization/Processors/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Binarization/Processors/BinaryThresholdProcessor.cs index 455c6ad8c..dc1297d6f 100644 --- a/src/ImageSharp/Processing/Binarization/Processors/BinaryThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Binarization/Processors/BinaryThresholdProcessor.cs @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Processing.Binarization.Processors y => { Span row = source.GetPixelRowSpan(y); - var rgba = default(Rgba32); + Rgba32 rgba = default; for (int x = startX; x < endX; x++) { diff --git a/src/ImageSharp/Processing/Convolution/Processors/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Convolution/Processors/Convolution2PassProcessor.cs index a080beb88..4e14882ff 100644 --- a/src/ImageSharp/Processing/Convolution/Processors/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Convolution/Processors/Convolution2PassProcessor.cs @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.Processing.Convolution.Processors for (int x = startX; x < endX; x++) { - var destination = default(Vector4); + Vector4 destination = default; // Apply each matrix multiplier to the color components for each pixel. for (int fy = 0; fy < kernelHeight; fy++) diff --git a/src/ImageSharp/Processing/Dithering/Processors/ErrorDiffusionPaletteProcessor.cs b/src/ImageSharp/Processing/Dithering/Processors/ErrorDiffusionPaletteProcessor.cs index c90e91a6b..0f9e2d397 100644 --- a/src/ImageSharp/Processing/Dithering/Processors/ErrorDiffusionPaletteProcessor.cs +++ b/src/ImageSharp/Processing/Dithering/Processors/ErrorDiffusionPaletteProcessor.cs @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Processing.Dithering.Processors protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { float threshold = this.Threshold * 255F; - var rgba = default(Rgba32); + Rgba32 rgba = default; bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); diff --git a/src/ImageSharp/Processing/Dithering/Processors/OrderedDitherPaletteProcessor.cs b/src/ImageSharp/Processing/Dithering/Processors/OrderedDitherPaletteProcessor.cs index ce9b7fb3e..a59826e23 100644 --- a/src/ImageSharp/Processing/Dithering/Processors/OrderedDitherPaletteProcessor.cs +++ b/src/ImageSharp/Processing/Dithering/Processors/OrderedDitherPaletteProcessor.cs @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Processing.Dithering.Processors /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - var rgba = default(Rgba32); + Rgba32 rgba = default; bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); diff --git a/src/ImageSharp/Processing/Dithering/Processors/PaletteDitherProcessorBase.cs b/src/ImageSharp/Processing/Dithering/Processors/PaletteDitherProcessorBase.cs index 89cc7cfb6..683ef7044 100644 --- a/src/ImageSharp/Processing/Dithering/Processors/PaletteDitherProcessorBase.cs +++ b/src/ImageSharp/Processing/Dithering/Processors/PaletteDitherProcessorBase.cs @@ -46,8 +46,8 @@ namespace SixLabors.ImageSharp.Processing.Dithering.Processors float secondLeastDistance = int.MaxValue; var vector = pixel.ToVector4(); - var closest = default(TPixel); - var secondClosest = default(TPixel); + TPixel closest = default; + TPixel secondClosest = default; for (int index = 0; index < colorPalette.Length; index++) { TPixel temp = colorPalette[index]; diff --git a/src/ImageSharp/Processing/Quantization/FrameQuantizers/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Quantization/FrameQuantizers/OctreeFrameQuantizer{TPixel}.cs index 431064f22..e32022254 100644 --- a/src/ImageSharp/Processing/Quantization/FrameQuantizers/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Quantization/FrameQuantizers/OctreeFrameQuantizer{TPixel}.cs @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers ref TPixel scanBaseRef = ref MemoryMarshal.GetReference(row); // And loop through each column - var rgba = default(Rgba32); + Rgba32 rgba = default; for (int x = 0; x < width; x++) { ref TPixel pixel = ref Unsafe.Add(ref scanBaseRef, x); @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers // pass of the algorithm by avoiding transforming rows of identical color. TPixel sourcePixel = source[0, 0]; TPixel previousPixel = sourcePixel; - var rgba = default(Rgba32); + Rgba32 rgba = default; byte pixelValue = this.QuantizePixel(sourcePixel, ref rgba); TPixel[] colorPalette = this.GetPalette(); TPixel transformedPixel = colorPalette[pixelValue]; @@ -152,7 +152,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers { // Transparent pixels are much more likely to be found at the end of a palette int index = this.colors; - var trans = default(Rgba32); + Rgba32 trans = default; for (int i = this.palette.Length - 1; i >= 0; i--) { this.palette[i].ToRgba32(ref trans); @@ -539,7 +539,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers byte b = (this.blue / this.pixelCount).ToByte(); // And set the color of the palette entry - var pixel = default(TPixel); + TPixel pixel = default; pixel.PackFromRgba32(new Rgba32(r, g, b, 255)); palette[index] = pixel; diff --git a/src/ImageSharp/Processing/Quantization/FrameQuantizers/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Quantization/FrameQuantizers/WuFrameQuantizer{TPixel}.cs index 4887519e3..78c4bfbf8 100644 --- a/src/ImageSharp/Processing/Quantization/FrameQuantizers/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Quantization/FrameQuantizers/WuFrameQuantizer{TPixel}.cs @@ -237,7 +237,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers ref TPixel scanBaseRef = ref MemoryMarshal.GetReference(row); // And loop through each column - var rgba = default(Rgba32); + Rgba32 rgba = default; for (int x = 0; x < width; x++) { ref TPixel pixel = ref Unsafe.Add(ref scanBaseRef, x); @@ -858,7 +858,7 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers } // Expected order r->g->b->a - var rgba = default(Rgba32); + Rgba32 rgba = default; pixel.ToRgba32(ref rgba); int r = rgba.R >> (8 - IndexBits); From 90b494a3042b8ac5e31a3e85a49a94dd98508f1f Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 22 Jun 2018 16:48:09 -0700 Subject: [PATCH 56/63] Use ternary operator --- .../Formats/Bmp/BmpImageFormatDetector.cs | 7 +----- src/ImageSharp/Formats/ImageFormatManager.cs | 23 ++++++++----------- .../ColorConverters/JpegColorConverter.cs | 2 +- .../Formats/Png/PngImageFormatDetector.cs | 7 +----- src/ImageSharp/Image.Decode.cs | 8 +++---- 5 files changed, 15 insertions(+), 32 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs index 9c9786e0a..bb884019b 100644 --- a/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs @@ -16,12 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// public IImageFormat DetectFormat(ReadOnlySpan header) { - if (this.IsSupportedFileFormat(header)) - { - return ImageFormats.Bmp; - } - - return null; + return this.IsSupportedFileFormat(header) ? ImageFormats.Bmp : null; } private bool IsSupportedFileFormat(ReadOnlySpan header) diff --git a/src/ImageSharp/Formats/ImageFormatManager.cs b/src/ImageSharp/Formats/ImageFormatManager.cs index 4e33a0445..63fd02d8d 100644 --- a/src/ImageSharp/Formats/ImageFormatManager.cs +++ b/src/ImageSharp/Formats/ImageFormatManager.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; -using System.Text; namespace SixLabors.ImageSharp.Formats { @@ -87,9 +86,9 @@ namespace SixLabors.ImageSharp.Formats { Guard.NotNullOrWhiteSpace(extension, nameof(extension)); - if (extension[0] == '.') - { - extension = extension.Substring(1); + if (extension[0] == '.') + { + extension = extension.Substring(1); } return this.imageFormats.FirstOrDefault(x => x.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)); @@ -158,12 +157,10 @@ namespace SixLabors.ImageSharp.Formats public IImageDecoder FindDecoder(IImageFormat format) { Guard.NotNull(format, nameof(format)); - if (this.mimeTypeDecoders.TryGetValue(format, out IImageDecoder decoder)) - { - return decoder; - } - return null; + return this.mimeTypeDecoders.TryGetValue(format, out IImageDecoder decoder) + ? decoder + : null; } /// @@ -174,12 +171,10 @@ namespace SixLabors.ImageSharp.Formats public IImageEncoder FindEncoder(IImageFormat format) { Guard.NotNull(format, nameof(format)); - if (this.mimeTypeEncoders.TryGetValue(format, out IImageEncoder encoder)) - { - return encoder; - } - return null; + return this.mimeTypeEncoders.TryGetValue(format, out IImageEncoder encoder) + ? encoder + : null; } /// diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs index 5105e57ab..2937b23a7 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters /// Returns the for the YCbCr colorspace that matches the current CPU architecture. /// private static JpegColorConverter GetYCbCrConverter() => - JpegColorConverter.FromYCbCrSimdAvx2.IsAvailable ? (JpegColorConverter)new JpegColorConverter.FromYCbCrSimdAvx2() : new JpegColorConverter.FromYCbCrSimd(); + FromYCbCrSimdAvx2.IsAvailable ? (JpegColorConverter)new FromYCbCrSimdAvx2() : new FromYCbCrSimd(); /// /// A stack-only struct to reference the input buffers using -s. diff --git a/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs index 36b43a470..c1c039a1b 100644 --- a/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs @@ -17,12 +17,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// public IImageFormat DetectFormat(ReadOnlySpan header) { - if (this.IsSupportedFileFormat(header)) - { - return ImageFormats.Png; - } - - return null; + return this.IsSupportedFileFormat(header) ? ImageFormats.Png : null; } private bool IsSupportedFileFormat(ReadOnlySpan header) diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs index 443ae6a37..9087db414 100644 --- a/src/ImageSharp/Image.Decode.cs +++ b/src/ImageSharp/Image.Decode.cs @@ -48,12 +48,10 @@ namespace SixLabors.ImageSharp private static IImageDecoder DiscoverDecoder(Stream stream, Configuration config, out IImageFormat format) { format = InternalDetectFormat(stream, config); - if (format != null) - { - return config.ImageFormatsManager.FindDecoder(format); - } - return null; + return format != null + ? config.ImageFormatsManager.FindDecoder(format) + : null; } #pragma warning disable SA1008 // Opening parenthesis must be spaced correctly From 7d6cc4ffcb54bd54b3abdd0faa0cf74fef474e08 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 22 Jun 2018 16:48:22 -0700 Subject: [PATCH 57/63] Make TransformHelpers static --- src/ImageSharp/Processing/Transforms/TransformHelpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Processing/Transforms/TransformHelpers.cs b/src/ImageSharp/Processing/Transforms/TransformHelpers.cs index 46dd134ce..71d3b35c1 100644 --- a/src/ImageSharp/Processing/Transforms/TransformHelpers.cs +++ b/src/ImageSharp/Processing/Transforms/TransformHelpers.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms /// /// Contains helper methods for working with affine and non-affine transforms /// - internal class TransformHelpers + internal static class TransformHelpers { /// /// Updates the dimensional metadata of a transformed image From 912eb6ace51407f5ed5df9f9cec962bc49de57d1 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 22 Jun 2018 16:48:45 -0700 Subject: [PATCH 58/63] Use span copy --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 7ec82c57c..cf869e68a 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -247,7 +247,7 @@ namespace SixLabors.ImageSharp.Formats.Png where TPixel : struct, IPixel { byte[] rawScanlineArray = this.rawScanline.Array; - var rgba = default(Rgba32); + Rgba32 rgba = default; // Copy the pixels across from the image. // Reuse the chunk type buffer. @@ -305,8 +305,9 @@ namespace SixLabors.ImageSharp.Formats.Png switch (this.pngColorType) { case PngColorType.Palette: - // TODO: Use Span copy! - Buffer.BlockCopy(this.palettePixelData, row * this.rawScanline.Length(), this.rawScanline.Array, 0, this.rawScanline.Length()); + int stride = this.rawScanline.Length(); + + this.palettePixelData.AsSpan(row * stride, stride).CopyTo(this.rawScanline.GetSpan()); break; case PngColorType.Grayscale: case PngColorType.GrayscaleWithAlpha: From 86407f58773e149ea3e7a1d9ac5eef7b014e942e Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 22 Jun 2018 16:49:09 -0700 Subject: [PATCH 59/63] Avoid HuffmanSpec copies --- src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 9ffd40c93..1310d90d2 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -544,15 +544,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg specs = new[] { HuffmanSpec.TheHuffmanSpecs[0], HuffmanSpec.TheHuffmanSpecs[1] }; } - foreach (HuffmanSpec s in specs) + for (int i = 0; i < specs.Length; i++) { + ref HuffmanSpec s = ref specs[i]; markerlen += 1 + 16 + s.Values.Length; } this.WriteMarkerHeader(JpegConstants.Markers.DHT, markerlen); for (int i = 0; i < specs.Length; i++) { - HuffmanSpec spec = specs[i]; + ref HuffmanSpec spec = ref specs[i]; int len = 0; fixed (byte* huffman = this.huffmanBuffer) From b08e9eec507c44ddd09412966f21dd0abd16c2dc Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 22 Jun 2018 16:49:26 -0700 Subject: [PATCH 60/63] Change IsProfile to use ReadOnlySpan --- .../Formats/Jpeg/Components/Decoder/ProfileResolver.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs index e5de4441c..8273f20ea 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// The bytes to check /// The profile identifier /// The - public static bool IsProfile(Span bytesToCheck, Span profileIdentifier) + public static bool IsProfile(ReadOnlySpan bytesToCheck, ReadOnlySpan profileIdentifier) { return bytesToCheck.Length >= profileIdentifier.Length && bytesToCheck.Slice(0, profileIdentifier.Length).SequenceEqual(profileIdentifier); From 16edc8fcc6d9f962b6a0ff976b36ea58b00f3738 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 22 Jun 2018 16:49:42 -0700 Subject: [PATCH 61/63] Remove unused using statements --- src/ImageSharp/Formats/IImageEncoder.cs | 2 -- src/ImageSharp/Formats/IImageFormatDetector.cs | 2 -- src/ImageSharp/MetaData/ImageFrameMetaData.cs | 1 - 3 files changed, 5 deletions(-) diff --git a/src/ImageSharp/Formats/IImageEncoder.cs b/src/ImageSharp/Formats/IImageEncoder.cs index ac0b6e311..76d831d5a 100644 --- a/src/ImageSharp/Formats/IImageEncoder.cs +++ b/src/ImageSharp/Formats/IImageEncoder.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Collections.Generic; using System.IO; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Formats/IImageFormatDetector.cs b/src/ImageSharp/Formats/IImageFormatDetector.cs index 8266439bd..da3730d20 100644 --- a/src/ImageSharp/Formats/IImageFormatDetector.cs +++ b/src/ImageSharp/Formats/IImageFormatDetector.cs @@ -2,8 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Collections.Generic; -using System.Text; namespace SixLabors.ImageSharp.Formats { diff --git a/src/ImageSharp/MetaData/ImageFrameMetaData.cs b/src/ImageSharp/MetaData/ImageFrameMetaData.cs index ca3012f4a..d507a5b3e 100644 --- a/src/ImageSharp/MetaData/ImageFrameMetaData.cs +++ b/src/ImageSharp/MetaData/ImageFrameMetaData.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Gif; namespace SixLabors.ImageSharp.MetaData From b08dd4dc9ea847919f20380b8f745b3e63da44d7 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 22 Jun 2018 16:55:54 -0700 Subject: [PATCH 62/63] Use nameof --- src/ImageSharp/Formats/Gif/GifDecoder.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegDecoder.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs index c81c51e8b..ac451a355 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoder.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// public IImageInfo Identify(Configuration configuration, Stream stream) { - Guard.NotNull(stream, "stream"); + Guard.NotNull(stream, nameof(stream)); var decoder = new GifDecoderCore(configuration, this); return decoder.Identify(stream); diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs index e738982cb..eafbb391c 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// public IImageInfo Identify(Configuration configuration, Stream stream) { - Guard.NotNull(stream, "stream"); + Guard.NotNull(stream, nameof(stream)); using (var decoder = new PdfJsJpegDecoderCore(configuration, this)) { From 0bea00e68b9b47d795b7e4ff3b41c4d44cb01b89 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 22 Jun 2018 16:56:23 -0700 Subject: [PATCH 63/63] Remove unnessary DebugGaurds on structs --- .../ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs | 2 -- .../Implementation/CieLuv/CieXyzToCieLuvConverter.cs | 2 -- .../Implementation/CieXyy/CieXyzAndCieXyyConverter.cs | 4 ---- .../Conversion/Implementation/Hsl/HslAndRgbConverter.cs | 4 ---- .../Conversion/Implementation/Hsv/HsvAndRgbConverter.cs | 4 ---- .../HunterLab/CieXyzAndHunterLabConverterBase.cs | 2 -- .../HunterLab/CieXyzToHunterLabConverter.cs | 8 +------- .../Implementation/Rgb/CieXyzToLinearRgbConverter.cs | 2 -- .../Implementation/Rgb/LinearRgbToCieXyzConverter.cs | 1 - .../Implementation/Rgb/LinearRgbToRgbConverter.cs | 2 -- .../Implementation/YCbCr/YCbCrAndRgbConverter.cs | 4 ---- 11 files changed, 1 insertion(+), 34 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs index 45beecf66..b609934e9 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs @@ -110,8 +110,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public Rgb ToRgb(Hsl color) { - Guard.NotNull(color, nameof(color)); - // Conversion return HslAndRgbConverter.Convert(color); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieXyzToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieXyzToCieLuvConverter.cs index 709d8d426..e1c5dde4f 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieXyzToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieXyzToCieLuvConverter.cs @@ -44,8 +44,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLuvColor [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLuv Convert(CieXyz input) { - DebugGuard.NotNull(input, nameof(input)); - // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Luv.html float yr = input.Y / this.LuvWhitePoint.Y; float up = ComputeUp(input); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyy/CieXyzAndCieXyyConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyy/CieXyzAndCieXyyConverter.cs index bb7d6bb3f..7dfc577dc 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyy/CieXyzAndCieXyyConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyy/CieXyzAndCieXyyConverter.cs @@ -16,8 +16,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieXyyColor [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyy Convert(CieXyz input) { - DebugGuard.NotNull(input, nameof(input)); - float x = input.X / (input.X + input.Y + input.Z); float y = input.Y / (input.X + input.Y + input.Z); @@ -33,8 +31,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieXyyColor [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyz Convert(CieXyy input) { - DebugGuard.NotNull(input, nameof(input)); - if (MathF.Abs(input.Y) < Constants.Epsilon) { return new CieXyz(0, 0, input.Yl); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsl/HslAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsl/HslAndRgbConverter.cs index 2bdbbceca..7983b6ce4 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsl/HslAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsl/HslAndRgbConverter.cs @@ -16,8 +16,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HslColorSap [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgb Convert(Hsl input) { - DebugGuard.NotNull(input, nameof(input)); - float rangedH = input.H / 360F; float r = 0; float g = 0; @@ -49,8 +47,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HslColorSap [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hsl Convert(Rgb input) { - DebugGuard.NotNull(input, nameof(input)); - float r = input.R; float g = input.G; float b = input.B; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsv/HsvAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsv/HsvAndRgbConverter.cs index 981b8f3ab..c46d8f26b 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsv/HsvAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsv/HsvAndRgbConverter.cs @@ -16,8 +16,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HsvColorSap [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgb Convert(Hsv input) { - DebugGuard.NotNull(input, nameof(input)); - float s = input.S; float v = input.V; @@ -81,8 +79,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HsvColorSap [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hsv Convert(Rgb input) { - DebugGuard.NotNull(input, nameof(input)); - float r = input.R; float g = input.G; float b = input.B; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzAndHunterLabConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzAndHunterLabConverterBase.cs index 2d4e3b0e7..ebf75e0d5 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzAndHunterLabConverterBase.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzAndHunterLabConverterBase.cs @@ -34,8 +34,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HunterLabCo [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float ComputeKb(CieXyz whitePoint) { - DebugGuard.NotNull(whitePoint, nameof(whitePoint)); - if (whitePoint == Illuminants.C) { return 70F; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzToHunterLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzToHunterLabConverter.cs index 309663796..58363ea2b 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzToHunterLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzToHunterLabConverter.cs @@ -33,18 +33,12 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HunterLabCo /// /// Gets the target reference white. When not set, is used. /// - public CieXyz HunterLabWhitePoint - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get; - } + public CieXyz HunterLabWhitePoint { get; } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public HunterLab Convert(CieXyz input) { - DebugGuard.NotNull(input, nameof(input)); - // Conversion algorithm described here: http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab float x = input.X, y = input.Y, z = input.Z; float xn = this.HunterLabWhitePoint.X, yn = this.HunterLabWhitePoint.Y, zn = this.HunterLabWhitePoint.Z; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/CieXyzToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/CieXyzToLinearRgbConverter.cs index fd76a30fb..2f52c2074 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/CieXyzToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/CieXyzToLinearRgbConverter.cs @@ -38,8 +38,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSap /// public LinearRgb Convert(CieXyz input) { - DebugGuard.NotNull(input, nameof(input)); - Matrix4x4.Invert(this.conversionMatrix, out Matrix4x4 inverted); Vector3 vector = Vector3.Transform(input.Vector, inverted); return new LinearRgb(vector, this.TargetWorkingSpace); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbToCieXyzConverter.cs index bf36e252a..0746c78c3 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbToCieXyzConverter.cs @@ -38,7 +38,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSap /// public CieXyz Convert(LinearRgb input) { - DebugGuard.NotNull(input, nameof(input)); DebugGuard.IsTrue(input.WorkingSpace.Equals(this.SourceWorkingSpace), nameof(input.WorkingSpace), "Input and source working spaces must be equal."); Vector3 vector = Vector3.Transform(input.Vector, this.conversionMatrix); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbToRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbToRgbConverter.cs index 29ea0f314..3b70c02af 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbToRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbToRgbConverter.cs @@ -13,8 +13,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSap /// public Rgb Convert(LinearRgb input) { - DebugGuard.NotNull(input, nameof(input)); - Vector3 vector = input.Vector; vector.X = input.WorkingSpace.Companding.Compress(vector.X); vector.Y = input.WorkingSpace.Companding.Compress(vector.Y); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCr/YCbCrAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCr/YCbCrAndRgbConverter.cs index aa9668b82..99149a592 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCr/YCbCrAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCr/YCbCrAndRgbConverter.cs @@ -19,8 +19,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.YCbCrColorS [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgb Convert(YCbCr input) { - DebugGuard.NotNull(input, nameof(input)); - float y = input.Y; float cb = input.Cb - 128F; float cr = input.Cr - 128F; @@ -36,8 +34,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.YCbCrColorS [MethodImpl(MethodImplOptions.AggressiveInlining)] public YCbCr Convert(Rgb input) { - DebugGuard.NotNull(input, nameof(input)); - Vector3 rgb = input.Vector * MaxBytes; float r = rgb.X; float g = rgb.Y;