From 4f199ff73a53088f5e3bb6e1574084d9373e0e1f Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Tue, 4 Jan 2022 16:20:42 +0300 Subject: [PATCH 1/8] 4 byte IFD pointer --- src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs index e7a01b070f..00ed4adb31 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs @@ -70,7 +70,7 @@ public byte[] GetData() // two bytes for the byte Order marker 'II' or 'MM', followed by the number 42 (0x2A) and a 0, making 4 bytes total length += (uint)ExifConstants.LittleEndianByteOrderMarker.Length; - length += 4 + 2; + length += 4 + 4; var result = new byte[length]; @@ -103,7 +103,7 @@ public byte[] GetData() i = this.WriteData(startIndex, this.gpsValues, result, i); } - WriteUInt16(0, result, i); + WriteUInt32(0, result, i); return result; } From 4491343ee8d9426d2c91ed6dcf9c6351bb87f760 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Tue, 4 Jan 2022 16:47:08 +0300 Subject: [PATCH 2/8] test fix --- .../ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs index ebc0968524..18d53e9e47 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs @@ -420,7 +420,7 @@ public void TestArrayValueWithUnspecifiedSize() Assert.Equal(2, profile.Values.Count(v => (ExifTagValue)(ushort)v.Tag == ExifTagValue.DateTime)); byte[] bytes = profile.ToByteArray(); - Assert.Equal(525, bytes.Length); + Assert.Equal(527, bytes.Length); var profile2 = new ExifProfile(bytes); Assert.Equal(25, profile2.Values.Count); From 2216980c2f55e41fca5e389a14b0905b6c476fd3 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 8 Jan 2022 12:39:09 +0300 Subject: [PATCH 3/8] exif ifd writing fixes --- .../Metadata/Profiles/Exif/ExifWriter.cs | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs index 82f4aac17d..2fb1924497 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs @@ -46,7 +46,6 @@ public ExifWriter(IList values, ExifParts allowedParts) public byte[] GetData() { const uint startIndex = 0; - uint length; IExifValue exifOffset = GetOffsetValue(this.ifdValues, this.exifValues, ExifTag.SubIFDOffset); IExifValue gpsOffset = GetOffsetValue(this.ifdValues, this.gpsValues, ExifTag.GPSIFDOffset); @@ -56,13 +55,13 @@ public byte[] GetData() return Array.Empty(); } - uint ifdLength = this.GetLength(this.ifdValues) + 4U; + uint ifdLength = this.GetLength(this.ifdValues); uint exifLength = this.GetLength(this.exifValues); uint gpsLength = this.GetLength(this.gpsValues); - length = ifdLength + exifLength + gpsLength; + uint length = ifdLength + exifLength + gpsLength; - if (length == 4U) + if (length == 0) { return Array.Empty(); } @@ -70,9 +69,10 @@ public byte[] GetData() // two bytes for the byte Order marker 'II' or 'MM', followed by the number 42 (0x2A) and a 0, making 4 bytes total length += (uint)ExifConstants.LittleEndianByteOrderMarker.Length; - length += 4 + 4; + // first IFD offset + length += 4; - var result = new byte[length]; + byte[] result = new byte[length]; int i = 0; @@ -80,15 +80,13 @@ public byte[] GetData() ExifConstants.LittleEndianByteOrderMarker.CopyTo(result.AsSpan(start: i)); i += ExifConstants.LittleEndianByteOrderMarker.Length; - uint ifdOffset = ((uint)i - startIndex) + 4U; - uint thumbnailOffset = ifdOffset + ifdLength + exifLength + gpsLength; + uint ifdOffset = (uint)i - startIndex + 4U; exifOffset?.TrySetValue(ifdOffset + ifdLength); gpsOffset?.TrySetValue(ifdOffset + ifdLength + exifLength); i = WriteUInt32(ifdOffset, result, i); i = this.WriteHeaders(this.ifdValues, result, i); - i = WriteUInt32(thumbnailOffset, result, i); i = this.WriteData(startIndex, this.ifdValues, result, i); if (exifLength > 0) @@ -103,8 +101,6 @@ public byte[] GetData() i = this.WriteData(startIndex, this.gpsValues, result, i); } - WriteUInt32(0, result, i); - return result; } @@ -263,7 +259,7 @@ private uint GetLength(IList values) { uint valueLength = GetLength(value); - length += 2 + 2 + 4 + 4; + length += 12; if (valueLength > 4) { @@ -271,6 +267,9 @@ private uint GetLength(IList values) } } + // next IFD offset + length += 4; + return length; } @@ -361,6 +360,9 @@ private int WriteHeaders(List values, Span destination, int of newOffset += 4; } + // next IFD offset + newOffset = WriteUInt32(0, destination, newOffset); + return newOffset; } From c944d410e3e2351084fb560311eb6682ce326604 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 8 Jan 2022 12:39:40 +0300 Subject: [PATCH 4/8] test fixes --- .../ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs index 72d07190e4..e144ece6c7 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs @@ -420,7 +420,7 @@ public void TestArrayValueWithUnspecifiedSize() Assert.Equal(2, profile.Values.Count(v => (ExifTagValue)(ushort)v.Tag == ExifTagValue.DateTime)); byte[] bytes = profile.ToByteArray(); - Assert.Equal(527, bytes.Length); + Assert.Equal(531, bytes.Length); var profile2 = new ExifProfile(bytes); Assert.Equal(25, profile2.Values.Count); From b79b409de3f77acddb2889104535ec90e8b19f90 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 8 Jan 2022 14:22:40 +0300 Subject: [PATCH 5/8] add test --- .../Profiles/Exif/ExifProfileTests.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs index e144ece6c7..028f1967da 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs @@ -487,6 +487,28 @@ private static ExifProfile CreateExifProfile() return profile; } + [Fact] + public void IfdStructure() + { + var exif = new ExifProfile(); + exif.SetValue(ExifTag.XPAuthor, Encoding.GetEncoding("UCS-2").GetBytes("Dan Petitt")); + + byte[] actualBytes = exif.ToByteArray(); + + // Assert + int ifdOffset = ExifConstants.LittleEndianByteOrderMarker.Length; + Assert.Equal(8, actualBytes[ifdOffset]); + Assert.Equal(0, actualBytes[ifdOffset + 1]); + Assert.Equal(0, actualBytes[ifdOffset + 2]); + Assert.Equal(0, actualBytes[ifdOffset + 3]); + + int nextIfdPointerOffset = ExifConstants.LittleEndianByteOrderMarker.Length + 4 + 2 + 12; + Assert.Equal(0, actualBytes[nextIfdPointerOffset]); + Assert.Equal(0, actualBytes[nextIfdPointerOffset + 1]); + Assert.Equal(0, actualBytes[nextIfdPointerOffset + 2]); + Assert.Equal(0, actualBytes[nextIfdPointerOffset + 3]); + } + internal static ExifProfile GetExifProfile() { using Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateRgba32Image(); From 2f664e5edb35cf4b17fbbcc44c7cfac445e86590 Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 8 Jan 2022 14:37:35 +0300 Subject: [PATCH 6/8] minor improve test --- .../Metadata/Profiles/Exif/ExifProfileTests.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs index 028f1967da..4e258d8478 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers.Binary; using System.Collections.Generic; using System.IO; using System.Linq; @@ -493,20 +494,15 @@ public void IfdStructure() var exif = new ExifProfile(); exif.SetValue(ExifTag.XPAuthor, Encoding.GetEncoding("UCS-2").GetBytes("Dan Petitt")); - byte[] actualBytes = exif.ToByteArray(); + Span actualBytes = exif.ToByteArray(); // Assert int ifdOffset = ExifConstants.LittleEndianByteOrderMarker.Length; - Assert.Equal(8, actualBytes[ifdOffset]); - Assert.Equal(0, actualBytes[ifdOffset + 1]); - Assert.Equal(0, actualBytes[ifdOffset + 2]); - Assert.Equal(0, actualBytes[ifdOffset + 3]); + + Assert.Equal(8U, BinaryPrimitives.ReadUInt32LittleEndian(actualBytes.Slice(ifdOffset, 4))); int nextIfdPointerOffset = ExifConstants.LittleEndianByteOrderMarker.Length + 4 + 2 + 12; - Assert.Equal(0, actualBytes[nextIfdPointerOffset]); - Assert.Equal(0, actualBytes[nextIfdPointerOffset + 1]); - Assert.Equal(0, actualBytes[nextIfdPointerOffset + 2]); - Assert.Equal(0, actualBytes[nextIfdPointerOffset + 3]); + Assert.Equal(0U, BinaryPrimitives.ReadUInt32LittleEndian(actualBytes.Slice(nextIfdPointerOffset, 4))); } internal static ExifProfile GetExifProfile() From 556c0a7c4f62a216b99d572d448ebca908711d3d Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 8 Jan 2022 15:09:05 +0300 Subject: [PATCH 7/8] cleanup, add empty profile writer test --- src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs | 5 ----- .../Metadata/Profiles/Exif/ExifProfileTests.cs | 12 +++++++++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs index 2fb1924497..e2ed569548 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs @@ -50,11 +50,6 @@ public byte[] GetData() IExifValue exifOffset = GetOffsetValue(this.ifdValues, this.exifValues, ExifTag.SubIFDOffset); IExifValue gpsOffset = GetOffsetValue(this.ifdValues, this.gpsValues, ExifTag.GPSIFDOffset); - if (this.ifdValues.Count == 0 && this.exifValues.Count == 0 && this.gpsValues.Count == 0) - { - return Array.Empty(); - } - uint ifdLength = this.GetLength(this.ifdValues); uint exifLength = this.GetLength(this.exifValues); uint gpsLength = this.GetLength(this.gpsValues); diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs index 4e258d8478..0210086f57 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs @@ -87,6 +87,17 @@ public void ConstructorEmpty() new ExifProfile(Array.Empty()); } + [Fact] + public void EmptyWriter() + { + var profile = new ExifProfile() { Parts = ExifParts.GpsTags }; + profile.SetValue(ExifTag.Copyright, "Copyright text"); + + byte[] bytes = profile.ToByteArray(); + Assert.NotNull(bytes); + Assert.Empty(bytes); + } + [Fact] public void ConstructorCopy() { @@ -498,7 +509,6 @@ public void IfdStructure() // Assert int ifdOffset = ExifConstants.LittleEndianByteOrderMarker.Length; - Assert.Equal(8U, BinaryPrimitives.ReadUInt32LittleEndian(actualBytes.Slice(ifdOffset, 4))); int nextIfdPointerOffset = ExifConstants.LittleEndianByteOrderMarker.Length + 4 + 2 + 12; From 92cc9fbb1c9c00961a399ef14cd9609ec3af567c Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Sat, 8 Jan 2022 15:19:18 +0300 Subject: [PATCH 8/8] fake changes --- .../ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs index 0210086f57..7fc3ff6f19 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs @@ -94,6 +94,7 @@ public void EmptyWriter() profile.SetValue(ExifTag.Copyright, "Copyright text"); byte[] bytes = profile.ToByteArray(); + Assert.NotNull(bytes); Assert.Empty(bytes); }