diff --git a/src/ImageSharp.Formats.Tiff/TiffDecoderCore.cs b/src/ImageSharp.Formats.Tiff/TiffDecoderCore.cs index 37aad73200..9a09209804 100644 --- a/src/ImageSharp.Formats.Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp.Formats.Tiff/TiffDecoderCore.cs @@ -150,6 +150,111 @@ namespace ImageSharp.Formats return entry.Value; } + public uint ReadUnsignedInteger(ref TiffIfdEntry entry) + { + if (entry.Count != 1) + throw new ImageFormatException($"Cannot read a single value from an array of multiple items."); + + switch (entry.Type) + { + case TiffType.Byte: + return (uint)ToByte(entry.Value, 0); + case TiffType.Short: + return (uint)ToUInt16(entry.Value, 0); + case TiffType.Long: + return ToUInt32(entry.Value, 0); + default: + throw new ImageFormatException($"A value of type '{entry.Type}' cannot be converted to an unsigned integer."); + } + } + + public int ReadSignedInteger(ref TiffIfdEntry entry) + { + if (entry.Count != 1) + throw new ImageFormatException($"Cannot read a single value from an array of multiple items."); + + switch (entry.Type) + { + case TiffType.SByte: + return (int)ToSByte(entry.Value, 0); + case TiffType.SShort: + return (int)ToInt16(entry.Value, 0); + case TiffType.SLong: + return ToInt32(entry.Value, 0); + default: + throw new ImageFormatException($"A value of type '{entry.Type}' cannot be converted to a signed integer."); + } + } + + public uint[] ReadUnsignedIntegerArray(ref TiffIfdEntry entry) + { + byte[] bytes = ReadBytes(ref entry); + uint[] result = new uint[entry.Count]; + + switch (entry.Type) + { + case TiffType.Byte: + { + for (int i = 0 ; i < result.Length ; i++) + result[i] = (uint)ToByte(bytes, i); + break; + } + case TiffType.Short: + { + for (int i = 0 ; i < result.Length ; i++) + result[i] = (uint)ToUInt16(bytes, i * 2); + break; + } + case TiffType.Long: + { + for (int i = 0 ; i < result.Length ; i++) + result[i] = ToUInt32(bytes, i * 4); + break; + } + default: + throw new ImageFormatException($"A value of type '{entry.Type}' cannot be converted to an unsigned integer."); + } + + return result; + } + + public int[] ReadSignedIntegerArray(ref TiffIfdEntry entry) + { + byte[] bytes = ReadBytes(ref entry); + int[] result = new int[entry.Count]; + + switch (entry.Type) + { + case TiffType.SByte: + { + for (int i = 0 ; i < result.Length ; i++) + result[i] = (int)ToSByte(bytes, i); + break; + } + case TiffType.SShort: + { + for (int i = 0 ; i < result.Length ; i++) + result[i] = (int)ToInt16(bytes, i * 2); + break; + } + case TiffType.SLong: + { + for (int i = 0 ; i < result.Length ; i++) + result[i] = ToInt32(bytes, i * 4); + break; + } + default: + throw new ImageFormatException($"A value of type '{entry.Type}' cannot be converted to a signed integer."); + } + + return result; + } + + private SByte ToSByte(byte[] bytes, int offset) + { + return (sbyte)bytes[offset]; + } + private Int16 ToInt16(byte[] bytes, int offset) { if (IsLittleEndian) @@ -166,6 +271,11 @@ namespace ImageSharp.Formats return (bytes[offset + 0] << 24) | (bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3]; } + private Byte ToByte(byte[] bytes, int offset) + { + return bytes[offset]; + } + private UInt32 ToUInt32(byte[] bytes, int offset) { return (uint)ToInt32(bytes, offset); diff --git a/tests/ImageSharp.Formats.Tiff.Tests/Formats/Tiff/TiffDecoderIfdEntryTests.cs b/tests/ImageSharp.Formats.Tiff.Tests/Formats/Tiff/TiffDecoderIfdEntryTests.cs index 1d987de9af..16581e3674 100644 --- a/tests/ImageSharp.Formats.Tiff.Tests/Formats/Tiff/TiffDecoderIfdEntryTests.cs +++ b/tests/ImageSharp.Formats.Tiff.Tests/Formats/Tiff/TiffDecoderIfdEntryTests.cs @@ -5,6 +5,7 @@ namespace ImageSharp.Tests { + using System; using System.IO; using System.Linq; using Xunit; @@ -115,6 +116,254 @@ namespace ImageSharp.Tests Assert.Equal(bytes, entry.Value); } + [Theory] + [InlineDataAttribute(TiffType.Byte, true, new byte[] { 0, 1, 2, 3 }, 0)] + [InlineDataAttribute(TiffType.Byte, true, new byte[] { 1, 2, 3, 4 }, 1)] + [InlineDataAttribute(TiffType.Byte, true, new byte[] { 255, 2, 3, 4 }, 255)] + [InlineDataAttribute(TiffType.Byte, false, new byte[] { 0, 1, 2, 3 }, 0)] + [InlineDataAttribute(TiffType.Byte, false, new byte[] { 1, 2, 3, 4 }, 1)] + [InlineDataAttribute(TiffType.Byte, false, new byte[] { 255, 2, 3, 4 }, 255)] + [InlineDataAttribute(TiffType.Short, true, new byte[] { 0, 0, 2, 3 }, 0)] + [InlineDataAttribute(TiffType.Short, true, new byte[] { 1, 0, 2, 3 }, 1)] + [InlineDataAttribute(TiffType.Short, true, new byte[] { 0, 1, 2, 3 }, 256)] + [InlineDataAttribute(TiffType.Short, true, new byte[] { 2, 1, 2, 3 }, 258)] + [InlineDataAttribute(TiffType.Short, true, new byte[] { 255, 255, 2, 3 }, UInt16.MaxValue)] + [InlineDataAttribute(TiffType.Short, false, new byte[] { 0, 0, 2, 3 }, 0)] + [InlineDataAttribute(TiffType.Short, false, new byte[] { 0, 1, 2, 3 }, 1)] + [InlineDataAttribute(TiffType.Short, false, new byte[] { 1, 0, 2, 3 }, 256)] + [InlineDataAttribute(TiffType.Short, false, new byte[] { 1, 2, 2, 3 }, 258)] + [InlineDataAttribute(TiffType.Short, false, new byte[] { 255, 255, 2, 3 }, UInt16.MaxValue)] + [InlineDataAttribute(TiffType.Long, true, new byte[] { 0, 0, 0, 0 }, 0)] + [InlineDataAttribute(TiffType.Long, true, new byte[] { 1, 0, 0, 0 }, 1)] + [InlineDataAttribute(TiffType.Long, true, new byte[] { 0, 1, 0, 0 }, 256)] + [InlineDataAttribute(TiffType.Long, true, new byte[] { 0, 0, 1, 0 }, 256 * 256)] + [InlineDataAttribute(TiffType.Long, true, new byte[] { 0, 0, 0, 1 }, 256 * 256 * 256)] + [InlineDataAttribute(TiffType.Long, true, new byte[] { 1, 2, 3, 4 }, 67305985)] + [InlineDataAttribute(TiffType.Long, true, new byte[] { 255, 255, 255, 255 }, UInt32.MaxValue)] + [InlineDataAttribute(TiffType.Long, false, new byte[] { 0, 0, 0, 0 }, 0)] + [InlineDataAttribute(TiffType.Long, false, new byte[] { 0, 0, 0, 1 }, 1)] + [InlineDataAttribute(TiffType.Long, false, new byte[] { 0, 0, 1, 0 }, 256)] + [InlineDataAttribute(TiffType.Long, false, new byte[] { 0, 1, 0, 0 }, 256 * 256)] + [InlineDataAttribute(TiffType.Long, false, new byte[] { 1, 0, 0, 0 }, 256 * 256 * 256)] + [InlineDataAttribute(TiffType.Long, false, new byte[] { 4, 3, 2, 1 }, 67305985)] + [InlineDataAttribute(TiffType.Long, false, new byte[] { 255, 255, 255, 255 }, UInt32.MaxValue)] + public void ReadUnsignedInteger_ReturnsValue(ushort type, bool isLittleEndian, byte[] bytes, uint expectedValue) + { + (TiffDecoderCore decoder, TiffIfdEntry entry) = GenerateTestIfdEntry(TiffGenEntry.Bytes(TiffTags.ImageWidth, (TiffType)type, 1, bytes), isLittleEndian); + + uint result = decoder.ReadUnsignedInteger(ref entry); + + Assert.Equal(expectedValue, result); + } + + [Theory] + [InlineDataAttribute(TiffType.Ascii)] + [InlineDataAttribute(TiffType.Rational)] + [InlineDataAttribute(TiffType.SByte)] + [InlineDataAttribute(TiffType.Undefined)] + [InlineDataAttribute(TiffType.SShort)] + [InlineDataAttribute(TiffType.SLong)] + [InlineDataAttribute(TiffType.SRational)] + [InlineDataAttribute(TiffType.Float)] + [InlineDataAttribute(TiffType.Double)] + [InlineDataAttribute(TiffType.Ifd)] + [InlineDataAttribute((TiffType)99)] + public void ReadUnsignedInteger_ThrowsExceptionIfInvalidType(ushort type) + { + (TiffDecoderCore decoder, TiffIfdEntry entry) = GenerateTestIfdEntry(TiffGenEntry.Bytes(TiffTags.ImageWidth, (TiffType)type, 1, new byte[4]), true); + + var e = Assert.Throws(() => decoder.ReadUnsignedInteger(ref entry)); + + Assert.Equal($"A value of type '{(TiffType)type}' cannot be converted to an unsigned integer.", e.Message); + } + + [Theory] + [InlineDataAttribute(TiffType.Byte, true)] + [InlineDataAttribute(TiffType.Short, true)] + [InlineDataAttribute(TiffType.Long, true)] + [InlineDataAttribute(TiffType.Byte, false)] + [InlineDataAttribute(TiffType.Short, false)] + [InlineDataAttribute(TiffType.Long, false)] + public void ReadUnsignedInteger_ThrowsExceptionIfCountIsNotOne(ushort type, bool isLittleEndian) + { + (TiffDecoderCore decoder, TiffIfdEntry entry) = GenerateTestIfdEntry(TiffGenEntry.Bytes(TiffTags.ImageWidth, (TiffType)type, 2, new byte[4]), isLittleEndian); + + var e = Assert.Throws(() => decoder.ReadUnsignedInteger(ref entry)); + + Assert.Equal($"Cannot read a single value from an array of multiple items.", e.Message); + } + + [Theory] + [InlineDataAttribute(TiffType.SByte, true, new byte[] { 0, 1, 2, 3 }, 0)] + [InlineDataAttribute(TiffType.SByte, true, new byte[] { 1, 2, 3, 4 }, 1)] + [InlineDataAttribute(TiffType.SByte, true, new byte[] { 255, 2, 3, 4 }, -1)] + [InlineDataAttribute(TiffType.SByte, false, new byte[] { 0, 1, 2, 3 }, 0)] + [InlineDataAttribute(TiffType.SByte, false, new byte[] { 1, 2, 3, 4 }, 1)] + [InlineDataAttribute(TiffType.SByte, false, new byte[] { 255, 2, 3, 4 }, -1)] + [InlineDataAttribute(TiffType.SShort, true, new byte[] { 0, 0, 2, 3 }, 0)] + [InlineDataAttribute(TiffType.SShort, true, new byte[] { 1, 0, 2, 3 }, 1)] + [InlineDataAttribute(TiffType.SShort, true, new byte[] { 0, 1, 2, 3 }, 256)] + [InlineDataAttribute(TiffType.SShort, true, new byte[] { 2, 1, 2, 3 }, 258)] + [InlineDataAttribute(TiffType.SShort, true, new byte[] { 255, 255, 2, 3 }, -1)] + [InlineDataAttribute(TiffType.SShort, false, new byte[] { 0, 0, 2, 3 }, 0)] + [InlineDataAttribute(TiffType.SShort, false, new byte[] { 0, 1, 2, 3 }, 1)] + [InlineDataAttribute(TiffType.SShort, false, new byte[] { 1, 0, 2, 3 }, 256)] + [InlineDataAttribute(TiffType.SShort, false, new byte[] { 1, 2, 2, 3 }, 258)] + [InlineDataAttribute(TiffType.SShort, false, new byte[] { 255, 255, 2, 3 }, -1)] + [InlineDataAttribute(TiffType.SLong, true, new byte[] { 0, 0, 0, 0 }, 0)] + [InlineDataAttribute(TiffType.SLong, true, new byte[] { 1, 0, 0, 0 }, 1)] + [InlineDataAttribute(TiffType.SLong, true, new byte[] { 0, 1, 0, 0 }, 256)] + [InlineDataAttribute(TiffType.SLong, true, new byte[] { 0, 0, 1, 0 }, 256 * 256)] + [InlineDataAttribute(TiffType.SLong, true, new byte[] { 0, 0, 0, 1 }, 256 * 256 * 256)] + [InlineDataAttribute(TiffType.SLong, true, new byte[] { 1, 2, 3, 4 }, 67305985)] + [InlineDataAttribute(TiffType.SLong, true, new byte[] { 255, 255, 255, 255 }, -1)] + [InlineDataAttribute(TiffType.SLong, false, new byte[] { 0, 0, 0, 0 }, 0)] + [InlineDataAttribute(TiffType.SLong, false, new byte[] { 0, 0, 0, 1 }, 1)] + [InlineDataAttribute(TiffType.SLong, false, new byte[] { 0, 0, 1, 0 }, 256)] + [InlineDataAttribute(TiffType.SLong, false, new byte[] { 0, 1, 0, 0 }, 256 * 256)] + [InlineDataAttribute(TiffType.SLong, false, new byte[] { 1, 0, 0, 0 }, 256 * 256 * 256)] + [InlineDataAttribute(TiffType.SLong, false, new byte[] { 4, 3, 2, 1 }, 67305985)] + [InlineDataAttribute(TiffType.SLong, false, new byte[] { 255, 255, 255, 255 }, -1)] + public void ReadSignedInteger_ReturnsValue(ushort type, bool isLittleEndian, byte[] bytes, int expectedValue) + { + (TiffDecoderCore decoder, TiffIfdEntry entry) = GenerateTestIfdEntry(TiffGenEntry.Bytes(TiffTags.ImageWidth, (TiffType)type, 1, bytes), isLittleEndian); + + int result = decoder.ReadSignedInteger(ref entry); + + Assert.Equal(expectedValue, result); + } + + [Theory] + [InlineDataAttribute(TiffType.Byte)] + [InlineDataAttribute(TiffType.Ascii)] + [InlineDataAttribute(TiffType.Short)] + [InlineDataAttribute(TiffType.Long)] + [InlineDataAttribute(TiffType.Rational)] + [InlineDataAttribute(TiffType.Undefined)] + [InlineDataAttribute(TiffType.SRational)] + [InlineDataAttribute(TiffType.Float)] + [InlineDataAttribute(TiffType.Double)] + [InlineDataAttribute(TiffType.Ifd)] + [InlineDataAttribute((TiffType)99)] + public void ReadSignedInteger_ThrowsExceptionIfInvalidType(ushort type) + { + (TiffDecoderCore decoder, TiffIfdEntry entry) = GenerateTestIfdEntry(TiffGenEntry.Bytes(TiffTags.ImageWidth, (TiffType)type, 1, new byte[4]), true); + + var e = Assert.Throws(() => decoder.ReadSignedInteger(ref entry)); + + Assert.Equal($"A value of type '{(TiffType)type}' cannot be converted to a signed integer.", e.Message); + } + + [Theory] + [InlineDataAttribute(TiffType.SByte, true)] + [InlineDataAttribute(TiffType.SShort, true)] + [InlineDataAttribute(TiffType.SLong, true)] + [InlineDataAttribute(TiffType.SByte, false)] + [InlineDataAttribute(TiffType.SShort, false)] + [InlineDataAttribute(TiffType.SLong, false)] + public void ReadSignedInteger_ThrowsExceptionIfCountIsNotOne(ushort type, bool isLittleEndian) + { + (TiffDecoderCore decoder, TiffIfdEntry entry) = GenerateTestIfdEntry(TiffGenEntry.Bytes(TiffTags.ImageWidth, (TiffType)type, 2, new byte[4]), isLittleEndian); + + var e = Assert.Throws(() => decoder.ReadSignedInteger(ref entry)); + + Assert.Equal($"Cannot read a single value from an array of multiple items.", e.Message); + } + + [Theory] + [InlineDataAttribute(TiffType.Byte, 1, true, new byte[] { 0, 1, 2, 3 }, new uint[] { 0 })] + [InlineDataAttribute(TiffType.Byte, 3, true, new byte[] { 0, 1, 2, 3 }, new uint[] { 0, 1, 2 })] + [InlineDataAttribute(TiffType.Byte, 7, true, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, new uint[] { 0, 1, 2, 3, 4, 5, 6 })] + [InlineDataAttribute(TiffType.Byte, 1, false, new byte[] { 0, 1, 2, 3 }, new uint[] { 0 })] + [InlineDataAttribute(TiffType.Byte, 3, false, new byte[] { 0, 1, 2, 3 }, new uint[] { 0, 1, 2 })] + [InlineDataAttribute(TiffType.Byte, 7, false, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, new uint[] { 0, 1, 2, 3, 4, 5, 6 })] + [InlineDataAttribute(TiffType.Short, 1, true, new byte[] { 1, 0, 3, 2 }, new uint[] { 1 })] + [InlineDataAttribute(TiffType.Short, 2, true, new byte[] { 1, 0, 3, 2 }, new uint[] { 1, 515 })] + [InlineDataAttribute(TiffType.Short, 3, true, new byte[] { 1, 0, 3, 2, 5, 4, 6, 7, 8 }, new uint[] { 1, 515, 1029 })] + [InlineDataAttribute(TiffType.Short, 1, false, new byte[] { 0, 1, 2, 3 }, new uint[] { 1 })] + [InlineDataAttribute(TiffType.Short, 2, false, new byte[] { 0, 1, 2, 3 }, new uint[] { 1, 515 })] + [InlineDataAttribute(TiffType.Short, 3, false, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, new uint[] { 1, 515, 1029 })] + [InlineDataAttribute(TiffType.Long, 1, true, new byte[] { 4, 3, 2, 1 }, new uint[] { 0x01020304 })] + [InlineDataAttribute(TiffType.Long, 2, true, new byte[] { 4, 3, 2, 1, 6, 5, 4, 3, 99, 99 }, new uint[] { 0x01020304, 0x03040506 })] + [InlineDataAttribute(TiffType.Long, 1, false, new byte[] { 1, 2, 3, 4 }, new uint[] { 0x01020304 })] + [InlineDataAttribute(TiffType.Long, 2, false, new byte[] { 1, 2, 3, 4, 3, 4, 5, 6, 99, 99 }, new uint[] { 0x01020304, 0x03040506 })] + public void ReadUnsignedIntegerArray_ReturnsValue(ushort type, int count, bool isLittleEndian, byte[] bytes, uint[] expectedValue) + { + (TiffDecoderCore decoder, TiffIfdEntry entry) = GenerateTestIfdEntry(TiffGenEntry.Bytes(TiffTags.ImageWidth, (TiffType)type, (uint)expectedValue.Length, bytes), isLittleEndian); + + uint[] result = decoder.ReadUnsignedIntegerArray(ref entry); + + Assert.Equal(expectedValue, result); + } + + [Theory] + [InlineDataAttribute(TiffType.Ascii)] + [InlineDataAttribute(TiffType.Rational)] + [InlineDataAttribute(TiffType.SByte)] + [InlineDataAttribute(TiffType.Undefined)] + [InlineDataAttribute(TiffType.SShort)] + [InlineDataAttribute(TiffType.SLong)] + [InlineDataAttribute(TiffType.SRational)] + [InlineDataAttribute(TiffType.Float)] + [InlineDataAttribute(TiffType.Double)] + [InlineDataAttribute(TiffType.Ifd)] + [InlineDataAttribute((TiffType)99)] + public void ReadUnsignedIntegerArray_ThrowsExceptionIfInvalidType(ushort type) + { + (TiffDecoderCore decoder, TiffIfdEntry entry) = GenerateTestIfdEntry(TiffGenEntry.Bytes(TiffTags.ImageWidth, (TiffType)type, 1, new byte[4]), true); + + var e = Assert.Throws(() => decoder.ReadUnsignedIntegerArray(ref entry)); + + Assert.Equal($"A value of type '{(TiffType)type}' cannot be converted to an unsigned integer.", e.Message); + } + + [Theory] + [InlineDataAttribute(TiffType.SByte, 1, true, new byte[] { 0, 1, 2, 3 }, new int[] { 0 })] + [InlineDataAttribute(TiffType.SByte, 3, true, new byte[] { 0, 255, 2, 3 }, new int[] { 0, -1, 2 })] + [InlineDataAttribute(TiffType.SByte, 7, true, new byte[] { 0, 255, 2, 3, 4, 5, 6, 7, 8 }, new int[] { 0, -1, 2, 3, 4, 5, 6 })] + [InlineDataAttribute(TiffType.SByte, 1, false, new byte[] { 0, 1, 2, 3 }, new int[] { 0 })] + [InlineDataAttribute(TiffType.SByte, 3, false, new byte[] { 0, 255, 2, 3 }, new int[] { 0, -1, 2 })] + [InlineDataAttribute(TiffType.SByte, 7, false, new byte[] { 0, 255, 2, 3, 4, 5, 6, 7, 8 }, new int[] { 0, -1, 2, 3, 4, 5, 6 })] + [InlineDataAttribute(TiffType.SShort, 1, true, new byte[] { 1, 0, 3, 2 }, new int[] { 1 })] + [InlineDataAttribute(TiffType.SShort, 2, true, new byte[] { 1, 0, 255, 255 }, new int[] { 1, -1 })] + [InlineDataAttribute(TiffType.SShort, 3, true, new byte[] { 1, 0, 255, 255, 5, 4, 6, 7, 8 }, new int[] { 1, -1, 1029 })] + [InlineDataAttribute(TiffType.SShort, 1, false, new byte[] { 0, 1, 2, 3 }, new int[] { 1 })] + [InlineDataAttribute(TiffType.SShort, 2, false, new byte[] { 0, 1, 255, 255 }, new int[] { 1, -1 })] + [InlineDataAttribute(TiffType.SShort, 3, false, new byte[] { 0, 1, 255, 255, 4, 5, 6, 7, 8 }, new int[] { 1, -1, 1029 })] + [InlineDataAttribute(TiffType.SLong, 1, true, new byte[] { 4, 3, 2, 1 }, new int[] { 0x01020304 })] + [InlineDataAttribute(TiffType.SLong, 2, true, new byte[] { 4, 3, 2, 1, 255, 255, 255, 255, 99, 99 }, new int[] { 0x01020304, -1 })] + [InlineDataAttribute(TiffType.SLong, 1, false, new byte[] { 1, 2, 3, 4 }, new int[] { 0x01020304 })] + [InlineDataAttribute(TiffType.SLong, 2, false, new byte[] { 1, 2, 3, 4, 255, 255, 255, 255, 99, 99 }, new int[] { 0x01020304, -1 })] + public void ReadSignedIntegerArray_ReturnsValue(ushort type, int count, bool isLittleEndian, byte[] bytes, int[] expectedValue) + { + (TiffDecoderCore decoder, TiffIfdEntry entry) = GenerateTestIfdEntry(TiffGenEntry.Bytes(TiffTags.ImageWidth, (TiffType)type, (uint)expectedValue.Length, bytes), isLittleEndian); + + int[] result = decoder.ReadSignedIntegerArray(ref entry); + + Assert.Equal(expectedValue, result); + } + + [Theory] + [InlineDataAttribute(TiffType.Byte)] + [InlineDataAttribute(TiffType.Ascii)] + [InlineDataAttribute(TiffType.Short)] + [InlineDataAttribute(TiffType.Long)] + [InlineDataAttribute(TiffType.Rational)] + [InlineDataAttribute(TiffType.Undefined)] + [InlineDataAttribute(TiffType.SRational)] + [InlineDataAttribute(TiffType.Float)] + [InlineDataAttribute(TiffType.Double)] + [InlineDataAttribute(TiffType.Ifd)] + [InlineDataAttribute((TiffType)99)] + public void ReadSignedIntegerArray_ThrowsExceptionIfInvalidType(ushort type) + { + (TiffDecoderCore decoder, TiffIfdEntry entry) = GenerateTestIfdEntry(TiffGenEntry.Bytes(TiffTags.ImageWidth, (TiffType)type, 1, new byte[4]), true); + + var e = Assert.Throws(() => decoder.ReadSignedIntegerArray(ref entry)); + + Assert.Equal($"A value of type '{(TiffType)type}' cannot be converted to a signed integer.", e.Message); + } + private (TiffDecoderCore, TiffIfdEntry) GenerateTestIfdEntry(TiffGenEntry entry, bool isLittleEndian) { Stream stream = new TiffGenIfd() diff --git a/tests/ImageSharp.Formats.Tiff.Tests/TestUtilities/Tiff/TiffGenEntry.cs b/tests/ImageSharp.Formats.Tiff.Tests/TestUtilities/Tiff/TiffGenEntry.cs index 757da63b4d..c0bb9d78c8 100644 --- a/tests/ImageSharp.Formats.Tiff.Tests/TestUtilities/Tiff/TiffGenEntry.cs +++ b/tests/ImageSharp.Formats.Tiff.Tests/TestUtilities/Tiff/TiffGenEntry.cs @@ -53,6 +53,20 @@ namespace ImageSharp.Tests return new TiffGenEntryInteger(tag, type, value); } + public static TiffGenEntry Integer(ushort tag, TiffType type, uint value) + { + return TiffGenEntry.Integer(tag, type, new uint[] {value}); + } + + public static TiffGenEntry Integer(ushort tag, TiffType type, uint[] value) + { + if (type != TiffType.Byte && type != TiffType.Short && type != TiffType.Long && + type != TiffType.SByte && type != TiffType.SShort && type != TiffType.SLong) + throw new ArgumentException(nameof(type), "The specified type is not an integer type."); + + return new TiffGenEntryUnsignedInteger(tag, type, value); + } + private class TiffGenEntryAscii : TiffGenEntry { public TiffGenEntryAscii(ushort tag, string value) : base(tag, TiffType.Ascii, (uint)GetBytes(value).Length) @@ -125,5 +139,42 @@ namespace ImageSharp.Tests } } } + + private class TiffGenEntryUnsignedInteger : TiffGenEntry + { + public TiffGenEntryUnsignedInteger(ushort tag, TiffType type, uint[] value) : base(tag, type, (uint)value.Length) + { + this.Value = value; + } + + public uint[] Value { get; } + + public override IEnumerable GetData(bool isLittleEndian) + { + byte[] bytes = GetBytes().SelectMany(b => b.WithByteOrder(isLittleEndian)).ToArray(); + return new[] { new TiffGenDataBlock(bytes) }; + } + + private IEnumerable GetBytes() + { + switch (Type) + { + case TiffType.Byte: + return Value.Select(i => new byte[] { (byte)i }); + case TiffType.Short: + return Value.Select(i => BitConverter.GetBytes((ushort)i)); + case TiffType.Long: + return Value.Select(i => BitConverter.GetBytes((uint)i)); + case TiffType.SByte: + return Value.Select(i => BitConverter.GetBytes((sbyte)i)); + case TiffType.SShort: + return Value.Select(i => BitConverter.GetBytes((short)i)); + case TiffType.SLong: + return Value.Select(i => BitConverter.GetBytes((int)i)); + default: + throw new InvalidOperationException(); + } + } + } } } \ No newline at end of file