Browse Source

Add Tiff encoder Tests

pull/1570/head
Brian Popow 6 years ago
parent
commit
a7deb8b251
  1. 5
      src/ImageSharp/Formats/Tiff/TiffEncoder.cs
  2. 16
      src/ImageSharp/Formats/Tiff/TiffEncoderCompression.cs
  3. 22
      src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
  4. 2
      tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs
  5. 2
      tests/ImageSharp.Tests/Formats/Tiff/Compression/NoneTiffCompressionTests.cs
  6. 172
      tests/ImageSharp.Tests/Formats/Tiff/ImageExtensionsTest.cs
  7. 9
      tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderHeaderTests.cs
  8. 70
      tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs
  9. 63
      tests/ImageSharp.Tests/Formats/Tiff/TiffTestUtils.cs

5
src/ImageSharp/Formats/Tiff/TiffEncoder.cs

@ -19,6 +19,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// </summary>
public TiffBitsPerPixel? BitsPerPixel { get; set; }
/// <summary>
/// Gets or sets a value indicating which compression to use.
/// </summary>
public TiffEncoderCompression Compression { get; set; } = TiffEncoderCompression.None;
/// <inheritdoc/>
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>

16
src/ImageSharp/Formats/Tiff/TiffEncoderCompression.cs

@ -0,0 +1,16 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Tiff
{
/// <summary>
/// Indicates which tiff compression is used.
/// </summary>
public enum TiffEncoderCompression
{
/// <summary>
/// No compression is used.
/// </summary>
None,
}
}

22
src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs

@ -47,21 +47,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff
public TiffEncoderCore(ITiffEncoderOptions options, MemoryAllocator memoryAllocator)
{
this.memoryAllocator = memoryAllocator;
if (options.BitsPerPixel == TiffBitsPerPixel.Pixel8)
{
this.PhotometricInterpretation = TiffPhotometricInterpretation.BlackIsZero;
}
else
{
this.PhotometricInterpretation = TiffPhotometricInterpretation.Rgb;
}
}
/// <summary>
/// Gets the photometric interpretation implementation to use when encoding the image.
/// </summary>
private TiffPhotometricInterpretation PhotometricInterpretation { get; }
private TiffPhotometricInterpretation PhotometricInterpretation { get; set; }
/// <summary>
/// Gets or sets the compression implementation to use when encoding the image.
@ -85,6 +76,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
ImageMetadata metadata = image.Metadata;
TiffMetadata tiffMetadata = metadata.GetTiffMetadata();
this.bitsPerPixel ??= tiffMetadata.BitsPerPixel;
this.PhotometricInterpretation = this.bitsPerPixel == TiffBitsPerPixel.Pixel8 ? TiffPhotometricInterpretation.BlackIsZero : TiffPhotometricInterpretation.Rgb;
short bpp = (short)this.bitsPerPixel;
int bytesPerLine = 4 * (((image.Width * bpp) + 31) / 32);
@ -132,15 +124,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
// Write the image bytes to the steam.
var imageDataStart = (uint)writer.Position;
int imageDataBytes;
if (this.PhotometricInterpretation == TiffPhotometricInterpretation.Rgb)
{
imageDataBytes = writer.WriteRgbImageData(image, this.padding);
}
else
{
imageDataBytes = writer.WriteGrayImageData(image, this.padding);
}
int imageDataBytes = this.PhotometricInterpretation == TiffPhotometricInterpretation.Rgb ? writer.WriteRgbImageData(image, this.padding) : writer.WriteGrayImageData(image, this.padding);
// Write info's about the image to the stream.
this.AddImageFormat(image, ifdEntries, imageDataStart, imageDataBytes);

2
tests/ImageSharp.Tests/Formats/Tiff/Compression/LzwTiffCompressionTests.cs

@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
{
using (Stream stream = CreateCompressedStream(data))
{
byte[] buffer = new byte[data.Length];
var buffer = new byte[data.Length];
new LzwTiffCompression(Configuration.Default.MemoryAllocator).Decompress(stream, (int)stream.Length, buffer);

2
tests/ImageSharp.Tests/Formats/Tiff/Compression/NoneTiffCompressionTests.cs

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
public void Decompress_ReadsData(byte[] inputData, int byteCount, byte[] expectedResult)
{
Stream stream = new MemoryStream(inputData);
byte[] buffer = new byte[expectedResult.Length];
var buffer = new byte[expectedResult.Length];
new NoneTiffCompression(null).Decompress(stream, byteCount, buffer);

172
tests/ImageSharp.Tests/Formats/Tiff/ImageExtensionsTest.cs

@ -1,172 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.IO;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.Tiff
{
[Trait("Category", "Tiff.BlackBox.Encoder")]
[Trait("Category", "Tiff")]
public class ImageExtensionsTest
{
[Theory]
[WithFile(TestImages.Tiff.RgbUncompressed, PixelTypes.Rgba32)]
public void ThrowsSavingNotImplemented<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
Assert.Throws<NotImplementedException>(() =>
{
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsTiff_Path.tiff");
using var image = provider.GetImage(new TiffDecoder());
image.SaveAsTiff(file);
});
}
[Fact(Skip = "Saving not implemented")]
public void SaveAsTiff_Path()
{
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsTiff_Path.tiff");
using (var image = new Image<Rgba32>(10, 10))
{
image.SaveAsTiff(file);
}
using (Image.Load(file, out IImageFormat mime))
{
Assert.Equal("image/tiff", mime.DefaultMimeType);
}
}
[Fact(Skip = "Saving not implemented")]
public async Task SaveAsTiffAsync_Path()
{
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensionsTest));
string file = Path.Combine(dir, "SaveAsTiffAsync_Path.tiff");
using (var image = new Image<Rgba32>(10, 10))
{
await image.SaveAsTiffAsync(file);
}
using (Image.Load(file, out IImageFormat mime))
{
Assert.Equal("image/tiff", mime.DefaultMimeType);
}
}
[Fact(Skip = "Saving not implemented")]
public void SaveAsTiff_Path_Encoder()
{
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsTiff_Path_Encoder.tiff");
using (var image = new Image<Rgba32>(10, 10))
{
image.SaveAsTiff(file, new TiffEncoder());
}
using (Image.Load(file, out IImageFormat mime))
{
Assert.Equal("image/tiff", mime.DefaultMimeType);
}
}
[Fact(Skip = "Saving not implemented")]
public async Task SaveAsTiffAsync_Path_Encoder()
{
string dir = TestEnvironment.CreateOutputDirectory(nameof(ImageExtensions));
string file = Path.Combine(dir, "SaveAsTiffAsync_Path_Encoder.tiff");
using (var image = new Image<Rgba32>(10, 10))
{
await image.SaveAsTiffAsync(file, new TiffEncoder());
}
using (Image.Load(file, out IImageFormat mime))
{
Assert.Equal("image/tiff", mime.DefaultMimeType);
}
}
[Fact(Skip = "Saving not implemented")]
public void SaveAsTiff_Stream()
{
using var memoryStream = new MemoryStream();
using (var image = new Image<Rgba32>(10, 10))
{
image.SaveAsTiff(memoryStream);
}
memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime))
{
Assert.Equal("image/tiff", mime.DefaultMimeType);
}
}
[Fact(Skip = "Saving not implemented")]
public async Task SaveAsTiffAsync_StreamAsync()
{
using var memoryStream = new MemoryStream();
using (var image = new Image<Rgba32>(10, 10))
{
await image.SaveAsTiffAsync(memoryStream);
}
memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime))
{
Assert.Equal("image/tiff", mime.DefaultMimeType);
}
}
[Fact(Skip = "Saving not implemented")]
public void SaveAsTiff_Stream_Encoder()
{
using var memoryStream = new MemoryStream();
using (var image = new Image<Rgba32>(10, 10))
{
image.SaveAsTiff(memoryStream, new TiffEncoder());
}
memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime))
{
Assert.Equal("image/tiff", mime.DefaultMimeType);
}
}
[Fact(Skip = "Saving not implemented")]
public async Task SaveAsTiffAsync_Stream_Encoder()
{
using var memoryStream = new MemoryStream();
using (var image = new Image<Rgba32>(10, 10))
{
await image.SaveAsTiffAsync(memoryStream, new TiffEncoder());
}
memoryStream.Position = 0;
using (Image.Load(memoryStream, out IImageFormat mime))
{
Assert.Equal("image/tiff", mime.DefaultMimeType);
}
}
}
}

9
tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderHeaderTests.cs

@ -13,12 +13,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
{
private static readonly MemoryAllocator MemoryAllocator = new ArrayPoolMemoryAllocator();
private static readonly Configuration Configuration = Configuration.Default;
private static readonly ITiffEncoderOptions Options = new TiffEncoder();
[Fact]
public void WriteHeader_WritesValidHeader()
{
var stream = new MemoryStream();
var encoder = new TiffEncoderCore(null, MemoryAllocator);
using var stream = new MemoryStream();
var encoder = new TiffEncoderCore(Options, MemoryAllocator);
using (var writer = new TiffWriter(stream, MemoryAllocator, Configuration))
{
@ -31,8 +32,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tiff
[Fact]
public void WriteHeader_ReturnsFirstIfdMarker()
{
var stream = new MemoryStream();
var encoder = new TiffEncoderCore(null, MemoryAllocator);
using var stream = new MemoryStream();
var encoder = new TiffEncoderCore(Options, MemoryAllocator);
using (var writer = new TiffWriter(stream, MemoryAllocator, Configuration))
{

70
tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderTests.cs

@ -0,0 +1,70 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System.IO;
using SixLabors.ImageSharp.Formats.Tiff;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.Tiff
{
public class TiffEncoderTests
{
public static readonly TheoryData<string, TiffBitsPerPixel> TiffBitsPerPixelFiles =
new TheoryData<string, TiffBitsPerPixel>
{
{ TestImages.Tiff.GrayscaleUncompressed, TiffBitsPerPixel.Pixel8 },
{ TestImages.Tiff.RgbUncompressed, TiffBitsPerPixel.Pixel24 },
};
[Theory]
[MemberData(nameof(TiffBitsPerPixelFiles))]
public void TiffEncoder_PreserveBitsPerPixel(string imagePath, TiffBitsPerPixel expectedBitsPerPixel)
{
// arrange
var tiffEncoder = new TiffEncoder();
var testFile = TestFile.Create(imagePath);
using Image<Rgba32> input = testFile.CreateRgba32Image();
using var memStream = new MemoryStream();
// act
input.Save(memStream, tiffEncoder);
// assert
memStream.Position = 0;
using var output = Image.Load<Rgba32>(memStream);
TiffMetadata meta = output.Metadata.GetTiffMetadata();
Assert.Equal(expectedBitsPerPixel, meta.BitsPerPixel);
}
[Theory]
[WithFile(TestImages.Tiff.RgbUncompressed, PixelTypes.Rgba32)]
public void TiffEncoder_EncodeRgb_Works<TPixel>(TestImageProvider<TPixel> provider, TiffBitsPerPixel bitsPerPixel = TiffBitsPerPixel.Pixel24)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffEncoderCore(provider, bitsPerPixel);
[Theory]
[WithFile(TestImages.Tiff.RgbUncompressed, PixelTypes.Rgba32)]
public void TiffEncoder_EncodeGray_Works<TPixel>(TestImageProvider<TPixel> provider, TiffBitsPerPixel bitsPerPixel = TiffBitsPerPixel.Pixel8)
where TPixel : unmanaged, IPixel<TPixel> => TestTiffEncoderCore(provider, bitsPerPixel);
private static void TestTiffEncoderCore<TPixel>(
TestImageProvider<TPixel> provider,
TiffBitsPerPixel bitsPerPixel,
TiffEncoderCompression compression = TiffEncoderCompression.None,
bool useExactComparer = true,
float compareTolerance = 0.01f)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();
var encoder = new TiffEncoder { BitsPerPixel = bitsPerPixel, Compression = compression };
using var memStream = new MemoryStream();
image.Save(memStream, encoder);
memStream.Position = 0;
using var encodedImage = (Image<TPixel>)Image.Load(memStream);
TiffTestUtils.CompareWithReferenceDecoder(provider, encodedImage, useExactComparer, compareTolerance);
}
}
}

63
tests/ImageSharp.Tests/Formats/Tiff/TiffTestUtils.cs

@ -0,0 +1,63 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.IO;
using ImageMagick;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.Tiff
{
public class TiffTestUtils
{
public static void CompareWithReferenceDecoder<TPixel>(
TestImageProvider<TPixel> provider,
Image<TPixel> image,
bool useExactComparer = true,
float compareTolerance = 0.01f)
where TPixel : unmanaged, ImageSharp.PixelFormats.IPixel<TPixel>
{
string path = TestImageProvider<TPixel>.GetFilePathOrNull(provider);
if (path == null)
{
throw new InvalidOperationException("CompareToOriginal() works only with file providers!");
}
var testFile = TestFile.Create(path);
Image<Rgba32> magickImage = DecodeWithMagick<Rgba32>(Configuration.Default, new FileInfo(testFile.FullPath));
if (useExactComparer)
{
ImageComparer.Exact.VerifySimilarity(magickImage, image);
}
else
{
ImageComparer.Tolerant(compareTolerance).VerifySimilarity(magickImage, image);
}
}
public static Image<TPixel> DecodeWithMagick<TPixel>(Configuration configuration, FileInfo fileInfo)
where TPixel : unmanaged, ImageSharp.PixelFormats.IPixel<TPixel>
{
using var magickImage = new MagickImage(fileInfo);
magickImage.AutoOrient();
var result = new Image<TPixel>(configuration, magickImage.Width, magickImage.Height);
Assert.True(result.TryGetSinglePixelSpan(out Span<TPixel> resultPixels));
using IUnsafePixelCollection<ushort> pixels = magickImage.GetPixelsUnsafe();
byte[] data = pixels.ToByteArray(PixelMapping.RGBA);
PixelOperations<TPixel>.Instance.FromRgba32Bytes(
configuration,
data,
resultPixels,
resultPixels.Length);
return result;
}
}
}
Loading…
Cancel
Save