diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index 3a29e21d9c..ddbac2d072 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -18,6 +18,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Represents a Jpeg block with coefficients. /// + [StructLayout(LayoutKind.Sequential)] internal partial struct Block8x8F : IEquatable { /// @@ -51,9 +52,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components public Vector4 V7R; #pragma warning restore SA1600 // ElementsMustBeDocumented - private static readonly Vector4 NegativeOne = new Vector4(-1); - private static readonly Vector4 Offset = new Vector4(.5F); - /// /// Get/Set scalar elements at a given index /// @@ -155,10 +153,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// [MethodImpl(InliningOptions.ShortMethod)] public void Clear() - { - // The cheapest way to do this in C#: - this = default; - } + => this = default; // The cheapest way to do this in C#: /// /// Load raw 32bit floating point data from source. @@ -180,9 +175,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Source [MethodImpl(InliningOptions.ShortMethod)] public static unsafe void LoadFrom(Block8x8F* blockPtr, Span source) - { - blockPtr->LoadFrom(source); - } + => blockPtr->LoadFrom(source); /// /// Load raw 32bit floating point data from source @@ -236,9 +229,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// The destination. [MethodImpl(InliningOptions.ShortMethod)] public static unsafe void ScaledCopyTo(Block8x8F* blockPtr, Span dest) - { - blockPtr->ScaledCopyTo(dest); - } + => blockPtr->ScaledCopyTo(dest); /// /// Copy raw 32bit floating point data to dest @@ -439,7 +430,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// The block pointer. /// The qt pointer. /// Unzig pointer - // [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void DequantizeBlock(Block8x8F* blockPtr, Block8x8F* qtPtr, byte* unzigPtr) { float* b = (float*)blockPtr; @@ -556,22 +546,60 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components [MethodImpl(InliningOptions.ShortMethod)] private static void DivideRoundAll(ref Block8x8F a, ref Block8x8F b) { - a.V0L = DivideRound(a.V0L, b.V0L); - a.V0R = DivideRound(a.V0R, b.V0R); - a.V1L = DivideRound(a.V1L, b.V1L); - a.V1R = DivideRound(a.V1R, b.V1R); - a.V2L = DivideRound(a.V2L, b.V2L); - a.V2R = DivideRound(a.V2R, b.V2R); - a.V3L = DivideRound(a.V3L, b.V3L); - a.V3R = DivideRound(a.V3R, b.V3R); - a.V4L = DivideRound(a.V4L, b.V4L); - a.V4R = DivideRound(a.V4R, b.V4R); - a.V5L = DivideRound(a.V5L, b.V5L); - a.V5R = DivideRound(a.V5R, b.V5R); - a.V6L = DivideRound(a.V6L, b.V6L); - a.V6R = DivideRound(a.V6R, b.V6R); - a.V7L = DivideRound(a.V7L, b.V7L); - a.V7R = DivideRound(a.V7R, b.V7R); +#if SUPPORTS_RUNTIME_INTRINSICS + if (Avx.IsSupported) + { + var vnegOne = Vector256.Create(-1f); + var vadd = Vector256.Create(.5F); + var vone = Vector256.Create(1f); + + ref Vector256 aBase = ref Unsafe.AsRef(Unsafe.As>(ref a.V0L)); + ref Vector256 bBase = ref Unsafe.AsRef(Unsafe.As>(ref b.V0L)); + ref Vector256 aEnd = ref Unsafe.Add(ref aBase, 8); + + do + { + Vector256 voff = Avx.Multiply(Avx.Min(Avx.Max(vnegOne, aBase), vone), vadd); + Unsafe.Add(ref aBase, 0) = Avx.Add(Avx.Divide(aBase, bBase), voff); + + aBase = ref Unsafe.Add(ref aBase, 1); + bBase = ref Unsafe.Add(ref bBase, 1); + } + while (Unsafe.IsAddressLessThan(ref aBase, ref aEnd)); + } + else +#endif + { + a.V0L = DivideRound(a.V0L, b.V0L); + a.V0R = DivideRound(a.V0R, b.V0R); + a.V1L = DivideRound(a.V1L, b.V1L); + a.V1R = DivideRound(a.V1R, b.V1R); + a.V2L = DivideRound(a.V2L, b.V2L); + a.V2R = DivideRound(a.V2R, b.V2R); + a.V3L = DivideRound(a.V3L, b.V3L); + a.V3R = DivideRound(a.V3R, b.V3R); + a.V4L = DivideRound(a.V4L, b.V4L); + a.V4R = DivideRound(a.V4R, b.V4R); + a.V5L = DivideRound(a.V5L, b.V5L); + a.V5R = DivideRound(a.V5R, b.V5R); + a.V6L = DivideRound(a.V6L, b.V6L); + a.V6R = DivideRound(a.V6R, b.V6R); + a.V7L = DivideRound(a.V7L, b.V7L); + a.V7R = DivideRound(a.V7R, b.V7R); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector4 DivideRound(Vector4 dividend, Vector4 divisor) + { + var neg = new Vector4(-1); + var add = new Vector4(.5F); + + // sign(dividend) = max(min(dividend, 1), -1) + Vector4 sign = Numerics.Clamp(dividend, neg, Vector4.One); + + // AlmostRound(dividend/divisor) = dividend/divisor + 0.5*sign(dividend) + return (dividend / divisor) + (sign * add); } public void RoundInto(ref Block8x8 dest) @@ -673,8 +701,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// public bool Equals(Block8x8F other) - { - return this.V0L == other.V0L + => this.V0L == other.V0L && this.V0R == other.V0R && this.V1L == other.V1L && this.V1R == other.V1R @@ -690,7 +717,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components && this.V6R == other.V6R && this.V7L == other.V7L && this.V7R == other.V7R; - } /// public override string ToString() @@ -718,16 +744,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components return row.FastRound(); } - [MethodImpl(InliningOptions.ShortMethod)] - private static Vector4 DivideRound(Vector4 dividend, Vector4 divisor) - { - // sign(dividend) = max(min(dividend, 1), -1) - Vector4 sign = Numerics.Clamp(dividend, NegativeOne, Vector4.One); - - // AlmostRound(dividend/divisor) = dividend/divisor + 0.5*sign(dividend) - return (dividend / divisor) + (sign * Offset); - } - [Conditional("DEBUG")] private static void GuardBlockIndex(int idx) { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs index 8fcc63c6aa..81e64b277b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs @@ -59,9 +59,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder /// /// Converts a 8x8 image area inside 'pixels' at position (x,y) placing the result members of the structure (, , ) /// - public void Convert(ImageFrame frame, int x, int y, in RowOctet currentRows) + public void Convert(ImageFrame frame, int x, int y, ref RowOctet currentRows) { - this.pixelBlock.LoadAndStretchEdges(frame.PixelBuffer, x, y, currentRows); + this.pixelBlock.LoadAndStretchEdges(frame.PixelBuffer, x, y, ref currentRows); Span rgbSpan = this.rgbBlock.AsSpanUnsafe(); PixelOperations.Instance.ToRgb24(frame.GetConfiguration(), this.pixelBlock.AsSpanUnsafe(), rgbSpan); @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder } else { - this.colorTables.Convert(rgbSpan, ref yBlock, ref cbBlock, ref crBlock); + this.colorTables.Convert(rgbSpan, ref yBlock, ref cbBlock, ref crBlock); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs index 92ba1afd35..42c01d770e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Load a 8x8 region of an image into the block. /// The "outlying" area of the block will be stretched out with pixels on the right and bottom edge of the image. /// - public void LoadAndStretchEdges(Buffer2D source, int sourceX, int sourceY, in RowOctet currentRows) + public void LoadAndStretchEdges(Buffer2D source, int sourceX, int sourceY, ref RowOctet currentRows) { int width = Math.Min(8, source.Width - sourceX); int height = Math.Min(8, source.Height - sourceY); diff --git a/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs b/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs index ae10bfba83..f35bb44682 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. using System; @@ -12,39 +12,24 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Cache 8 pixel rows on the stack, which may originate from different buffers of a . /// [StructLayout(LayoutKind.Sequential)] - internal readonly ref struct RowOctet + internal ref struct RowOctet where T : struct { - private readonly Span row0; - private readonly Span row1; - private readonly Span row2; - private readonly Span row3; - private readonly Span row4; - private readonly Span row5; - private readonly Span row6; - private readonly Span row7; - - public RowOctet(Buffer2D buffer, int startY) - { - int y = startY; - int height = buffer.Height; - this.row0 = y < height ? buffer.GetRowSpan(y++) : default; - this.row1 = y < height ? buffer.GetRowSpan(y++) : default; - this.row2 = y < height ? buffer.GetRowSpan(y++) : default; - this.row3 = y < height ? buffer.GetRowSpan(y++) : default; - this.row4 = y < height ? buffer.GetRowSpan(y++) : default; - this.row5 = y < height ? buffer.GetRowSpan(y++) : default; - this.row6 = y < height ? buffer.GetRowSpan(y++) : default; - this.row7 = y < height ? buffer.GetRowSpan(y) : default; - } + private Span row0; + private Span row1; + private Span row2; + private Span row3; + private Span row4; + private Span row5; + private Span row6; + private Span row7; + // No unsafe tricks, since Span can't be used as a generic argument public Span this[int y] { - [MethodImpl(InliningOptions.ShortMethod)] - get - { - // No unsafe tricks, since Span can't be used as a generic argument - return y switch + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => + y switch { 0 => this.row0, 1 => this.row1, @@ -56,13 +41,57 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components 7 => this.row7, _ => ThrowIndexOutOfRangeException() }; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private set + { + switch (y) + { + case 0: + this.row0 = value; + break; + case 1: + this.row1 = value; + break; + case 2: + this.row2 = value; + break; + case 3: + this.row3 = value; + break; + case 4: + this.row4 = value; + break; + case 5: + this.row5 = value; + break; + case 6: + this.row6 = value; + break; + default: + this.row7 = value; + break; + } } } - [MethodImpl(InliningOptions.ColdPath)] - private static Span ThrowIndexOutOfRangeException() + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Update(Buffer2D buffer, int startY) { - throw new IndexOutOfRangeException(); + // We don't actually have to assign values outside of the + // frame pixel buffer since they are never requested. + int y = startY; + int yEnd = Math.Min(y + 8, buffer.Height); + + int i = 0; + while (y < yEnd) + { + this[i++] = buffer.GetRowSpan(y++); + } } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static Span ThrowIndexOutOfRangeException() + => throw new IndexOutOfRangeException(); } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 36766d05f0..422c7bd7ec 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -6,6 +6,7 @@ using System.Buffers.Binary; using System.IO; using System.Linq; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Threading; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Jpeg.Components; @@ -313,7 +314,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// /// The packed bits. /// The number of bits - private void Emit(uint bits, uint count) + /// The reference to the emitBuffer. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Emit(uint bits, uint count, ref byte emitBufferBase) { count += this.bitCount; bits <<= (int)(32 - count); @@ -327,10 +330,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg while (count >= 8) { byte b = (byte)(bits >> 24); - this.emitBuffer[len++] = b; - if (b == 0xff) + Unsafe.Add(ref emitBufferBase, len++) = b; + if (b == byte.MaxValue) { - this.emitBuffer[len++] = 0x00; + Unsafe.Add(ref emitBufferBase, len++) = byte.MinValue; } bits <<= 8; @@ -352,11 +355,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// /// The index of the Huffman encoder /// The value to encode. + /// The reference to the emit buffer. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void EmitHuff(HuffIndex index, int value) + private void EmitHuff(HuffIndex index, int value, ref byte emitBufferBase) { uint x = HuffmanLut.TheHuffmanLut[(int)index].Values[value]; - this.Emit(x & ((1 << 24) - 1), x >> 24); + this.Emit(x & ((1 << 24) - 1), x >> 24, ref emitBufferBase); } /// @@ -365,8 +369,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// The index of the Huffman encoder /// The number of copies to encode. /// The value to encode. + /// The reference to the emit buffer. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void EmitHuffRLE(HuffIndex index, int runLength, int value) + private void EmitHuffRLE(HuffIndex index, int runLength, int value, ref byte emitBufferBase) { int a = value; int b = value; @@ -386,10 +391,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg bt = 8 + (uint)BitCountLut[a >> 8]; } - this.EmitHuff(index, (int)((uint)(runLength << 4) | bt)); + this.EmitHuff(index, (int)((uint)(runLength << 4) | bt), ref emitBufferBase); if (bt > 0) { - this.Emit((uint)b & (uint)((1 << ((int)bt)) - 1), bt); + this.Emit((uint)b & (uint)((1 << ((int)bt)) - 1), bt, ref emitBufferBase); } } @@ -399,7 +404,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// The pixel format. /// The pixel accessor providing access to the image pixels. /// The token to monitor for cancellation. - private void Encode444(Image pixels, CancellationToken cancellationToken) + /// The reference to the emit buffer. + private void Encode444(Image pixels, CancellationToken cancellationToken, ref byte emitBufferBase) where TPixel : unmanaged, IPixel { // TODO: Need a JpegScanEncoder class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.) @@ -418,15 +424,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg var pixelConverter = YCbCrForwardConverter.Create(); ImageFrame frame = pixels.Frames.RootFrame; Buffer2D pixelBuffer = frame.PixelBuffer; + RowOctet currentRows = default; for (int y = 0; y < pixels.Height; y += 8) { cancellationToken.ThrowIfCancellationRequested(); - var currentRows = new RowOctet(pixelBuffer, y); + currentRows.Update(pixelBuffer, y); for (int x = 0; x < pixels.Width; x += 8) { - pixelConverter.Convert(frame, x, y, currentRows); + pixelConverter.Convert(frame, x, y, ref currentRows); prevDCY = this.WriteBlock( QuantIndex.Luminance, @@ -435,7 +442,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg ref temp1, ref temp2, ref onStackLuminanceQuantTable, - ref unzig); + ref unzig, + ref emitBufferBase); + prevDCCb = this.WriteBlock( QuantIndex.Chrominance, prevDCCb, @@ -443,7 +452,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg ref temp1, ref temp2, ref onStackChrominanceQuantTable, - ref unzig); + ref unzig, + ref emitBufferBase); + prevDCCr = this.WriteBlock( QuantIndex.Chrominance, prevDCCr, @@ -451,7 +462,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg ref temp1, ref temp2, ref onStackChrominanceQuantTable, - ref unzig); + ref unzig, + ref emitBufferBase); } } } @@ -517,9 +529,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// Temporal block 2 /// Quantization table /// The 8x8 Unzig block. - /// - /// The - /// + /// The reference to the emit buffer. + /// The . private int WriteBlock( QuantIndex index, int prevDC, @@ -527,7 +538,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg ref Block8x8F tempDest1, ref Block8x8F tempDest2, ref Block8x8F quant, - ref ZigZag unZig) + ref ZigZag unZig, + ref byte emitBufferBase) { FastFloatingPointDCT.TransformFDCT(ref src, ref tempDest1, ref tempDest2); @@ -536,7 +548,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg int dc = (int)tempDest2[0]; // Emit the DC delta. - this.EmitHuffRLE((HuffIndex)((2 * (int)index) + 0), 0, dc - prevDC); + this.EmitHuffRLE((HuffIndex)((2 * (int)index) + 0), 0, dc - prevDC, ref emitBufferBase); // Emit the AC components. var h = (HuffIndex)((2 * (int)index) + 1); @@ -554,18 +566,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg { while (runLength > 15) { - this.EmitHuff(h, 0xf0); + this.EmitHuff(h, 0xf0, ref emitBufferBase); runLength -= 16; } - this.EmitHuffRLE(h, runLength, ac); + this.EmitHuffRLE(h, runLength, ac, ref emitBufferBase); runLength = 0; } } if (runLength > 0) { - this.EmitHuff(h, 0x00); + this.EmitHuff(h, 0x00, ref emitBufferBase); } return dc; @@ -747,9 +759,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// /// The length of the data the app1 marker contains. private void WriteApp1Header(int app1Length) - { - this.WriteAppHeader(app1Length, JpegConstants.Markers.APP1); - } + => this.WriteAppHeader(app1Length, JpegConstants.Markers.APP1); /// /// Writes a AppX header. @@ -953,19 +963,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg // TODO: Need a JpegScanEncoder class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.) // TODO: We should allow grayscale writing. this.outputStream.Write(SosHeaderYCbCr); - + ref byte emitBufferBase = ref MemoryMarshal.GetReference(this.emitBuffer); switch (this.subsample) { case JpegSubsample.Ratio444: - this.Encode444(image, cancellationToken); + this.Encode444(image, cancellationToken, ref emitBufferBase); break; case JpegSubsample.Ratio420: - this.Encode420(image, cancellationToken); + this.Encode420(image, cancellationToken, ref emitBufferBase); break; } // Pad the last byte with 1's. - this.Emit(0x7f, 7); + this.Emit(0x7f, 7, ref emitBufferBase); } /// @@ -975,7 +985,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// The pixel format. /// The pixel accessor providing access to the image pixels. /// The token to monitor for cancellation. - private void Encode420(Image pixels, CancellationToken cancellationToken) + /// The reference to the emit buffer. + private void Encode420(Image pixels, CancellationToken cancellationToken, ref byte emitBufferBase) where TPixel : unmanaged, IPixel { // TODO: Need a JpegScanEncoder class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.) @@ -997,6 +1008,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg int prevDCY = 0, prevDCCb = 0, prevDCCr = 0; ImageFrame frame = pixels.Frames.RootFrame; Buffer2D pixelBuffer = frame.PixelBuffer; + RowOctet currentRows = default; for (int y = 0; y < pixels.Height; y += 16) { @@ -1008,10 +1020,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg int xOff = (i & 1) * 8; int yOff = (i & 2) * 4; - // TODO: Try pushing this to the outer loop! - var currentRows = new RowOctet(pixelBuffer, y + yOff); - - pixelConverter.Convert(frame, x + xOff, y + yOff, currentRows); + currentRows.Update(pixelBuffer, y + yOff); + pixelConverter.Convert(frame, x + xOff, y + yOff, ref currentRows); cb[i] = pixelConverter.Cb; cr[i] = pixelConverter.Cr; @@ -1023,7 +1033,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg ref temp1, ref temp2, ref onStackLuminanceQuantTable, - ref unzig); + ref unzig, + ref emitBufferBase); } Block8x8F.Scale16X16To8X8(ref b, cb); @@ -1034,7 +1045,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg ref temp1, ref temp2, ref onStackChrominanceQuantTable, - ref unzig); + ref unzig, + ref emitBufferBase); Block8x8F.Scale16X16To8X8(ref b, cr); prevDCCr = this.WriteBlock( @@ -1044,7 +1056,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg ref temp1, ref temp2, ref onStackChrominanceQuantTable, - ref unzig); + ref unzig, + ref emitBufferBase); } } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Scale16X16To8X8.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Scale16X16To8X8.cs index 8188297608..ebd3e40130 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Scale16X16To8X8.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Scale16X16To8X8.cs @@ -1,3 +1,6 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + using System; using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.Formats.Jpeg.Components; @@ -15,7 +18,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Format.Jpeg.Components { var random = new Random(); - float[] f = new float[8*8]; + float[] f = new float[8 * 8]; for (int i = 0; i < f.Length; i++) { f[i] = (float)random.NextDouble(); diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs index bfbd150fea..81a5604f1e 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { if (this.bmpStream == null) { - const string TestImage = TestImages.Bmp.Car; + const string TestImage = TestImages.Bmp.NegHeight; this.bmpStream = File.OpenRead(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImage)); this.bmpCore = Image.Load(this.bmpStream); this.bmpStream.Position = 0; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs b/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs index c366e4f56e..c0f3b6a6a4 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs @@ -42,8 +42,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg using (Image s = provider.GetImage()) { var d = default(GenericBlock8x8); - var rowOctet = new RowOctet(s.GetRootFramePixelBuffer(), 0); - d.LoadAndStretchEdges(s.Frames.RootFrame.PixelBuffer, 0, 0, rowOctet); + RowOctet rowOctet = default; + rowOctet.Update(s.GetRootFramePixelBuffer(), 0); + d.LoadAndStretchEdges(s.Frames.RootFrame.PixelBuffer, 0, 0, ref rowOctet); TPixel a = s.Frames.RootFrame[0, 0]; TPixel b = d[0, 0]; @@ -67,8 +68,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg using (Image s = provider.GetImage()) { var d = default(GenericBlock8x8); - var rowOctet = new RowOctet(s.GetRootFramePixelBuffer(), 7); - d.LoadAndStretchEdges(s.Frames.RootFrame.PixelBuffer, 6, 7, rowOctet); + RowOctet rowOctet = default; + rowOctet.Update(s.GetRootFramePixelBuffer(), 7); + + d.LoadAndStretchEdges(s.Frames.RootFrame.PixelBuffer, 6, 7, ref rowOctet); Assert.Equal(s[6, 7], d[0, 0]); Assert.Equal(s[6, 8], d[0, 1]); diff --git a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs index 16d0baff39..17c73cc834 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs @@ -375,7 +375,7 @@ namespace SixLabors.ImageSharp.Tests var array = new Rgba32[size]; var memory = new Memory(array); - Image.WrapMemory(memory, height, width); + Image.WrapMemory(memory, height, width); } private class TestMemoryOwner : IMemoryOwner diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs index b80a29646c..8d1b0f7938 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs @@ -263,7 +263,7 @@ namespace SixLabors.ImageSharp.Tests private static string GetNetCoreVersion() { Assembly assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly; - string[] assemblyPath = assembly.CodeBase.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries); + string[] assemblyPath = assembly.Location.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries); int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App"); if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2) {