Browse Source

Make stream buffer size configurable. Fixes #1276

pull/1286/head
James Jackson-South 6 years ago
parent
commit
36b3fab2d9
  1. 24
      src/ImageSharp/Configuration.cs
  2. 8
      src/ImageSharp/Formats/Bmp/BmpDecoder.cs
  3. 8
      src/ImageSharp/Formats/Gif/GifDecoder.cs
  4. 8
      src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
  5. 8
      src/ImageSharp/Formats/Png/PngDecoder.cs
  6. 3
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  7. 8
      src/ImageSharp/Formats/Tga/TgaDecoder.cs
  8. 47
      src/ImageSharp/IO/BufferedReadStream.cs
  9. 4
      src/ImageSharp/Image.FromStream.cs
  10. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs
  11. 6
      tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs
  12. 7
      tests/ImageSharp.Tests/ConfigurationTests.cs
  13. 2
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
  14. 4
      tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs
  15. 2
      tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs
  16. 2
      tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs
  17. 87
      tests/ImageSharp.Tests/IO/BufferedReadStreamTests.cs

24
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
/// </summary>
private static readonly Lazy<Configuration> Lazy = new Lazy<Configuration>(CreateDefaultInstance);
private const int MinStreamProcessingBufferSize = 128;
private const int DefaultStreamProcessingBufferSize = 8096;
private int streamProcessingBufferSize = DefaultStreamProcessingBufferSize;
private int maxDegreeOfParallelism = Environment.ProcessorCount;
/// <summary>
@ -75,6 +77,25 @@ namespace SixLabors.ImageSharp
}
}
/// <summary>
/// Gets or sets the size of the buffer to use when working with streams.
/// Intitialized with <see cref="DefaultStreamProcessingBufferSize"/> by default
/// and can accept a minimum value of <see cref="MinStreamProcessingBufferSize"/>.
/// </summary>
public int StreamProcessingBufferSize
{
get => this.streamProcessingBufferSize;
set
{
if (value < MinStreamProcessingBufferSize)
{
value = MinStreamProcessingBufferSize;
}
this.streamProcessingBufferSize = value;
}
}
/// <summary>
/// Gets a set of properties for the Congiguration.
/// </summary>
@ -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,

8
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<TPixel>(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<TPixel>(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);
}
}

8
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<TPixel>(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<TPixel>(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);
}
}

8
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<TPixel>(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<TPixel>(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);
}

8
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<TPixel>(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<TPixel>(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<IImageInfo> 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);
}
}

3
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<byte> 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))

8
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<TPixel>(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<TPixel>(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);
}
}

47
src/ImageSharp/IO/BufferedReadStream.cs

@ -14,12 +14,7 @@ namespace SixLabors.ImageSharp.IO
/// </summary>
internal sealed class BufferedReadStream : Stream
{
/// <summary>
/// The length, in bytes, of the underlying buffer.
/// </summary>
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
/// <summary>
/// Initializes a new instance of the <see cref="BufferedReadStream"/> class.
/// </summary>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="stream">The input stream.</param>
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<byte>.Shared.Rent(BufferLength);
this.BufferSize = configuration.StreamProcessingBufferSize;
this.maxBufferIndex = this.BufferSize - 1;
this.readBuffer = ArrayPool<byte>.Shared.Rent(this.BufferSize);
this.readBufferHandle = new Memory<byte>(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;
}
/// <summary>
/// Gets the size, in bytes, of the underlying buffer.
/// </summary>
public int BufferSize
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get;
}
/// <inheritdoc/>
@ -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;
}
/// <inheritdoc/>
@ -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;
}

4
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);

2
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);

6
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);

7
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);
}
}
}

2
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);

4
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);

2
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);

2
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<InvalidImageContentException>(() => decoder.Decode<Rgb24>(null, memStream));
Assert.Throws<InvalidImageContentException>(() => decoder.Decode<Rgb24>(Configuration.Default, memStream));
Assert.Equal($"CRC Error. PNG {chunkName} chunk is corrupt!", exception.Message);
}

87
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<byte> 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();

Loading…
Cancel
Save