diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index 067257132..b96204ed9 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Net.Http; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Formats.Gif; @@ -27,6 +26,9 @@ namespace SixLabors.ImageSharp /// private static readonly Lazy Lazy = new Lazy(CreateDefaultInstance); + private const int MinStreamProcessingBufferSize = 128; + private const int DefaultStreamProcessingBufferSize = 8096; + private int streamProcessingBufferSize = DefaultStreamProcessingBufferSize; private int maxDegreeOfParallelism = Environment.ProcessorCount; /// @@ -75,6 +77,25 @@ namespace SixLabors.ImageSharp } } + /// + /// Gets or sets the size of the buffer to use when working with streams. + /// Intitialized with by default + /// and can accept a minimum value of . + /// + public int StreamProcessingBufferSize + { + get => this.streamProcessingBufferSize; + set + { + if (value < MinStreamProcessingBufferSize) + { + value = MinStreamProcessingBufferSize; + } + + this.streamProcessingBufferSize = value; + } + } + /// /// Gets a set of properties for the Congiguration. /// @@ -145,6 +166,7 @@ namespace SixLabors.ImageSharp return new Configuration { MaxDegreeOfParallelism = this.MaxDegreeOfParallelism, + StreamProcessingBufferSize = this.StreamProcessingBufferSize, ImageFormatsManager = this.ImageFormatsManager, MemoryAllocator = this.MemoryAllocator, ImageOperationsProvider = this.ImageOperationsProvider, diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs index 7e8ac0721..cb26ff606 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp try { - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return decoder.Decode(bufferedStream); } catch (InvalidMemoryOperationException ex) @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp try { - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return await decoder.DecodeAsync(bufferedStream).ConfigureAwait(false); } catch (InvalidMemoryOperationException ex) @@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { Guard.NotNull(stream, nameof(stream)); - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return new BmpDecoderCore(configuration, this).Identify(bufferedStream); } @@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { Guard.NotNull(stream, nameof(stream)); - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return new BmpDecoderCore(configuration, this).IdentifyAsync(bufferedStream); } } diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs index 2a5fde6ac..2b7103072 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoder.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Formats.Gif try { - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return decoder.Decode(bufferedStream); } catch (InvalidMemoryOperationException ex) @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Formats.Gif try { - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return await decoder.DecodeAsync(bufferedStream).ConfigureAwait(false); } catch (InvalidMemoryOperationException ex) @@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Formats.Gif var decoder = new GifDecoderCore(configuration, this); - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return decoder.Identify(bufferedStream); } @@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.Formats.Gif var decoder = new GifDecoderCore(configuration, this); - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return decoder.IdentifyAsync(bufferedStream); } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs index c5332acb5..3eaf3a4c4 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg using var decoder = new JpegDecoderCore(configuration, this); try { - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return decoder.Decode(bufferedStream); } catch (InvalidMemoryOperationException ex) @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg using var decoder = new JpegDecoderCore(configuration, this); try { - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return await decoder.DecodeAsync(bufferedStream).ConfigureAwait(false); } catch (InvalidMemoryOperationException ex) @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg Guard.NotNull(stream, nameof(stream)); using var decoder = new JpegDecoderCore(configuration, this); - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return decoder.Identify(bufferedStream); } @@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg Guard.NotNull(stream, nameof(stream)); using var decoder = new JpegDecoderCore(configuration, this); - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return decoder.IdentifyAsync(bufferedStream); } diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs index 9eb927784..87e0195c3 100644 --- a/src/ImageSharp/Formats/Png/PngDecoder.cs +++ b/src/ImageSharp/Formats/Png/PngDecoder.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Formats.Png try { - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return decoder.Decode(bufferedStream); } catch (InvalidMemoryOperationException ex) @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Formats.Png try { - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return await decoder.DecodeAsync(bufferedStream).ConfigureAwait(false); } catch (InvalidMemoryOperationException ex) @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Formats.Png public IImageInfo Identify(Configuration configuration, Stream stream) { var decoder = new PngDecoderCore(configuration, this); - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return decoder.Identify(bufferedStream); } @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Formats.Png public Task IdentifyAsync(Configuration configuration, Stream stream) { var decoder = new PngDecoderCore(configuration, this); - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return decoder.IdentifyAsync(bufferedStream); } } diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 89fa4e63d..89caac3f6 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -9,7 +9,6 @@ using System.IO.Compression; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; -using System.Threading.Tasks; using SixLabors.ImageSharp.Formats.Png.Chunks; using SixLabors.ImageSharp.Formats.Png.Filters; using SixLabors.ImageSharp.Formats.Png.Zlib; @@ -1027,7 +1026,7 @@ namespace SixLabors.ImageSharp.Formats.Png private bool TryUncompressTextData(ReadOnlySpan compressedData, Encoding encoding, out string value) { using (var memoryStream = new MemoryStream(compressedData.ToArray())) - using (var bufferedStream = new BufferedReadStream(memoryStream)) + using (var bufferedStream = new BufferedReadStream(this.Configuration, memoryStream)) using (var inflateStream = new ZlibInflateStream(bufferedStream)) { if (!inflateStream.AllocateNewBytes(compressedData.Length, false)) diff --git a/src/ImageSharp/Formats/Tga/TgaDecoder.cs b/src/ImageSharp/Formats/Tga/TgaDecoder.cs index 3d9b9a3d2..25aa233db 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoder.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoder.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Formats.Tga try { - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return decoder.Decode(bufferedStream); } catch (InvalidMemoryOperationException ex) @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Formats.Tga try { - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return await decoder.DecodeAsync(bufferedStream).ConfigureAwait(false); } catch (InvalidMemoryOperationException ex) @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Formats.Tga { Guard.NotNull(stream, nameof(stream)); - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return new TgaDecoderCore(configuration, this).Identify(bufferedStream); } @@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Formats.Tga { Guard.NotNull(stream, nameof(stream)); - using var bufferedStream = new BufferedReadStream(stream); + using var bufferedStream = new BufferedReadStream(configuration, stream); return new TgaDecoderCore(configuration, this).IdentifyAsync(bufferedStream); } } diff --git a/src/ImageSharp/IO/BufferedReadStream.cs b/src/ImageSharp/IO/BufferedReadStream.cs index 816626374..54d919963 100644 --- a/src/ImageSharp/IO/BufferedReadStream.cs +++ b/src/ImageSharp/IO/BufferedReadStream.cs @@ -14,12 +14,7 @@ namespace SixLabors.ImageSharp.IO /// internal sealed class BufferedReadStream : Stream { - /// - /// The length, in bytes, of the underlying buffer. - /// - public const int BufferLength = 8192; - - private const int MaxBufferIndex = BufferLength - 1; + private readonly int maxBufferIndex; private readonly byte[] readBuffer; @@ -38,9 +33,11 @@ namespace SixLabors.ImageSharp.IO /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The input stream. - public BufferedReadStream(Stream stream) + public BufferedReadStream(Configuration configuration, Stream stream) { + Guard.NotNull(configuration, nameof(configuration)); Guard.IsTrue(stream.CanRead, nameof(stream), "Stream must be readable."); Guard.IsTrue(stream.CanSeek, nameof(stream), "Stream must be seekable."); @@ -55,8 +52,9 @@ namespace SixLabors.ImageSharp.IO this.BaseStream = stream; this.Position = (int)stream.Position; this.Length = stream.Length; - - this.readBuffer = ArrayPool.Shared.Rent(BufferLength); + this.BufferSize = configuration.StreamProcessingBufferSize; + this.maxBufferIndex = this.BufferSize - 1; + this.readBuffer = ArrayPool.Shared.Rent(this.BufferSize); this.readBufferHandle = new Memory(this.readBuffer).Pin(); unsafe { @@ -64,7 +62,16 @@ namespace SixLabors.ImageSharp.IO } // This triggers a full read on first attempt. - this.readBufferIndex = BufferLength; + this.readBufferIndex = this.BufferSize; + } + + /// + /// Gets the size, in bytes, of the underlying buffer. + /// + public int BufferSize + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; } /// @@ -91,7 +98,7 @@ namespace SixLabors.ImageSharp.IO // Base stream seek will throw for us if invalid. this.BaseStream.Seek(value, SeekOrigin.Begin); this.readerPosition = value; - this.readBufferIndex = BufferLength; + this.readBufferIndex = this.BufferSize; } } } @@ -125,7 +132,7 @@ namespace SixLabors.ImageSharp.IO // Our buffer has been read. // We need to refill and start again. - if (this.readBufferIndex > MaxBufferIndex) + if (this.readBufferIndex > this.maxBufferIndex) { this.FillReadBuffer(); } @@ -142,14 +149,14 @@ namespace SixLabors.ImageSharp.IO public override int Read(byte[] buffer, int offset, int count) { // Too big for our buffer. Read directly from the stream. - if (count > BufferLength) + if (count > this.BufferSize) { return this.ReadToBufferDirectSlow(buffer, offset, count); } // Too big for remaining buffer but less than entire buffer length // Copy to buffer then read from there. - if (count + this.readBufferIndex > BufferLength) + if (count + this.readBufferIndex > this.BufferSize) { return this.ReadToBufferViaCopySlow(buffer, offset, count); } @@ -164,14 +171,14 @@ namespace SixLabors.ImageSharp.IO { // Too big for our buffer. Read directly from the stream. int count = buffer.Length; - if (count > BufferLength) + if (count > this.BufferSize) { return this.ReadToBufferDirectSlow(buffer); } // Too big for remaining buffer but less than entire buffer length // Copy to buffer then read from there. - if (count + this.readBufferIndex > BufferLength) + if (count + this.readBufferIndex > this.BufferSize) { return this.ReadToBufferViaCopySlow(buffer); } @@ -192,7 +199,7 @@ namespace SixLabors.ImageSharp.IO } // Reset to trigger full read on next attempt. - this.readBufferIndex = BufferLength; + this.readBufferIndex = this.BufferSize; } /// @@ -249,7 +256,7 @@ namespace SixLabors.ImageSharp.IO private bool IsInReadBuffer(long newPosition, out long index) { index = newPosition - this.readerPosition + this.readBufferIndex; - return index > -1 && index < BufferLength; + return index > -1 && index < this.BufferSize; } [MethodImpl(MethodImplOptions.NoInlining)] @@ -267,10 +274,10 @@ namespace SixLabors.ImageSharp.IO int i; do { - i = baseStream.Read(this.readBuffer, n, BufferLength - n); + i = baseStream.Read(this.readBuffer, n, this.BufferSize - n); n += i; } - while (n < BufferLength && i > 0); + while (n < this.BufferSize && i > 0); this.readBufferIndex = 0; } diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs index beec0b188..fae88f21e 100644 --- a/src/ImageSharp/Image.FromStream.cs +++ b/src/ImageSharp/Image.FromStream.cs @@ -687,7 +687,7 @@ namespace SixLabors.ImageSharp // We want to be able to load images from things like HttpContext.Request.Body using MemoryStream memoryStream = configuration.MemoryAllocator.AllocateFixedCapacityMemoryStream(stream.Length); - stream.CopyTo(memoryStream); + stream.CopyTo(memoryStream, configuration.StreamProcessingBufferSize); memoryStream.Position = 0; return action(memoryStream); @@ -729,7 +729,7 @@ namespace SixLabors.ImageSharp } using MemoryStream memoryStream = configuration.MemoryAllocator.AllocateFixedCapacityMemoryStream(stream.Length); - await stream.CopyToAsync(memoryStream).ConfigureAwait(false); + await stream.CopyToAsync(memoryStream, configuration.StreamProcessingBufferSize).ConfigureAwait(false); memoryStream.Position = 0; return await action(memoryStream).ConfigureAwait(false); diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs index ef098e263..8c597a8c5 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg public void ParseStreamPdfJs() { using var memoryStream = new MemoryStream(this.jpegBytes); - using var bufferedStream = new BufferedReadStream(memoryStream); + using var bufferedStream = new BufferedReadStream(Configuration.Default, memoryStream); var decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder { IgnoreMetadata = true }); decoder.ParseStream(bufferedStream); diff --git a/tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs b/tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs index 72cceae90..be232c78d 100644 --- a/tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs +++ b/tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs @@ -35,8 +35,8 @@ namespace SixLabors.ImageSharp.Benchmarks.IO this.stream4 = new MemoryStream(this.buffer); this.stream5 = new MemoryStream(this.buffer); this.stream6 = new MemoryStream(this.buffer); - this.bufferedStream1 = new BufferedReadStream(this.stream3); - this.bufferedStream2 = new BufferedReadStream(this.stream4); + this.bufferedStream1 = new BufferedReadStream(Configuration.Default, this.stream3); + this.bufferedStream2 = new BufferedReadStream(Configuration.Default, this.stream4); this.bufferedStreamWrap1 = new BufferedReadStreamWrapper(this.stream5); this.bufferedStreamWrap2 = new BufferedReadStreamWrapper(this.stream6); } @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.Benchmarks.IO private static byte[] CreateTestBytes() { - var buffer = new byte[BufferedReadStream.BufferLength * 3]; + var buffer = new byte[Configuration.Default.StreamProcessingBufferSize * 3]; var random = new Random(); random.NextBytes(buffer); diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index b18d04834..3507d5c4d 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -133,5 +133,12 @@ namespace SixLabors.ImageSharp.Tests Configuration config = this.DefaultConfiguration; Assert.True(config.WorkingBufferSizeHintInBytes > 1024); } + + [Fact] + public void StreamBufferSize_DefaultIsCorrect() + { + Configuration config = this.DefaultConfiguration; + Assert.True(config.StreamProcessingBufferSize == 8096); + } } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 0694a0855..912f606b2 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { byte[] bytes = TestFile.Create(TestImages.Jpeg.Progressive.Progress).Bytes; using var ms = new MemoryStream(bytes); - using var bufferedStream = new BufferedReadStream(ms); + using var bufferedStream = new BufferedReadStream(Configuration.Default, ms); var decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder()); decoder.ParseStream(bufferedStream); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs index 1d200592a..662ea9e33 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg byte[] sourceBytes = TestFile.Create(provider.SourceFileOrDescription).Bytes; using var ms = new MemoryStream(sourceBytes); - using var bufferedStream = new BufferedReadStream(ms); + using var bufferedStream = new BufferedReadStream(Configuration.Default, ms); decoder.ParseStream(bufferedStream); var data = LibJpegTools.SpectralData.LoadFromImageSharpDecoder(decoder); @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg byte[] sourceBytes = TestFile.Create(provider.SourceFileOrDescription).Bytes; using var ms = new MemoryStream(sourceBytes); - using var bufferedStream = new BufferedReadStream(ms); + using var bufferedStream = new BufferedReadStream(Configuration.Default, ms); decoder.ParseStream(bufferedStream); var imageSharpData = LibJpegTools.SpectralData.LoadFromImageSharpDecoder(decoder); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs index 96d85fd8e..c6f4704f0 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs @@ -193,7 +193,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils { byte[] bytes = TestFile.Create(testFileName).Bytes; using var ms = new MemoryStream(bytes); - using var bufferedStream = new BufferedReadStream(ms); + using var bufferedStream = new BufferedReadStream(Configuration.Default, ms); var decoder = new JpegDecoderCore(Configuration.Default, new JpegDecoder()); decoder.ParseStream(bufferedStream, metaDataOnly); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs index 6284191f3..1ec7e2448 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png var decoder = new PngDecoder(); ImageFormatException exception = - Assert.Throws(() => decoder.Decode(null, memStream)); + Assert.Throws(() => decoder.Decode(Configuration.Default, memStream)); Assert.Equal($"CRC Error. PNG {chunkName} chunk is corrupt!", exception.Message); } diff --git a/tests/ImageSharp.Tests/IO/BufferedReadStreamTests.cs b/tests/ImageSharp.Tests/IO/BufferedReadStreamTests.cs index d08d5adef..b15093a3d 100644 --- a/tests/ImageSharp.Tests/IO/BufferedReadStreamTests.cs +++ b/tests/ImageSharp.Tests/IO/BufferedReadStreamTests.cs @@ -10,18 +10,27 @@ namespace SixLabors.ImageSharp.Tests.IO { public class BufferedReadStreamTests { + private readonly Configuration configuration; + private readonly int bufferSize; + + public BufferedReadStreamTests() + { + this.configuration = Configuration.Default; + this.bufferSize = this.configuration.StreamProcessingBufferSize; + } + [Fact] public void BufferedStreamCanReadSingleByteFromOrigin() { - using (MemoryStream stream = this.CreateTestStream()) + using (MemoryStream stream = this.CreateTestStream(this.bufferSize * 3)) { byte[] expected = stream.ToArray(); - using (var reader = new BufferedReadStream(stream)) + using (var reader = new BufferedReadStream(this.configuration, stream)) { Assert.Equal(expected[0], reader.ReadByte()); // We've read a whole chunk but increment by 1 in our reader. - Assert.Equal(BufferedReadStream.BufferLength, stream.Position); + Assert.Equal(this.bufferSize, stream.Position); Assert.Equal(1, reader.Position); } @@ -33,18 +42,18 @@ namespace SixLabors.ImageSharp.Tests.IO [Fact] public void BufferedStreamCanReadSingleByteFromOffset() { - using (MemoryStream stream = this.CreateTestStream()) + using (MemoryStream stream = this.CreateTestStream(this.bufferSize * 3)) { byte[] expected = stream.ToArray(); const int offset = 5; - using (var reader = new BufferedReadStream(stream)) + using (var reader = new BufferedReadStream(this.configuration, stream)) { reader.Position = offset; Assert.Equal(expected[offset], reader.ReadByte()); // We've read a whole chunk but increment by 1 in our reader. - Assert.Equal(BufferedReadStream.BufferLength + offset, stream.Position); + Assert.Equal(this.bufferSize + offset, stream.Position); Assert.Equal(offset + 1, reader.Position); } @@ -55,30 +64,30 @@ namespace SixLabors.ImageSharp.Tests.IO [Fact] public void BufferedStreamCanReadSubsequentSingleByteCorrectly() { - using (MemoryStream stream = this.CreateTestStream()) + using (MemoryStream stream = this.CreateTestStream(this.bufferSize * 3)) { byte[] expected = stream.ToArray(); int i; - using (var reader = new BufferedReadStream(stream)) + using (var reader = new BufferedReadStream(this.configuration, stream)) { for (i = 0; i < expected.Length; i++) { Assert.Equal(expected[i], reader.ReadByte()); Assert.Equal(i + 1, reader.Position); - if (i < BufferedReadStream.BufferLength) + if (i < this.bufferSize) { - Assert.Equal(stream.Position, BufferedReadStream.BufferLength); + Assert.Equal(stream.Position, this.bufferSize); } - else if (i >= BufferedReadStream.BufferLength && i < BufferedReadStream.BufferLength * 2) + else if (i >= this.bufferSize && i < this.bufferSize * 2) { // We should have advanced to the second chunk now. - Assert.Equal(stream.Position, BufferedReadStream.BufferLength * 2); + Assert.Equal(stream.Position, this.bufferSize * 2); } else { // We should have advanced to the third chunk now. - Assert.Equal(stream.Position, BufferedReadStream.BufferLength * 3); + Assert.Equal(stream.Position, this.bufferSize * 3); } } } @@ -90,18 +99,18 @@ namespace SixLabors.ImageSharp.Tests.IO [Fact] public void BufferedStreamCanReadMultipleBytesFromOrigin() { - using (MemoryStream stream = this.CreateTestStream()) + using (MemoryStream stream = this.CreateTestStream(this.bufferSize * 3)) { var buffer = new byte[2]; byte[] expected = stream.ToArray(); - using (var reader = new BufferedReadStream(stream)) + using (var reader = new BufferedReadStream(this.configuration, stream)) { Assert.Equal(2, reader.Read(buffer, 0, 2)); Assert.Equal(expected[0], buffer[0]); Assert.Equal(expected[1], buffer[1]); // We've read a whole chunk but increment by the buffer length in our reader. - Assert.Equal(stream.Position, BufferedReadStream.BufferLength); + Assert.Equal(stream.Position, this.bufferSize); Assert.Equal(buffer.Length, reader.Position); } } @@ -110,11 +119,11 @@ namespace SixLabors.ImageSharp.Tests.IO [Fact] public void BufferedStreamCanReadSubsequentMultipleByteCorrectly() { - using (MemoryStream stream = this.CreateTestStream()) + using (MemoryStream stream = this.CreateTestStream(this.bufferSize * 3)) { var buffer = new byte[2]; byte[] expected = stream.ToArray(); - using (var reader = new BufferedReadStream(stream)) + using (var reader = new BufferedReadStream(this.configuration, stream)) { for (int i = 0, o = 0; i < expected.Length / 2; i++, o += 2) { @@ -124,19 +133,19 @@ namespace SixLabors.ImageSharp.Tests.IO Assert.Equal(o + 2, reader.Position); int offset = i * 2; - if (offset < BufferedReadStream.BufferLength) + if (offset < this.bufferSize) { - Assert.Equal(stream.Position, BufferedReadStream.BufferLength); + Assert.Equal(stream.Position, this.bufferSize); } - else if (offset >= BufferedReadStream.BufferLength && offset < BufferedReadStream.BufferLength * 2) + else if (offset >= this.bufferSize && offset < this.bufferSize * 2) { // We should have advanced to the second chunk now. - Assert.Equal(stream.Position, BufferedReadStream.BufferLength * 2); + Assert.Equal(stream.Position, this.bufferSize * 2); } else { // We should have advanced to the third chunk now. - Assert.Equal(stream.Position, BufferedReadStream.BufferLength * 3); + Assert.Equal(stream.Position, this.bufferSize * 3); } } } @@ -146,11 +155,11 @@ namespace SixLabors.ImageSharp.Tests.IO [Fact] public void BufferedStreamCanReadSubsequentMultipleByteSpanCorrectly() { - using (MemoryStream stream = this.CreateTestStream()) + using (MemoryStream stream = this.CreateTestStream(this.bufferSize * 3)) { Span buffer = new byte[2]; byte[] expected = stream.ToArray(); - using (var reader = new BufferedReadStream(stream)) + using (var reader = new BufferedReadStream(this.configuration, stream)) { for (int i = 0, o = 0; i < expected.Length / 2; i++, o += 2) { @@ -160,19 +169,19 @@ namespace SixLabors.ImageSharp.Tests.IO Assert.Equal(o + 2, reader.Position); int offset = i * 2; - if (offset < BufferedReadStream.BufferLength) + if (offset < this.bufferSize) { - Assert.Equal(stream.Position, BufferedReadStream.BufferLength); + Assert.Equal(stream.Position, this.bufferSize); } - else if (offset >= BufferedReadStream.BufferLength && offset < BufferedReadStream.BufferLength * 2) + else if (offset >= this.bufferSize && offset < this.bufferSize * 2) { // We should have advanced to the second chunk now. - Assert.Equal(stream.Position, BufferedReadStream.BufferLength * 2); + Assert.Equal(stream.Position, this.bufferSize * 2); } else { // We should have advanced to the third chunk now. - Assert.Equal(stream.Position, BufferedReadStream.BufferLength * 3); + Assert.Equal(stream.Position, this.bufferSize * 3); } } } @@ -182,14 +191,14 @@ namespace SixLabors.ImageSharp.Tests.IO [Fact] public void BufferedStreamCanSkip() { - using (MemoryStream stream = this.CreateTestStream()) + using (MemoryStream stream = this.CreateTestStream(this.bufferSize * 3)) { byte[] expected = stream.ToArray(); - using (var reader = new BufferedReadStream(stream)) + using (var reader = new BufferedReadStream(this.configuration, stream)) { int skip = 50; int plusOne = 1; - int skip2 = BufferedReadStream.BufferLength; + int skip2 = this.bufferSize; // Skip reader.Skip(skip); @@ -216,18 +225,18 @@ namespace SixLabors.ImageSharp.Tests.IO public void BufferedStreamReadsSmallStream() { // Create a stream smaller than the default buffer length - using (MemoryStream stream = this.CreateTestStream(BufferedReadStream.BufferLength / 4)) + using (MemoryStream stream = this.CreateTestStream(this.bufferSize / 4)) { byte[] expected = stream.ToArray(); const int offset = 5; - using (var reader = new BufferedReadStream(stream)) + using (var reader = new BufferedReadStream(this.configuration, stream)) { reader.Position = offset; Assert.Equal(expected[offset], reader.ReadByte()); // We've read a whole length of the stream but increment by 1 in our reader. - Assert.Equal(BufferedReadStream.BufferLength / 4, stream.Position); + Assert.Equal(this.bufferSize / 4, stream.Position); Assert.Equal(offset + 1, reader.Position); } @@ -238,10 +247,10 @@ namespace SixLabors.ImageSharp.Tests.IO [Fact] public void BufferedStreamReadsCanReadAllAsSingleByteFromOrigin() { - using (MemoryStream stream = this.CreateTestStream()) + using (MemoryStream stream = this.CreateTestStream(this.bufferSize * 3)) { byte[] expected = stream.ToArray(); - using (var reader = new BufferedReadStream(stream)) + using (var reader = new BufferedReadStream(this.configuration, stream)) { for (int i = 0; i < expected.Length; i++) { @@ -251,7 +260,7 @@ namespace SixLabors.ImageSharp.Tests.IO } } - private MemoryStream CreateTestStream(int length = BufferedReadStream.BufferLength * 3) + private MemoryStream CreateTestStream(int length) { var buffer = new byte[length]; var random = new Random();