From ebb277a7942e0c18069bb103294661ec6c774d4d Mon Sep 17 00:00:00 2001 From: Ildar Khayrutdinov Date: Fri, 17 Sep 2021 10:34:29 +0300 Subject: [PATCH] try improve reading ext values --- .../Formats/Tiff/Ifd/DirectoryReader.cs | 25 ++++---- .../Formats/Tiff/Ifd/EntryReader.cs | 10 +--- .../Metadata/Profiles/Exif/ExifReader.cs | 57 +++++++++---------- 3 files changed, 41 insertions(+), 51 deletions(-) diff --git a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs index f6bc33079..3c70ee591 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs @@ -18,10 +18,6 @@ namespace SixLabors.ImageSharp.Formats.Tiff private ulong nextIfdOffset; - // used for sequential read big values (actual for multiframe big files) - // todo: different tags can link to the same data (stream offset) - investigate - private readonly SortedList lazyLoaders = new SortedList(new DuplicateKeyComparer()); - public DirectoryReader(Stream stream) => this.stream = stream; /// @@ -68,23 +64,28 @@ namespace SixLabors.ImageSharp.Formats.Tiff var readers = new List(); while (this.nextIfdOffset != 0 && this.nextIfdOffset < (ulong)this.stream.Length) { - var reader = new EntryReader(this.stream, this.ByteOrder, this.lazyLoaders); + var reader = new EntryReader(this.stream, this.ByteOrder); reader.ReadTags(isBigTiff, this.nextIfdOffset); - this.nextIfdOffset = reader.NextIfdOffset; + if (reader.ExtTags.Count > 0) + { + reader.ExtTags.Sort((t1, t2) => t1.offset.CompareTo(t2.offset)); - readers.Add(reader); - } + if (reader.ExtTags[0].offset < reader.NextIfdOffset) + { + // this means that most likely all elements are placed before next IFD + reader.ReadExtValues(); + } + } - // Sequential reading big values. - foreach (Action loader in this.lazyLoaders.Values) - { - loader(); + this.nextIfdOffset = reader.NextIfdOffset; + readers.Add(reader); } var list = new List(readers.Count); foreach (EntryReader reader in readers) { + reader.ReadExtValues(); var profile = new ExifProfile(reader.Values, reader.InvalidTags); list.Add(profile); } diff --git a/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs index 7884242ef..5a83febf8 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs @@ -12,13 +12,10 @@ namespace SixLabors.ImageSharp.Formats.Tiff { internal class EntryReader : BaseExifReader { - private readonly SortedList lazyLoaders; - - public EntryReader(Stream stream, ByteOrder byteOrder, SortedList lazyLoaders) + public EntryReader(Stream stream, ByteOrder byteOrder) : base(stream) { this.IsBigEndian = byteOrder == ByteOrder.BigEndian; - this.lazyLoaders = lazyLoaders; } public List Values { get; } = new List(); @@ -43,8 +40,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff } } - protected override void RegisterExtLoader(ulong offset, Action reader) => - this.lazyLoaders.Add(offset, reader); + public void ReadExtValues() => this.ReadExtValues(this.Values); } internal class HeaderReader : BaseExifReader @@ -81,7 +77,5 @@ namespace SixLabors.ImageSharp.Formats.Tiff TiffThrowHelper.ThrowInvalidHeader(); } - - protected override void RegisterExtLoader(ulong offset, Action reader) => throw new NotSupportedException(); } } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index a63a40d66..0cac35197 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -14,8 +14,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { internal class ExifReader : BaseExifReader { - private readonly List loaders = new List(); - public ExifReader(byte[] exifData) : base(new MemoryStream(exifData ?? throw new ArgumentNullException(nameof(exifData)))) { @@ -41,22 +39,16 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif uint ifdOffset = this.ReadUInt32(); this.ReadValues(values, ifdOffset); + this.ReadExtValues(values); uint thumbnailOffset = this.ReadUInt32(); this.GetThumbnail(thumbnailOffset); this.ReadSubIfd(values); - foreach (Action loader in this.loaders) - { - loader(); - } - return values; } - protected override void RegisterExtLoader(ulong offset, Action loader) => this.loaders.Add(loader); - private void GetThumbnail(uint offset) { if (offset == 0) @@ -121,7 +113,17 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif public bool IsBigEndian { get; protected set; } - protected abstract void RegisterExtLoader(ulong offset, Action loader); + public List<(ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif)> ExtTags { get; } = new (); + + protected void ReadExtValues(List values) + { + foreach ((ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag in this.ExtTags) + { + this.ReadExtValue(values, tag); + } + + this.ExtTags.Clear(); + } /// /// Reads the values to the values collection. @@ -173,6 +175,18 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } } + protected void ReadExtValue(IList values, (ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) tag) + { + ulong size = tag.numberOfComponents * ExifDataTypes.GetSize(tag.dataType); + byte[] dataBuffer = new byte[size]; + this.Seek(tag.offset); + if (this.TryReadSpan(dataBuffer)) + { + object value = this.ConvertValue(tag.dataType, dataBuffer, tag.numberOfComponents); + this.Add(values, tag.exif, value); + } + } + protected void ReadSubIfd64(List values) { if (this.exifOffset != 0) @@ -375,21 +389,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return; } - this.RegisterExtLoader(newOffset, () => - { - byte[] dataBuffer = new byte[size]; - this.Seek(newOffset); - if (this.TryReadSpan(dataBuffer)) - { - object value = this.ConvertValue(dataType, dataBuffer, numberOfComponents); - this.Add(values, exifValue, value); - } - }); + this.ExtTags.Add((newOffset, dataType, numberOfComponents, exifValue)); } else { object value = this.ConvertValue(dataType, this.offsetBuffer, numberOfComponents); - this.Add(values, exifValue, value); } } @@ -465,16 +469,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return; } - this.RegisterExtLoader(newOffset, () => - { - byte[] dataBuffer = new byte[size]; - this.Seek(newOffset); - if (this.TryReadSpan(dataBuffer)) - { - object value = this.ConvertValue(dataType, dataBuffer, numberOfComponents); - this.Add(values, exifValue, value); - } - }); + this.ExtTags.Add((newOffset, dataType, numberOfComponents, exifValue)); } else {