Browse Source

Merge branch 'main' into js/encoder-normalization

pull/2269/head
James Jackson-South 3 years ago
committed by GitHub
parent
commit
ebdf5c80cc
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 28
      src/ImageSharp/IO/BufferedReadStream.cs
  2. 16
      src/ImageSharp/Image.FromStream.cs
  3. 42
      tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs
  4. 3
      tests/ImageSharp.Tests/TestImages.cs
  5. 3
      tests/Images/Input/Png/issues/Issue_2259.png

28
src/ImageSharp/IO/BufferedReadStream.cs

@ -60,7 +60,7 @@ internal sealed class BufferedReadStream : Stream
}
// This triggers a full read on first attempt.
this.readBufferIndex = this.BufferSize;
this.readBufferIndex = int.MinValue;
}
/// <summary>
@ -96,8 +96,9 @@ internal sealed class BufferedReadStream : Stream
else
{
// Base stream seek will throw for us if invalid.
this.BaseStream.Seek(value, SeekOrigin.Begin);
this.readerPosition = value;
this.FillReadBuffer();
this.readBufferIndex = int.MinValue;
}
}
}
@ -140,7 +141,7 @@ internal sealed class BufferedReadStream : Stream
// Our buffer has been read.
// We need to refill and start again.
if (this.readBufferIndex > this.maxBufferIndex)
if ((uint)this.readBufferIndex > (uint)this.maxBufferIndex)
{
this.FillReadBuffer();
}
@ -156,22 +157,7 @@ internal sealed class BufferedReadStream : Stream
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int Read(byte[] buffer, int offset, int count)
{
// Too big for our buffer. Read directly from the stream.
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 > this.BufferSize)
{
return this.ReadToBufferViaCopySlow(buffer, offset, count);
}
return this.ReadToBufferViaCopyFast(buffer, offset, count);
}
=> this.Read(buffer.AsSpan(offset, count));
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -186,7 +172,7 @@ internal sealed class BufferedReadStream : Stream
// Too big for remaining buffer but less than entire buffer length
// Copy to buffer then read from there.
if (count + this.readBufferIndex > this.BufferSize)
if ((uint)this.readBufferIndex > (uint)(this.BufferSize - count))
{
return this.ReadToBufferViaCopySlow(buffer);
}
@ -206,7 +192,7 @@ internal sealed class BufferedReadStream : Stream
}
// Reset to trigger full read on next attempt.
this.readBufferIndex = this.BufferSize;
this.readBufferIndex = int.MinValue;
}
/// <inheritdoc/>

16
src/ImageSharp/Image.FromStream.cs

@ -517,6 +517,7 @@ public abstract partial class Image
/// <param name="stream">The input stream.</param>
/// <param name="action">The action to perform.</param>
/// <returns>The <typeparamref name="T"/>.</returns>
/// <exception cref="NotSupportedException">Cannot read from the stream.</exception>
internal static T WithSeekableStream<T>(
DecoderOptions options,
Stream stream,
@ -587,7 +588,20 @@ public abstract partial class Image
await stream.CopyToAsync(memoryStream, configuration.StreamProcessingBufferSize, cancellationToken).ConfigureAwait(false);
memoryStream.Position = 0;
return action(memoryStream, cancellationToken);
T Action(Stream ms, CancellationToken ct)
{
// Reset the position of the seekable stream if we did not read to the end
// to allow additional reads.
T result = action(ms, ct);
if (stream.CanSeek && ms.Position != ms.Length)
{
stream.Position = ms.Position;
}
return result;
}
return Action(memoryStream, cancellationToken);
}
[DoesNotReturn]

42
tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs

@ -46,6 +46,36 @@ public class GeneralFormatTests
image.DebugSave(provider);
}
[Fact]
public void ReadOriginIsRespectedOnLoad()
{
using FileStream stream = File.OpenRead(TestFile.GetInputFileFullPath(TestImages.Png.Issue2259));
using Image<Rgb24> i = Image.Load<Rgb24>(stream);
long position1 = stream.Position;
Assert.NotEqual(0, position1);
using Image<Rgb24> j = Image.Load<Rgb24>(stream);
long position2 = stream.Position;
Assert.True(position2 > position1);
Assert.NotEqual(i[5, 5], j[5, 5]);
}
[Fact]
public async Task ReadOriginIsRespectedOnLoadAsync()
{
using FileStream stream = File.OpenRead(TestFile.GetInputFileFullPath(TestImages.Png.Issue2259));
using Image<Rgb24> i = await Image.LoadAsync<Rgb24>(stream);
long position1 = stream.Position;
Assert.NotEqual(0, position1);
using Image<Rgb24> j = await Image.LoadAsync<Rgb24>(stream);
long position2 = stream.Position;
Assert.True(position2 > position1);
Assert.NotEqual(i[5, 5], j[5, 5]);
}
[Fact]
public void ImageCanEncodeToString()
{
@ -155,15 +185,15 @@ public class GeneralFormatTests
foreach (TestFile file in Files)
{
byte[] serialized;
using (var image = Image.Load(file.Bytes, out IImageFormat mimeType))
using (var memoryStream = new MemoryStream())
using (Image image = Image.Load(file.Bytes, out IImageFormat mimeType))
using (MemoryStream memoryStream = new())
{
image.Save(memoryStream, mimeType);
memoryStream.Flush();
serialized = memoryStream.ToArray();
}
using var image2 = Image.Load<Rgba32>(serialized);
using Image<Rgba32> image2 = Image.Load<Rgba32>(serialized);
image2.Save($"{path}{Path.DirectorySeparatorChar}{file.FileName}");
}
}
@ -198,8 +228,8 @@ public class GeneralFormatTests
public void CanIdentifyImageLoadedFromBytes(int width, int height, string extension)
{
using var image = Image.LoadPixelData<Rgba32>(new Rgba32[width * height], width, height);
using var memoryStream = new MemoryStream();
using Image<Rgba32> image = Image.LoadPixelData<Rgba32>(new Rgba32[width * height], width, height);
using MemoryStream memoryStream = new();
IImageFormat format = GetFormat(extension);
image.Save(memoryStream, format);
memoryStream.Position = 0;
@ -220,7 +250,7 @@ public class GeneralFormatTests
{
byte[] invalid = new byte[10];
using var memoryStream = new MemoryStream(invalid);
using MemoryStream memoryStream = new(invalid);
IImageInfo imageInfo = Image.Identify(memoryStream, out IImageFormat format);
Assert.Null(imageInfo);

3
tests/ImageSharp.Tests/TestImages.cs

@ -130,6 +130,9 @@ public static class TestImages
// Issue 2209: https://github.com/SixLabors/ImageSharp/issues/2209
public const string Issue2209IndexedWithTransparency = "Png/issues/Issue_2209.png";
// Issue 2259: https://github.com/SixLabors/ImageSharp/issues/2259
public const string Issue2259 = "Png/issues/Issue_2259.png";
public static class Bad
{
public const string MissingDataChunk = "Png/xdtn0g01.png";

3
tests/Images/Input/Png/issues/Issue_2259.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:45b635fe3104e96b7c6d8fa9d28f7fb86fb184c7a407c44a2f90f3f88c140ef0
size 6037
Loading…
Cancel
Save