diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index a4fcd9275b..034ada0b8b 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -189,10 +189,19 @@ internal abstract class BaseExifReader { if (this.subIfds is not null) { - foreach (ulong subIfdOffset in this.subIfds) + do { - this.ReadValues(values, (uint)subIfdOffset); + int sz = this.subIfds.Count; + Span buf = sz <= 256 ? stackalloc ulong[sz] : new ulong[sz]; + + this.subIfds.CopyTo(buf); + this.subIfds.Clear(); + foreach (ulong subIfdOffset in buf) + { + this.ReadValues(values, (uint)subIfdOffset); + } } + while (this.subIfds.Count > 0); } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs index a803372537..27fbaf4aee 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs @@ -10,6 +10,7 @@ using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Tests.TestUtilities; +using static SixLabors.ImageSharp.Metadata.Profiles.Exif.EncodedString; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Formats.Jpg; @@ -439,9 +440,8 @@ public partial class JpegDecoderTests Assert.Equal(expectedComment, metadata.Comments.ElementAtOrDefault(0).ToString()); image.DebugSave(provider); image.CompareToOriginal(provider); - } - + // https://github.com/SixLabors/ImageSharp/issues/2758 [Theory] [WithFile(TestImages.Jpeg.Issues.Issue2758, PixelTypes.L8)] @@ -468,6 +468,47 @@ public partial class JpegDecoderTests image.Save(ms, new JpegEncoder()); } + // https://github.com/SixLabors/ImageSharp/issues/2857 + [Theory] + [WithFile(TestImages.Jpeg.Issues.Issue2857, PixelTypes.Rgb24)] + public void Issue2857_SubSubIfds(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(JpegDecoder.Instance); + + Assert.Equal(5616, image.Width); + Assert.Equal(3744, image.Height); + + JpegMetadata meta = image.Metadata.GetJpegMetadata(); + Assert.Equal(92, meta.LuminanceQuality); + Assert.Equal(93, meta.ChrominanceQuality); + + ExifProfile exifProfile = image.Metadata.ExifProfile; + Assert.NotNull(exifProfile); + + using MemoryStream ms = new(); + bool hasThumbnail = exifProfile.TryCreateThumbnail(out _); + Assert.False(hasThumbnail); + + Assert.Equal("BilderBox - Erwin Wodicka / wodicka@aon.at", exifProfile.GetValue(ExifTag.Copyright).Value); + Assert.Equal("Adobe Photoshop CS3 Windows", exifProfile.GetValue(ExifTag.Software).Value); + + Assert.Equal("Carers; seniors; caregiver; senior care; retirement home; hands; old; elderly; elderly caregiver; elder care; elderly care; geriatric care; nursing home; age; old age care; outpatient; needy; health care; home nurse; home care; sick; retirement; medical; mobile; the elderly; nursing department; nursing treatment; nursing; care services; nursing services; nursing care; nursing allowance; nursing homes; home nursing; care category; nursing class; care; nursing shortage; nursing patient care staff\0", exifProfile.GetValue(ExifTag.XPKeywords).Value); + + Assert.Equal( + new EncodedString(CharacterCode.ASCII, "StockSubmitter|Miscellaneous||Miscellaneous$|00|0000330000000110000000000000000|22$@NA_1005010.460@145$$@Miscellaneous.Miscellaneous$$@$@26$$@$@$@$@205$@$@$@$@$@$@$@$@$@43$@$@$@$$@Miscellaneous.Miscellaneous$$@90$$@22$@$@$@$@$@$@$|||"), + exifProfile.GetValue(ExifTag.UserComment).Value); + + image.Mutate(x => x.Crop(new(0, 0, 100, 100))); + + image.Save(ms, new JpegEncoder()); + + foreach (IExifValue val in image.Metadata.ExifProfile.Values) + { + this.Output.WriteLine($"{val.Tag}={val.GetValue()}"); + } + } + private static void VerifyEncodedStrings(ExifProfile exif) { Assert.NotNull(exif); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 4130474b58..f4f00c8fcc 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -325,6 +325,7 @@ public static class TestImages public const string Issue2067_CommentMarker = "Jpg/issues/issue-2067-comment.jpg"; public const string Issue2638 = "Jpg/issues/Issue2638.jpg"; public const string Issue2758 = "Jpg/issues/issue-2758.jpg"; + public const string Issue2857 = "Jpg/issues/issue-2857-subsub-ifds.jpg"; public static class Fuzz { diff --git a/tests/Images/Input/Jpg/issues/issue-2857-subsub-ifds.jpg b/tests/Images/Input/Jpg/issues/issue-2857-subsub-ifds.jpg new file mode 100644 index 0000000000..5e5288f22e --- /dev/null +++ b/tests/Images/Input/Jpg/issues/issue-2857-subsub-ifds.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ab45137ded01a42658aa94421165a358b184a536b6ab64427d8255e8d78c25b9 +size 2829977