From 0b8d9d1b081e847b34fdd8de71cf8f6a77fc5f46 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 6 Nov 2018 21:04:30 +0100 Subject: [PATCH 01/13] simplify calculations by using intermediate results instead of calculating the same stuff multiple times --- .../Converters/CieXyzToHunterLabConverter.cs | 8 +++++--- .../Converters/HunterLabToCieXyzConverter.cs | 9 ++++++--- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 4 ++-- .../Quantization/FrameQuantizerBase{TPixel}.cs | 6 ++++-- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs index c27c61608..f21235d06 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs @@ -45,9 +45,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float ka = ComputeKa(this.HunterLabWhitePoint); float kb = ComputeKb(this.HunterLabWhitePoint); - float l = 100 * MathF.Sqrt(y / yn); - float a = ka * (((x / xn) - (y / yn)) / MathF.Sqrt(y / yn)); - float b = kb * (((y / yn) - (z / zn)) / MathF.Sqrt(y / yn)); + float yByYn = y / yn; + float sqrtYbyYn = MathF.Sqrt(yByYn); + float l = 100 * sqrtYbyYn; + float a = ka * (((x / xn) - yByYn) / sqrtYbyYn); + float b = kb * ((yByYn - (z / zn)) / sqrtYbyYn); if (float.IsNaN(a)) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs index 783d29a55..4d6808e6c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs @@ -26,9 +26,12 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float ka = ComputeKa(input.WhitePoint); float kb = ComputeKb(input.WhitePoint); - float y = ImageMaths.Pow2(l / 100F) * yn; - float x = (((a / ka) * MathF.Sqrt(y / yn)) + (y / yn)) * xn; - float z = (((b / kb) * MathF.Sqrt(y / yn)) - (y / yn)) * (-zn); + float pow = ImageMaths.Pow2(l / 100F); + float sqrtPow = MathF.Sqrt(pow); + float y = pow * yn; + + float x = (((a / ka) * sqrtPow) + pow) * xn; + float z = (((b / kb) * sqrtPow) - pow) * (-zn); return new CieXyz(x, y, z); } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 7ae716aa0..468f619b9 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -896,9 +896,9 @@ namespace SixLabors.ImageSharp.Formats.Png ref byte sourceRef = ref MemoryMarshal.GetReference(source); ref byte resultRef = ref MemoryMarshal.GetReference(result); - byte mask = (byte)(0xFF >> (8 - bits)); - byte shift0 = (byte)(8 - bits); int shift = 8 - bits; + byte mask = (byte)(0xFF >> shift); + byte shift0 = (byte)shift; int v = 0; int resultOffset = 0; diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs index a8c6c5d7e..3b9b046a0 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs @@ -139,8 +139,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization protected byte GetTransparentIndex() { // Transparent pixels are much more likely to be found at the end of a palette. - int index = this.paletteVector.Length - 1; - for (int i = this.paletteVector.Length - 1; i >= 0; i--) + int paletteVectorLengthMinus1 = this.paletteVector.Length - 1; + + int index = paletteVectorLengthMinus1; + for (int i = paletteVectorLengthMinus1; i >= 0; i--) { ref Vector4 candidate = ref this.paletteVector[i]; if (candidate.Equals(default)) From ea6fc641c394abe1dc57cf1217289b61919bbabe Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 14:01:41 +0100 Subject: [PATCH 02/13] inline division as it's only used in some cases (and done at most once) --- src/ImageSharp/Processing/ResizeHelper.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Processing/ResizeHelper.cs b/src/ImageSharp/Processing/ResizeHelper.cs index b9233937b..92af89d9e 100644 --- a/src/ImageSharp/Processing/ResizeHelper.cs +++ b/src/ImageSharp/Processing/ResizeHelper.cs @@ -337,21 +337,19 @@ namespace SixLabors.ImageSharp.Processing float percentHeight = MathF.Abs(height / (float)sourceHeight); float percentWidth = MathF.Abs(width / (float)sourceWidth); - float sourceRatio = (float)sourceHeight / sourceWidth; - // Find the shortest distance to go. int widthDiff = sourceWidth - width; int heightDiff = sourceHeight - height; if (widthDiff < heightDiff) { - destinationHeight = (int)MathF.Round(width * sourceRatio); + destinationHeight = (int)MathF.Round(width * ((float)sourceHeight / sourceWidth)); height = destinationHeight; destinationWidth = width; } else if (widthDiff > heightDiff) { - destinationWidth = (int)MathF.Round(height / sourceRatio); + destinationWidth = (int)MathF.Round(height * ((float)sourceWidth / sourceHeight)); destinationHeight = height; width = destinationWidth; } From df155496b751e8132298eb9ff72f527a865f9337 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:02:50 +0100 Subject: [PATCH 03/13] inline variable --- .../Processing/Processors/Text/DrawTextProcessor.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs index 487c88064..266d842bf 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs @@ -139,10 +139,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text fistRow = -startY; } - int end = operation.Map.Height; - int maxHeight = source.Height - startY; - end = Math.Min(end, maxHeight); + int end = Math.Min(operation.Map.Height, maxHeight); for (int row = fistRow; row < end; row++) { From 74dba7a9edf22b86d0f682e999af62b26faa6a11 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:04:42 +0100 Subject: [PATCH 04/13] unwrap for-loop to avoid conditional check inside it is known beforehand when the if condition inside the loop will not match: only in the last iteration. Thus we can loop once less and append the last element afterwards. --- src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index 2be5addc2..81393342d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -543,15 +543,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components { var sb = new StringBuilder(); sb.Append('['); - for (int i = 0; i < Size; i++) + for (int i = 0; i < Size - 1; i++) { sb.Append(this[i]); - if (i < Size - 1) - { - sb.Append(','); - } + sb.Append(','); } + sb.Append(this[Size - 1]); + sb.Append(']'); return sb.ToString(); } From 3ebcebe99e8c1bce7f285a8c94c7b2001d00bbda Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:05:56 +0100 Subject: [PATCH 05/13] inline variable initialization --- src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 67f665576..f6da9cb2e 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -856,10 +856,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private void ProcessStartOfScanMarker() { int selectorsCount = this.InputStream.ReadByte(); - int componentIndex = -1; for (int i = 0; i < selectorsCount; i++) { - componentIndex = -1; + int componentIndex = -1; int selector = this.InputStream.ReadByte(); for (int j = 0; j < this.Frame.ComponentIds.Length; j++) From bb360ce3568f33da0f969d0f5708a84b58fd493c Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:48:19 +0100 Subject: [PATCH 06/13] invert condition: always assign literal 1, substract only on special case --- src/ImageSharp/Formats/Gif/LzwEncoder.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs index 34c353ec9..2d32fd23a 100644 --- a/src/ImageSharp/Formats/Gif/LzwEncoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwEncoder.cs @@ -309,10 +309,10 @@ namespace SixLabors.ImageSharp.Formats.Gif // Non-empty slot if (Unsafe.Add(ref hashTableRef, i) >= 0) { - int disp = hsizeReg - i; - if (i == 0) + int disp = 1; + if (i != 0) { - disp = 1; + disp = hsizeReg - i; } do From b6e9eb6f68b079a6f577a4ae550784453946aca2 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:56:38 +0100 Subject: [PATCH 07/13] multiply once and reuse --- 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 a4677ba2b..0dcbd8fef 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -822,11 +822,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg { for (int i = 0; i < componentCount; i++) { - this.buffer[(3 * i) + 6] = (byte)(i + 1); + int i3 = 3 * i; + this.buffer[i3 + 6] = (byte)(i + 1); // We use 4:2:0 chroma subsampling by default. - this.buffer[(3 * i) + 7] = subsamples[i]; - this.buffer[(3 * i) + 8] = chroma[i]; + this.buffer[i3 + 7] = subsamples[i]; + this.buffer[i3 + 8] = chroma[i]; } } From 34481a645a7d7d257a3e0f661ba25e49da4993b7 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 16:02:54 +0100 Subject: [PATCH 08/13] avoid local variable copy when the original is never changed --- src/ImageSharp/Formats/Png/PngScanlineProcessor.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index 3fe590ee2..420775eca 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -190,12 +190,11 @@ namespace SixLabors.ImageSharp.Formats.Png else { Rgba32 rgba32 = default; - int bps = bytesPerSample; for (int x = 0; x < header.Width; x++) { int offset = x * bytesPerPixel; byte luminance = Unsafe.Add(ref scanlineSpanRef, offset); - byte alpha = Unsafe.Add(ref scanlineSpanRef, offset + bps); + byte alpha = Unsafe.Add(ref scanlineSpanRef, offset + bytesPerSample); rgba32.R = luminance; rgba32.G = luminance; From 0da4c45cbd79059cc499522c4a76aa7294eb2b74 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 16:03:49 +0100 Subject: [PATCH 09/13] return first matching ImageFormat when iterating over FormatDetectors --- src/ImageSharp/Image.FromBytes.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index 07adc03ff..34927e6e2 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -198,18 +198,17 @@ namespace SixLabors.ImageSharp return null; } - IImageFormat format = default; foreach (IImageFormatDetector detector in config.ImageFormatsManager.FormatDetectors) { IImageFormat f = detector.DetectFormat(data); if (f != null) { - format = f; + return f; } } - return format; + return default; } /// From e60deb73af13c47d1054f49cdc0cc9e7664c1351 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 23:33:22 +0100 Subject: [PATCH 10/13] avoid doubled increment in for loop and multiple array indexer access --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index eb519f421..5a6cc1260 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -310,9 +310,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp } else { - for (int i = 0; i < cmd[0]; i++) + int max = cmd[0] + count; + byte cmd1 = cmd[1]; + + for (; count < max; count++) { - buffer[count++] = cmd[1]; + buffer[count] = cmd1; } } } From 321cca6e815ff0abb73d3a7b2168bfa9a670fdf3 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 7 Nov 2018 18:47:08 +0100 Subject: [PATCH 11/13] #771: change order of addition as proposed by @dlemstra added comments as explanation --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 5a6cc1260..ef3ca24ee 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -310,8 +310,8 @@ namespace SixLabors.ImageSharp.Formats.Bmp } else { - int max = cmd[0] + count; - byte cmd1 = cmd[1]; + int max = count + cmd[0]; // as we start at the current count in the following loop, max is count + cmd[0] + byte cmd1 = cmd[1]; // store the value to avoid the repeated indexer access inside the loop for (; count < max; count++) { From 88da4bcba303c335d457edce326e1640c972e167 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 11 Nov 2018 21:28:53 +0100 Subject: [PATCH 12/13] make code more clear by extracting the ratio to a variable again while keeping it inlined to avoid it in the third case, and while still replacing the division by a multiplication in the second case. --- src/ImageSharp/Processing/ResizeHelper.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Processing/ResizeHelper.cs b/src/ImageSharp/Processing/ResizeHelper.cs index 92af89d9e..aaac7346d 100644 --- a/src/ImageSharp/Processing/ResizeHelper.cs +++ b/src/ImageSharp/Processing/ResizeHelper.cs @@ -343,13 +343,15 @@ namespace SixLabors.ImageSharp.Processing if (widthDiff < heightDiff) { - destinationHeight = (int)MathF.Round(width * ((float)sourceHeight / sourceWidth)); + float sourceRatio = (float)sourceHeight / sourceWidth; + destinationHeight = (int)MathF.Round(width * sourceRatio); height = destinationHeight; destinationWidth = width; } else if (widthDiff > heightDiff) { - destinationWidth = (int)MathF.Round(height * ((float)sourceWidth / sourceHeight)); + float sourceRatioInverse = (float)sourceWidth / sourceHeight; + destinationWidth = (int)MathF.Round(height * sourceRatioInverse); destinationHeight = height; width = destinationWidth; } From f6618a6f3aeafe0dc14f82993e197d3c99958975 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 11 Nov 2018 21:30:19 +0100 Subject: [PATCH 13/13] inline percentHeiught and percentWidth as they are used only in one case each --- src/ImageSharp/Processing/ResizeHelper.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Processing/ResizeHelper.cs b/src/ImageSharp/Processing/ResizeHelper.cs index aaac7346d..3ae632162 100644 --- a/src/ImageSharp/Processing/ResizeHelper.cs +++ b/src/ImageSharp/Processing/ResizeHelper.cs @@ -333,10 +333,6 @@ namespace SixLabors.ImageSharp.Processing return (new Size(sourceWidth, sourceWidth), new Rectangle(0, 0, sourceWidth, sourceHeight)); } - // Fractional variants for preserving aspect ratio. - float percentHeight = MathF.Abs(height / (float)sourceHeight); - float percentWidth = MathF.Abs(width / (float)sourceWidth); - // Find the shortest distance to go. int widthDiff = sourceWidth - width; int heightDiff = sourceHeight - height; @@ -360,12 +356,14 @@ namespace SixLabors.ImageSharp.Processing if (height > width) { destinationWidth = width; + float percentWidth = MathF.Abs(width / (float)sourceWidth); destinationHeight = (int)MathF.Round(sourceHeight * percentWidth); height = destinationHeight; } else { destinationHeight = height; + float percentHeight = MathF.Abs(height / (float)sourceHeight); destinationWidth = (int)MathF.Round(sourceWidth * percentHeight); width = destinationWidth; }