Browse Source

Add tests to ensure chunk order

pull/1574/head
Brian Popow 6 years ago
parent
commit
9e7cd79b37
  1. 142
      tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
  2. 4
      tests/Images/Input/Png/PngWithMetaData.png

142
tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs

@ -2,6 +2,9 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
using System;
using System.Buffers.Binary;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -18,6 +21,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
{ {
public class PngEncoderTests public class PngEncoderTests
{ {
private static PngEncoder PngEncoder => new PngEncoder();
public static readonly TheoryData<string, PngBitDepth> PngBitDepthFiles = public static readonly TheoryData<string, PngBitDepth> PngBitDepthFiles =
new TheoryData<string, PngBitDepth> new TheoryData<string, PngBitDepth>
{ {
@ -234,8 +239,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
{ {
using (Stream stream = new MemoryStream()) using (Stream stream = new MemoryStream())
{ {
var encoder = new PngEncoder(); PngEncoder.Encode(provider.GetImage(), stream);
encoder.Encode(provider.GetImage(), stream);
stream.Seek(0, SeekOrigin.Begin); stream.Seek(0, SeekOrigin.Begin);
@ -281,7 +285,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
using (Image<TPixel> image = provider.GetImage()) using (Image<TPixel> image = provider.GetImage())
using (var ms = new MemoryStream()) using (var ms = new MemoryStream())
{ {
image.Save(ms, new PngEncoder()); image.Save(ms, PngEncoder);
byte[] data = ms.ToArray().Take(8).ToArray(); byte[] data = ms.ToArray().Take(8).ToArray();
byte[] expected = byte[] expected =
@ -304,14 +308,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
[MemberData(nameof(RatioFiles))] [MemberData(nameof(RatioFiles))]
public void Encode_PreserveRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) public void Encode_PreserveRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit)
{ {
var options = new PngEncoder();
var testFile = TestFile.Create(imagePath); var testFile = TestFile.Create(imagePath);
using (Image<Rgba32> input = testFile.CreateRgba32Image()) using (Image<Rgba32> input = testFile.CreateRgba32Image())
{ {
using (var memStream = new MemoryStream()) using (var memStream = new MemoryStream())
{ {
input.Save(memStream, options); input.Save(memStream, PngEncoder);
memStream.Position = 0; memStream.Position = 0;
using (var output = Image.Load<Rgba32>(memStream)) using (var output = Image.Load<Rgba32>(memStream))
@ -329,14 +331,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
[MemberData(nameof(PngBitDepthFiles))] [MemberData(nameof(PngBitDepthFiles))]
public void Encode_PreserveBits(string imagePath, PngBitDepth pngBitDepth) public void Encode_PreserveBits(string imagePath, PngBitDepth pngBitDepth)
{ {
var options = new PngEncoder();
var testFile = TestFile.Create(imagePath); var testFile = TestFile.Create(imagePath);
using (Image<Rgba32> input = testFile.CreateRgba32Image()) using (Image<Rgba32> input = testFile.CreateRgba32Image())
{ {
using (var memStream = new MemoryStream()) using (var memStream = new MemoryStream())
{ {
input.Save(memStream, options); input.Save(memStream, PngEncoder);
memStream.Position = 0; memStream.Position = 0;
using (var output = Image.Load<Rgba32>(memStream)) using (var output = Image.Load<Rgba32>(memStream))
@ -353,8 +353,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
[MemberData(nameof(PngTrnsFiles))] [MemberData(nameof(PngTrnsFiles))]
public void Encode_PreserveTrns(string imagePath, PngBitDepth pngBitDepth, PngColorType pngColorType) public void Encode_PreserveTrns(string imagePath, PngBitDepth pngBitDepth, PngColorType pngColorType)
{ {
var options = new PngEncoder();
var testFile = TestFile.Create(imagePath); var testFile = TestFile.Create(imagePath);
using (Image<Rgba32> input = testFile.CreateRgba32Image()) using (Image<Rgba32> input = testFile.CreateRgba32Image())
{ {
@ -363,7 +361,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
using (var memStream = new MemoryStream()) using (var memStream = new MemoryStream())
{ {
input.Save(memStream, options); input.Save(memStream, PngEncoder);
memStream.Position = 0; memStream.Position = 0;
using (var output = Image.Load<Rgba32>(memStream)) using (var output = Image.Load<Rgba32>(memStream))
{ {
@ -404,6 +402,126 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
} }
} }
[Fact]
public void HeaderChunk_ComesFirst()
{
var testFile = TestFile.Create(TestImages.Png.PngWithMetadata);
using Image<Rgba32> input = testFile.CreateRgba32Image();
using var memStream = new MemoryStream();
input.Save(memStream, PngEncoder);
memStream.Position = 0;
// Skip header.
Span<byte> bytesSpan = memStream.ToArray().AsSpan(8);
BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4));
var type = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4));
Assert.Equal(PngChunkType.Header, type);
}
[Fact]
public void EndChunk_IsLast()
{
var testFile = TestFile.Create(TestImages.Png.PngWithMetadata);
using Image<Rgba32> input = testFile.CreateRgba32Image();
using var memStream = new MemoryStream();
input.Save(memStream, PngEncoder);
memStream.Position = 0;
// Skip header.
Span<byte> bytesSpan = memStream.ToArray().AsSpan(8);
bool endChunkFound = false;
while (bytesSpan.Length > 0)
{
int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4));
var type = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4));
Assert.False(endChunkFound);
if (type == PngChunkType.End)
{
endChunkFound = true;
}
bytesSpan = bytesSpan.Slice(4 + 4 + length + 4);
}
}
[Theory]
[InlineData(PngChunkType.Gamma)]
[InlineData(PngChunkType.Chroma)]
[InlineData(PngChunkType.EmbeddedColorProfile)]
[InlineData(PngChunkType.SignificantBits)]
[InlineData(PngChunkType.StandardRgbColourSpace)]
public void Chunk_ComesBeforePlteAndIDat(object chunkTypeObj)
{
var chunkType = (PngChunkType)chunkTypeObj;
var testFile = TestFile.Create(TestImages.Png.PngWithMetadata);
using Image<Rgba32> input = testFile.CreateRgba32Image();
using var memStream = new MemoryStream();
input.Save(memStream, PngEncoder);
memStream.Position = 0;
// Skip header.
Span<byte> bytesSpan = memStream.ToArray().AsSpan(8);
bool palFound = false;
bool dataFound = false;
while (bytesSpan.Length > 0)
{
int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4));
var type = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4));
if (chunkType == type)
{
Assert.False(palFound || dataFound, $"{chunkType} chunk should come before data and palette chunk");
}
switch (type)
{
case PngChunkType.Data:
dataFound = true;
break;
case PngChunkType.Palette:
palFound = true;
break;
}
bytesSpan = bytesSpan.Slice(4 + 4 + length + 4);
}
}
[Theory]
[InlineData(PngChunkType.Physical)]
[InlineData(PngChunkType.SuggestedPalette)]
public void Chunk_ComesBeforeIDat(object chunkTypeObj)
{
var chunkType = (PngChunkType)chunkTypeObj;
var testFile = TestFile.Create(TestImages.Png.PngWithMetadata);
using Image<Rgba32> input = testFile.CreateRgba32Image();
using var memStream = new MemoryStream();
input.Save(memStream, PngEncoder);
memStream.Position = 0;
// Skip header.
Span<byte> bytesSpan = memStream.ToArray().AsSpan(8);
bool dataFound = false;
while (bytesSpan.Length > 0)
{
int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4));
var type = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4));
if (chunkType == type)
{
Assert.False(dataFound, $"{chunkType} chunk should come before data chunk");
}
if (type == PngChunkType.Data)
{
dataFound = true;
}
bytesSpan = bytesSpan.Slice(4 + 4 + length + 4);
}
}
[Theory] [Theory]
[WithTestPatternImages(587, 821, PixelTypes.Rgba32)] [WithTestPatternImages(587, 821, PixelTypes.Rgba32)]
[WithTestPatternImages(677, 683, PixelTypes.Rgba32)] [WithTestPatternImages(677, 683, PixelTypes.Rgba32)]

4
tests/Images/Input/Png/PngWithMetaData.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:c92a4ea43f50a7b5f5a492991c0a619ab639c4e802bf4ae0c2433a066e8c05a7 oid sha256:a37d2d31c2148b94bfd732c8964808dcc2dcdb6d2c187bb5d0403dc09af9ab46
size 777 size 60544

Loading…
Cancel
Save