Browse Source

Add TIFF IFD encoding

pull/119/head
Andrew Wilkinson 9 years ago
parent
commit
dfaa4cf835
  1. 5
      src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs
  2. 88
      src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
  3. 109
      src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs
  4. 33
      tests/ImageSharp.Formats.Tiff.Tests/Formats/Tiff/TiffEncoderHeaderTests.cs
  5. 299
      tests/ImageSharp.Formats.Tiff.Tests/Formats/Tiff/TiffEncoderIfdTests.cs
  6. 135
      tests/ImageSharp.Formats.Tiff.Tests/Formats/Tiff/Utils/TiffWriterTests.cs

5
src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs

@ -69,10 +69,5 @@ namespace ImageSharp.Formats.Tiff
/// Size (in bytes) of the Double data type
/// </summary>
public const int SizeOfDouble = 8;
/// <summary>
/// Size (in bytes) of the word boundary to allign data to when required
/// </summary>
public const int SizeOfWordBoundary = 4;
}
}

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

@ -7,6 +7,7 @@ namespace ImageSharp.Formats
{
using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
@ -50,30 +51,95 @@ namespace ImageSharp.Formats
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
using (BinaryWriter writer = new BinaryWriter(stream, Encoding.UTF8, true))
using (TiffWriter writer = new TiffWriter(stream))
{
this.WriteHeader(writer, 0);
long firstIfdMarker = this.WriteHeader(writer);
long nextIfdMarker = this.WriteImage(writer, image, firstIfdMarker);
}
}
/// <summary>
/// Writes the TIFF file header.
/// </summary>
/// <param name="writer">The <see cref="BinaryWriter"/> to write data to.</param>
/// <param name="firstIfdOffset">The byte offset to the first IFD in the file.</param>
public void WriteHeader(BinaryWriter writer, uint firstIfdOffset)
/// <param name="writer">The <see cref="TiffWriter"/> to write data to.</param>
/// <returns>The marker to write the first IFD offset.</returns>
public long WriteHeader(TiffWriter writer)
{
if (firstIfdOffset == 0 || firstIfdOffset % TiffConstants.SizeOfWordBoundary != 0)
{
throw new ArgumentException("IFD offsets must be non-zero and on a word boundary.", nameof(firstIfdOffset));
}
ushort byteOrderMarker = BitConverter.IsLittleEndian ? TiffConstants.ByteOrderLittleEndianShort
: TiffConstants.ByteOrderBigEndianShort;
writer.Write(byteOrderMarker);
writer.Write((ushort)42);
writer.Write(firstIfdOffset);
long firstIfdMarker = writer.PlaceMarker();
return firstIfdMarker;
}
/// <summary>
/// Writes a TIFF IFD block.
/// </summary>
/// <param name="writer">The <see cref="BinaryWriter"/> to write data to.</param>
/// <param name="entries">The IFD entries to write to the file.</param>
/// <returns>The marker to write the next IFD offset (if present).</returns>
public long WriteIfd(TiffWriter writer, List<TiffIfdEntry> entries)
{
if (entries.Count == 0)
{
throw new ArgumentException("There must be at least one entry per IFD.", nameof(entries));
}
uint dataOffset = (uint)writer.Position + (uint)(6 + (entries.Count * 12));
List<byte[]> largeDataBlocks = new List<byte[]>();
entries.Sort((a, b) => a.Tag - b.Tag);
writer.Write((ushort)entries.Count);
foreach (TiffIfdEntry entry in entries)
{
writer.Write(entry.Tag);
writer.Write((ushort)entry.Type);
writer.Write(entry.Count);
if (entry.Value.Length <= 4)
{
writer.WritePadded(entry.Value);
}
else
{
largeDataBlocks.Add(entry.Value);
writer.Write(dataOffset);
dataOffset += (uint)(entry.Value.Length + (entry.Value.Length % 2));
}
}
long nextIfdMarker = writer.PlaceMarker();
foreach (byte[] dataBlock in largeDataBlocks)
{
writer.Write(dataBlock);
if (dataBlock.Length % 2 == 1)
{
writer.Write((byte)0);
}
}
return nextIfdMarker;
}
/// <summary>
/// Writes all data required to define an image
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="writer">The <see cref="BinaryWriter"/> to write data to.</param>
/// <param name="image">The <see cref="ImageBase{TPixel}"/> to encode from.</param>
/// <param name="ifdOffset">The marker to write this IFD offset.</param>
/// <returns>The marker to write the next IFD offset (if present).</returns>
public long WriteImage<TPixel>(TiffWriter writer, Image<TPixel> image, long ifdOffset)
where TPixel : struct, IPixel<TPixel>
{
throw new NotImplementedException();
}
}
}

109
src/ImageSharp/Formats/Tiff/Utils/TiffWriter.cs

@ -0,0 +1,109 @@
// <copyright file="TiffWriter.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats.Tiff
{
using System;
using System.Collections.Generic;
using System.IO;
/// <summary>
/// Utility class for writing TIFF data to a <see cref="Stream"/>.
/// </summary>
internal class TiffWriter : IDisposable
{
private readonly Stream output;
private readonly byte[] paddingBytes = new byte[4];
private readonly List<long> references = new List<long>();
/// <summary>Initializes a new instance of the <see cref="TiffWriter"/> class.</summary>
/// <param name="output">The output stream.</param>
public TiffWriter(Stream output)
{
this.output = output;
}
/// <summary>
/// Gets a flag indicating whether the architecture is little-endian.
/// </summary>
public bool IsLittleEndian => BitConverter.IsLittleEndian;
/// <summary>
/// Returns the current position within the stream.
/// </summary>
public long Position => this.output.Position;
/// <summary>Writes an empty four bytes to the stream, returning the offset to be written later.</summary>
/// <returns>The offset to be written later</returns>
public long PlaceMarker()
{
long offset = this.output.Position;
this.Write(0u);
return offset;
}
/// <summary>Writes an array of bytes to the current stream.</summary>
/// <param name="value">The bytes to write.</param>
public void Write(byte[] value)
{
this.output.Write(value, 0, value.Length);
}
/// <summary>Writes a byte to the current stream.</summary>
/// <param name="value">The byte to write.</param>
public void Write(byte value)
{
this.output.Write(new byte[] { value }, 0, 1);
}
/// <summary>Writes a two-byte unsigned integer to the current stream.</summary>
/// <param name="value">The two-byte unsigned integer to write.</param>
public void Write(ushort value)
{
byte[] bytes = BitConverter.GetBytes(value);
this.output.Write(bytes, 0, 2);
}
/// <summary>Writes a four-byte unsigned integer to the current stream.</summary>
/// <param name="value">The four-byte unsigned integer to write.</param>
public void Write(uint value)
{
byte[] bytes = BitConverter.GetBytes(value);
this.output.Write(bytes, 0, 4);
}
/// <summary>Writes an array of bytes to the current stream, padded to four-bytes.</summary>
/// <param name="value">The bytes to write.</param>
public void WritePadded(byte[] value)
{
this.output.Write(value, 0, value.Length);
if (value.Length < 4)
{
this.output.Write(this.paddingBytes, 0, 4 - value.Length);
}
}
/// <summary>Writes a four-byte unsigned integer to the specified marker in the stream.</summary>
/// <param name="offset">The offset returned when placing the marker</param>
/// <param name="value">The four-byte unsigned integer to write.</param>
public void WriteMarker(long offset, uint value)
{
long currentOffset = this.output.Position;
this.output.Seek(offset, SeekOrigin.Begin);
this.Write(value);
this.output.Seek(currentOffset, SeekOrigin.Begin);
}
/// <summary>
/// Disposes <see cref="TiffWriter"/> instance, ensuring any unwritten data is flushed.
/// </summary>
public void Dispose()
{
this.output.Flush();
}
}
}

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

@ -7,9 +7,11 @@ namespace ImageSharp.Tests
{
using System;
using System.IO;
using System.Linq;
using Xunit;
using ImageSharp.Formats;
using ImageSharp.Formats.Tiff;
using System.Text;
public class TiffEncoderHeaderTests
@ -20,41 +22,24 @@ namespace ImageSharp.Tests
MemoryStream stream = new MemoryStream();
TiffEncoderCore encoder = new TiffEncoderCore(null);
using (BinaryWriter writer = new BinaryWriter(stream, Encoding.UTF8, true))
using (TiffWriter writer = new TiffWriter(stream))
{
encoder.WriteHeader(writer, 1232);
long firstIfdMarker = encoder.WriteHeader(writer);
}
stream.Position = 0;
Assert.Equal(8, stream.Length);
Assert.Equal(new byte[] { 0x49, 0x49, 42, 0, 0xD0, 0x04, 0x00, 0x00 }, stream.ToArray());
Assert.Equal(new byte[] { 0x49, 0x49, 42, 0, 0x00, 0x00, 0x00, 0x00 }, stream.ToArray());
}
[Fact]
public void WriteHeader_ThrowsExceptionIfFirstIfdOffsetIsZero()
public void WriteHeader_ReturnsFirstIfdMarker()
{
MemoryStream stream = new MemoryStream();
TiffEncoderCore encoder = new TiffEncoderCore(null);
using (BinaryWriter writer = new BinaryWriter(stream, Encoding.UTF8, true))
using (TiffWriter writer = new TiffWriter(stream))
{
ArgumentException e = Assert.Throws<ArgumentException>(() => { encoder.WriteHeader(writer, 0); });
Assert.Equal("IFD offsets must be non-zero and on a word boundary.\r\nParameter name: firstIfdOffset", e.Message);
Assert.Equal("firstIfdOffset", e.ParamName);
}
}
[Fact]
public void WriteHeader_ThrowsExceptionIfIfdOffsetIsNotOnAWordBoundary()
{
MemoryStream stream = new MemoryStream();
TiffEncoderCore encoder = new TiffEncoderCore(null);
using (BinaryWriter writer = new BinaryWriter(stream, Encoding.UTF8, true))
{
ArgumentException e = Assert.Throws<ArgumentException>(() => { encoder.WriteHeader(writer, 1234); });
Assert.Equal("IFD offsets must be non-zero and on a word boundary.\r\nParameter name: firstIfdOffset", e.Message);
Assert.Equal("firstIfdOffset", e.ParamName);
long firstIfdMarker = encoder.WriteHeader(writer);
Assert.Equal(4, firstIfdMarker);
}
}
}

299
tests/ImageSharp.Formats.Tiff.Tests/Formats/Tiff/TiffEncoderIfdTests.cs

@ -0,0 +1,299 @@
// <copyright file="TiffEncoderIfdTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Tests
{
using System;
using System.IO;
using System.Linq;
using Xunit;
using ImageSharp.Formats;
using ImageSharp.Formats.Tiff;
using System.Text;
using System.Collections.Generic;
public class TiffEncoderIfdTests
{
[Fact]
public void WriteIfd_DataIsCorrectLength()
{
MemoryStream stream = new MemoryStream();
TiffEncoderCore encoder = new TiffEncoderCore(null);
List<TiffIfdEntry> entries = new List<TiffIfdEntry>()
{
new TiffIfdEntry(TiffTags.ImageWidth, TiffType.Long, 1, new byte[] { 1, 2, 3, 4 }),
new TiffIfdEntry(TiffTags.ImageLength, TiffType.Long, 1, new byte[] { 5, 6, 7, 8 }),
new TiffIfdEntry(TiffTags.Compression, TiffType.Long, 1, new byte[] { 9, 10, 11, 12 })
};
using (TiffWriter writer = new TiffWriter(stream))
{
long nextIfdMarker = encoder.WriteIfd(writer, entries);
}
Assert.Equal(2 + 12 * 3 + 4, stream.Length);
}
[Fact]
public void WriteIfd_WritesNumberOfEntries()
{
MemoryStream stream = new MemoryStream();
TiffEncoderCore encoder = new TiffEncoderCore(null);
List<TiffIfdEntry> entries = new List<TiffIfdEntry>()
{
new TiffIfdEntry(TiffTags.ImageWidth, TiffType.Long, 1, new byte[] { 1, 2, 3, 4 }),
new TiffIfdEntry(TiffTags.ImageLength, TiffType.Long, 1, new byte[] { 5, 6, 7, 8 }),
new TiffIfdEntry(TiffTags.Compression, TiffType.Long, 1, new byte[] { 9, 10, 11, 12 })
};
using (TiffWriter writer = new TiffWriter(stream))
{
long nextIfdMarker = encoder.WriteIfd(writer, entries);
}
var ifdEntryBytes = stream.ToArray().Take(2).ToArray();
Assert.Equal(new byte[] { 3, 0 }, ifdEntryBytes);
}
[Fact]
public void WriteIfd_ReturnsNextIfdMarker()
{
MemoryStream stream = new MemoryStream();
TiffEncoderCore encoder = new TiffEncoderCore(null);
List<TiffIfdEntry> entries = new List<TiffIfdEntry>()
{
new TiffIfdEntry(TiffTags.ImageWidth, TiffType.Long, 1, new byte[] { 1, 2, 3, 4 }),
new TiffIfdEntry(TiffTags.ImageLength, TiffType.Long, 1, new byte[] { 5, 6, 7, 8 }),
new TiffIfdEntry(TiffTags.Compression, TiffType.Long, 1, new byte[] { 9, 10, 11, 12 })
};
using (TiffWriter writer = new TiffWriter(stream))
{
long nextIfdMarker = encoder.WriteIfd(writer, entries);
Assert.Equal(2 + 12 * 3, nextIfdMarker);
}
}
[Fact]
public void WriteIfd_WritesTagIdForEachEntry()
{
MemoryStream stream = new MemoryStream();
TiffEncoderCore encoder = new TiffEncoderCore(null);
List<TiffIfdEntry> entries = new List<TiffIfdEntry>()
{
new TiffIfdEntry(10, TiffType.Long, 1, new byte[] { 1, 2, 3, 4 }),
new TiffIfdEntry(20, TiffType.Long, 1, new byte[] { 5, 6, 7, 8 }),
new TiffIfdEntry(30, TiffType.Long, 1, new byte[] { 9, 10, 11, 12 })
};
using (TiffWriter writer = new TiffWriter(stream))
{
long nextIfdMarker = encoder.WriteIfd(writer, entries);
}
var ifdEntry1Bytes = stream.ToArray().Skip(2 + 12 * 0).Take(2).ToArray();
var ifdEntry2Bytes = stream.ToArray().Skip(2 + 12 * 1).Take(2).ToArray();
var ifdEntry3Bytes = stream.ToArray().Skip(2 + 12 * 2).Take(2).ToArray();
Assert.Equal(new byte[] { 10, 0 }, ifdEntry1Bytes);
Assert.Equal(new byte[] { 20, 0 }, ifdEntry2Bytes);
Assert.Equal(new byte[] { 30, 0 }, ifdEntry3Bytes);
}
[Fact]
public void WriteIfd_WritesTypeForEachEntry()
{
MemoryStream stream = new MemoryStream();
TiffEncoderCore encoder = new TiffEncoderCore(null);
List<TiffIfdEntry> entries = new List<TiffIfdEntry>()
{
new TiffIfdEntry(TiffTags.ImageWidth, TiffType.Long, 1, new byte[] { 1, 2, 3, 4 }),
new TiffIfdEntry(TiffTags.ImageLength, TiffType.Short, 2, new byte[] { 5, 6, 7, 8 }),
new TiffIfdEntry(TiffTags.Compression, TiffType.Ascii, 4, new byte[] { (byte)'A', (byte)'B', (byte)'C', 0 })
};
using (TiffWriter writer = new TiffWriter(stream))
{
long nextIfdMarker = encoder.WriteIfd(writer, entries);
}
var ifdEntry1Bytes = stream.ToArray().Skip(4 + 12 * 0).Take(2).ToArray();
var ifdEntry2Bytes = stream.ToArray().Skip(4 + 12 * 1).Take(2).ToArray();
var ifdEntry3Bytes = stream.ToArray().Skip(4 + 12 * 2).Take(2).ToArray();
Assert.Equal(new byte[] { 4, 0 }, ifdEntry1Bytes);
Assert.Equal(new byte[] { 3, 0 }, ifdEntry2Bytes);
Assert.Equal(new byte[] { 2, 0 }, ifdEntry3Bytes);
}
[Fact]
public void WriteIfd_WritesCountForEachEntry()
{
MemoryStream stream = new MemoryStream();
TiffEncoderCore encoder = new TiffEncoderCore(null);
List<TiffIfdEntry> entries = new List<TiffIfdEntry>()
{
new TiffIfdEntry(TiffTags.ImageWidth, TiffType.Long, 1, new byte[] { 1, 2, 3, 4 }),
new TiffIfdEntry(TiffTags.ImageLength, TiffType.Short, 2, new byte[] { 5, 6, 7, 8 }),
new TiffIfdEntry(TiffTags.Compression, TiffType.Ascii, 4, new byte[] { (byte)'A', (byte)'B', (byte)'C', 0 })
};
using (TiffWriter writer = new TiffWriter(stream))
{
long nextIfdMarker = encoder.WriteIfd(writer, entries);
}
var ifdEntry1Bytes = stream.ToArray().Skip(6 + 12 * 0).Take(4).ToArray();
var ifdEntry2Bytes = stream.ToArray().Skip(6 + 12 * 1).Take(4).ToArray();
var ifdEntry3Bytes = stream.ToArray().Skip(6 + 12 * 2).Take(4).ToArray();
Assert.Equal(new byte[] { 1, 0, 0, 0 }, ifdEntry1Bytes);
Assert.Equal(new byte[] { 2, 0, 0, 0 }, ifdEntry2Bytes);
Assert.Equal(new byte[] { 4, 0, 0, 0 }, ifdEntry3Bytes);
}
[Fact]
public void WriteIfd_WritesDataInline()
{
MemoryStream stream = new MemoryStream();
TiffEncoderCore encoder = new TiffEncoderCore(null);
List<TiffIfdEntry> entries = new List<TiffIfdEntry>()
{
new TiffIfdEntry(TiffTags.ImageWidth, TiffType.Long, 1, new byte[] { 1, 2, 3, 4 }),
new TiffIfdEntry(TiffTags.ImageLength, TiffType.Short, 2, new byte[] { 5, 6, 7, 8 }),
new TiffIfdEntry(TiffTags.Compression, TiffType.Ascii, 3, new byte[] { (byte)'A', (byte)'B', 0 })
};
using (TiffWriter writer = new TiffWriter(stream))
{
long nextIfdMarker = encoder.WriteIfd(writer, entries);
}
var ifdEntry1Bytes = stream.ToArray().Skip(10 + 12 * 0).Take(4).ToArray();
var ifdEntry2Bytes = stream.ToArray().Skip(10 + 12 * 1).Take(4).ToArray();
var ifdEntry3Bytes = stream.ToArray().Skip(10 + 12 * 2).Take(4).ToArray();
Assert.Equal(new byte[] { 1, 2, 3, 4 }, ifdEntry1Bytes);
Assert.Equal(new byte[] { 5, 6, 7, 8 }, ifdEntry2Bytes);
Assert.Equal(new byte[] { (byte)'A', (byte)'B', 0, 0 }, ifdEntry3Bytes);
}
[Fact]
public void WriteIfd_WritesDataByReference()
{
MemoryStream stream = new MemoryStream();
TiffEncoderCore encoder = new TiffEncoderCore(null);
List<TiffIfdEntry> entries = new List<TiffIfdEntry>()
{
new TiffIfdEntry(TiffTags.ImageWidth, TiffType.Byte, 8, new byte[] { 1, 2, 3, 4, 4, 3, 2, 1 }),
new TiffIfdEntry(TiffTags.ImageLength, TiffType.Short, 4, new byte[] { 5, 6, 7, 8, 9, 10, 11, 12 }),
new TiffIfdEntry(TiffTags.Compression, TiffType.Ascii, 3, new byte[] { (byte)'A', (byte)'B', 0 })
};
using (TiffWriter writer = new TiffWriter(stream))
{
writer.Write(new byte[] { 1, 2, 3, 4 });
long nextIfdMarker = encoder.WriteIfd(writer, entries);
}
var ifdEntry1Bytes = stream.ToArray().Skip(14 + 12 * 0).Take(4).ToArray();
var ifdEntry1Data = stream.ToArray().Skip(46).Take(8).ToArray();
var ifdEntry2Bytes = stream.ToArray().Skip(14 + 12 * 1).Take(4).ToArray();
var ifdEntry2Data = stream.ToArray().Skip(54).Take(8).ToArray();
var ifdEntry3Bytes = stream.ToArray().Skip(14 + 12 * 2).Take(4).ToArray();
Assert.Equal(new byte[] { 46, 0, 0, 0 }, ifdEntry1Bytes);
Assert.Equal(new byte[] { 1, 2, 3, 4, 4, 3, 2, 1 }, ifdEntry1Data);
Assert.Equal(new byte[] { 54, 0, 0, 0 }, ifdEntry2Bytes);
Assert.Equal(new byte[] { 5, 6, 7, 8, 9, 10, 11, 12 }, ifdEntry2Data);
Assert.Equal(new byte[] { (byte)'A', (byte)'B', 0, 0 }, ifdEntry3Bytes);
}
[Fact]
public void WriteIfd_WritesDataByReferenceOnWordBoundary()
{
MemoryStream stream = new MemoryStream();
TiffEncoderCore encoder = new TiffEncoderCore(null);
List<TiffIfdEntry> entries = new List<TiffIfdEntry>()
{
new TiffIfdEntry(TiffTags.ImageWidth, TiffType.Byte, 8, new byte[] { 1, 2, 3, 4, 5 }),
new TiffIfdEntry(TiffTags.ImageLength, TiffType.Short, 4, new byte[] { 5, 6, 7, 8, 9, 10, 11, 12 }),
new TiffIfdEntry(TiffTags.Compression, TiffType.Ascii, 3, new byte[] { (byte)'A', (byte)'B', 0 })
};
using (TiffWriter writer = new TiffWriter(stream))
{
writer.Write(new byte[] { 1, 2, 3, 4 });
long nextIfdMarker = encoder.WriteIfd(writer, entries);
}
var ifdEntry1Bytes = stream.ToArray().Skip(14 + 12 * 0).Take(4).ToArray();
var ifdEntry1Data = stream.ToArray().Skip(46).Take(5).ToArray();
var ifdEntry2Bytes = stream.ToArray().Skip(14 + 12 * 1).Take(4).ToArray();
var ifdEntry2Data = stream.ToArray().Skip(52).Take(8).ToArray();
var ifdEntry3Bytes = stream.ToArray().Skip(14 + 12 * 2).Take(4).ToArray();
Assert.Equal(new byte[] { 46, 0, 0, 0 }, ifdEntry1Bytes);
Assert.Equal(new byte[] { 1, 2, 3, 4, 5 }, ifdEntry1Data);
Assert.Equal(new byte[] { 52, 0, 0, 0 }, ifdEntry2Bytes);
Assert.Equal(new byte[] { 5, 6, 7, 8, 9, 10, 11, 12 }, ifdEntry2Data);
Assert.Equal(new byte[] { (byte)'A', (byte)'B', 0, 0 }, ifdEntry3Bytes);
}
[Fact]
public void WriteIfd_WritesEntriesInCorrectOrder()
{
MemoryStream stream = new MemoryStream();
TiffEncoderCore encoder = new TiffEncoderCore(null);
List<TiffIfdEntry> entries = new List<TiffIfdEntry>()
{
new TiffIfdEntry(10, TiffType.Long, 1, new byte[] { 1, 2, 3, 4 }),
new TiffIfdEntry(30, TiffType.Long, 1, new byte[] { 5, 6, 7, 8 }),
new TiffIfdEntry(20, TiffType.Long, 1, new byte[] { 9, 10, 11, 12 })
};
using (TiffWriter writer = new TiffWriter(stream))
{
long nextIfdMarker = encoder.WriteIfd(writer, entries);
}
var ifdEntry1Bytes = stream.ToArray().Skip(2 + 12 * 0).Take(2).ToArray();
var ifdEntry2Bytes = stream.ToArray().Skip(2 + 12 * 1).Take(2).ToArray();
var ifdEntry3Bytes = stream.ToArray().Skip(2 + 12 * 2).Take(2).ToArray();
Assert.Equal(new byte[] { 10, 0 }, ifdEntry1Bytes);
Assert.Equal(new byte[] { 20, 0 }, ifdEntry2Bytes);
Assert.Equal(new byte[] { 30, 0 }, ifdEntry3Bytes);
}
[Fact]
public void WriteIfd_ThrowsException_IfNoEntriesArePresent()
{
MemoryStream stream = new MemoryStream();
TiffEncoderCore encoder = new TiffEncoderCore(null);
List<TiffIfdEntry> entries = new List<TiffIfdEntry>();
using (TiffWriter writer = new TiffWriter(stream))
{
ArgumentException e = Assert.Throws<ArgumentException>(() => { encoder.WriteIfd(writer, entries); });
Assert.Equal("There must be at least one entry per IFD.\r\nParameter name: entries", e.Message);
Assert.Equal("entries", e.ParamName);
}
}
}
}

135
tests/ImageSharp.Formats.Tiff.Tests/Formats/Tiff/Utils/TiffWriterTests.cs

@ -0,0 +1,135 @@
// <copyright file="TiffWriterTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Tests
{
using System;
using System.IO;
using Xunit;
using ImageSharp.Formats.Tiff;
public class TiffWriterTests
{
[Fact]
public void IsLittleEndian_IsTrueOnWindows()
{
MemoryStream stream = new MemoryStream();
using (TiffWriter writer = new TiffWriter(stream))
{
Assert.True(writer.IsLittleEndian);
}
}
[Theory]
[InlineData(new byte[] {}, 0)]
[InlineData(new byte[] { 42 }, 1)]
[InlineData(new byte[] { 1, 2, 3, 4, 5 }, 5)]
public void Position_EqualsTheStreamPosition(byte[] data, long expectedResult)
{
MemoryStream stream = new MemoryStream();
using (TiffWriter writer = new TiffWriter(stream))
{
writer.Write(data);
Assert.Equal(writer.Position, expectedResult);
}
}
[Fact]
public void Write_WritesByte()
{
MemoryStream stream = new MemoryStream();
using (TiffWriter writer = new TiffWriter(stream))
{
writer.Write((byte)42);
}
Assert.Equal(new byte[] { 42 }, stream.ToArray());
}
[Fact]
public void Write_WritesByteArray()
{
MemoryStream stream = new MemoryStream();
using (TiffWriter writer = new TiffWriter(stream))
{
writer.Write(new byte[] { 2, 4, 6, 8 });
}
Assert.Equal(new byte[] { 2, 4, 6, 8 }, stream.ToArray());
}
[Fact]
public void Write_WritesUInt16()
{
MemoryStream stream = new MemoryStream();
using (TiffWriter writer = new TiffWriter(stream))
{
writer.Write((ushort)1234);
}
Assert.Equal(new byte[] { 0xD2, 0x04 }, stream.ToArray());
}
[Fact]
public void Write_WritesUInt32()
{
MemoryStream stream = new MemoryStream();
using (TiffWriter writer = new TiffWriter(stream))
{
writer.Write((uint)12345678);
}
Assert.Equal(new byte[] { 0x4E, 0x61, 0xBC, 0x00 }, stream.ToArray());
}
[Theory]
[InlineData(new byte[] { }, new byte[] { 0, 0, 0, 0 })]
[InlineData(new byte[] { 2 }, new byte[] { 2, 0, 0, 0 })]
[InlineData(new byte[] { 2, 4 }, new byte[] { 2, 4, 0, 0 })]
[InlineData(new byte[] { 2, 4, 6 }, new byte[] { 2, 4, 6, 0 })]
[InlineData(new byte[] { 2, 4, 6, 8 }, new byte[] { 2, 4, 6, 8 })]
[InlineData(new byte[] { 2, 4, 6, 8, 10, 12 }, new byte[] { 2, 4, 6, 8, 10, 12 })]
public void WritePadded_WritesByteArray(byte[] bytes, byte[] expectedResult)
{
MemoryStream stream = new MemoryStream();
using (TiffWriter writer = new TiffWriter(stream))
{
writer.WritePadded(bytes);
}
Assert.Equal(expectedResult, stream.ToArray());
}
[Fact]
public void WriteMarker_WritesToPlacedPosition()
{
MemoryStream stream = new MemoryStream();
using (TiffWriter writer = new TiffWriter(stream))
{
writer.Write((uint)0x11111111);
long marker = writer.PlaceMarker();
writer.Write((uint)0x33333333);
writer.WriteMarker(marker, 0x12345678);
writer.Write((uint)0x44444444);
}
Assert.Equal(new byte[] { 0x11, 0x11, 0x11, 0x11,
0x78, 0x56, 0x34, 0x12,
0x33, 0x33, 0x33, 0x33,
0x44, 0x44, 0x44, 0x44 }, stream.ToArray());
}
}
}
Loading…
Cancel
Save