From 6f2304bf6f9b80456c764aa06284b5b2f4ae26dc Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 26 Apr 2020 16:19:50 +0200 Subject: [PATCH 1/3] Identify now parses zTXt and iTXt chunks --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 6 ++ .../Formats/Png/PngMetadataTests.cs | 59 +++++++++++-------- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 0247dba351..7d9011a55a 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -273,6 +273,12 @@ namespace SixLabors.ImageSharp.Formats.Png case PngChunkType.Text: this.ReadTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length)); break; + case PngChunkType.CompressedText: + this.ReadCompressedTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length)); + break; + case PngChunkType.InternationalText: + this.ReadInternationalTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length)); + break; case PngChunkType.End: this.isEndChunkReached = true; break; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs index 5f5d5fd3d7..ee4e4f3c27 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs @@ -56,17 +56,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png using (Image image = provider.GetImage(new PngDecoder())) { PngMetadata meta = image.Metadata.GetFormatMetadata(PngFormat.Instance); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Comment") && m.Value.Equals("comment")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Author") && m.Value.Equals("ImageSharp")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Copyright") && m.Value.Equals("ImageSharp")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Title") && m.Value.Equals("unittest")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Description") && m.Value.Equals("compressed-text")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("International") && m.Value.Equals("'e', mu'tlheghvam, ghaH yu'") && m.LanguageTag.Equals("x-klingon") && m.TranslatedKeyword.Equals("warning")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("International2") && m.Value.Equals("ИМАГЕШАРП") && m.LanguageTag.Equals("rus")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("CompressedInternational") && m.Value.Equals("la plume de la mante") && m.LanguageTag.Equals("fra") && m.TranslatedKeyword.Equals("foobar")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("CompressedInternational2") && m.Value.Equals("這是一個考驗") && m.LanguageTag.Equals("chinese")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("NoLang") && m.Value.Equals("this text chunk is missing a language tag")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("NoTranslatedKeyword") && m.Value.Equals("dieser chunk hat kein übersetztes Schlüßelwort")); + VerifyTextDataIsPresent(meta); } } @@ -85,17 +75,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png using (Image image = decoder.Decode(Configuration.Default, memoryStream)) { PngMetadata meta = image.Metadata.GetFormatMetadata(PngFormat.Instance); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Comment") && m.Value.Equals("comment")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Author") && m.Value.Equals("ImageSharp")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Copyright") && m.Value.Equals("ImageSharp")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Title") && m.Value.Equals("unittest")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Description") && m.Value.Equals("compressed-text")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("International") && m.Value.Equals("'e', mu'tlheghvam, ghaH yu'") && m.LanguageTag.Equals("x-klingon") && m.TranslatedKeyword.Equals("warning")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("International2") && m.Value.Equals("ИМАГЕШАРП") && m.LanguageTag.Equals("rus")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("CompressedInternational") && m.Value.Equals("la plume de la mante") && m.LanguageTag.Equals("fra") && m.TranslatedKeyword.Equals("foobar")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("CompressedInternational2") && m.Value.Equals("這是一個考驗") && m.LanguageTag.Equals("chinese")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("NoLang") && m.Value.Equals("this text chunk is missing a language tag")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("NoTranslatedKeyword") && m.Value.Equals("dieser chunk hat kein übersetztes Schlüßelwort")); + VerifyTextDataIsPresent(meta); } } } @@ -178,7 +158,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png IgnoreMetadata = true }; - var testFile = TestFile.Create(TestImages.Png.Blur); + var testFile = TestFile.Create(TestImages.Png.PngWithMetadata); using (Image image = testFile.CreateRgba32Image(options)) { @@ -220,5 +200,38 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png Assert.Equal(resolutionUnit, meta.ResolutionUnits); } } + + [Theory] + [InlineData(TestImages.Png.PngWithMetadata)] + public void Identify_ReadsTextData(string imagePath) + { + var testFile = TestFile.Create(imagePath); + using (var stream = new MemoryStream(testFile.Bytes, false)) + { + IImageInfo imageInfo = Image.Identify(stream); + Assert.NotNull(imageInfo); + PngMetadata meta = imageInfo.Metadata.GetFormatMetadata(PngFormat.Instance); + VerifyTextDataIsPresent(meta); + } + } + + private static void VerifyTextDataIsPresent(PngMetadata meta) + { + Assert.NotNull(meta); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("Comment") && m.Value.Equals("comment")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("Author") && m.Value.Equals("ImageSharp")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("Copyright") && m.Value.Equals("ImageSharp")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("Title") && m.Value.Equals("unittest")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("Description") && m.Value.Equals("compressed-text")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("International") && m.Value.Equals("'e', mu'tlheghvam, ghaH yu'") && + m.LanguageTag.Equals("x-klingon") && m.TranslatedKeyword.Equals("warning")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("International2") && m.Value.Equals("ИМАГЕШАРП") && m.LanguageTag.Equals("rus")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("CompressedInternational") && m.Value.Equals("la plume de la mante") && + m.LanguageTag.Equals("fra") && m.TranslatedKeyword.Equals("foobar")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("CompressedInternational2") && m.Value.Equals("這是一個考驗") && + m.LanguageTag.Equals("chinese")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("NoLang") && m.Value.Equals("this text chunk is missing a language tag")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("NoTranslatedKeyword") && m.Value.Equals("dieser chunk hat kein übersetztes Schlüßelwort")); + } } } From 03547d078c5d47a4bcc8185a869daf1237baeab0 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 26 Apr 2020 17:32:22 +0200 Subject: [PATCH 2/3] Identify reads now exif data --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 9 +++ .../Formats/Png/PngMetadataTests.cs | 58 ++++++++++++++++++ tests/Images/Input/Png/PngWithMetaData.png | Bin 805 -> 751 bytes 3 files changed, 67 insertions(+) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 7d9011a55a..a5bcff3b2b 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -278,6 +278,15 @@ namespace SixLabors.ImageSharp.Formats.Png break; case PngChunkType.InternationalText: this.ReadInternationalTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length)); + break; + case PngChunkType.Exif: + if (!this.ignoreMetadata) + { + var exifData = new byte[chunk.Length]; + Buffer.BlockCopy(chunk.Data.Array, 0, exifData, 0, chunk.Length); + metadata.ExifProfile = new ExifProfile(exifData); + } + break; case PngChunkType.End: this.isEndChunkReached = true; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs index ee4e4f3c27..bf42066002 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Metadata; +using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.PixelFormats; using Xunit; @@ -129,6 +130,40 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } } + [Theory] + [WithFile(TestImages.Png.PngWithMetadata, PixelTypes.Rgba32)] + public void Decode_ReadsExifData(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + var decoder = new PngDecoder + { + IgnoreMetadata = false + }; + + using (Image image = provider.GetImage(decoder)) + { + Assert.NotNull(image.Metadata.ExifProfile); + ExifProfile exif = image.Metadata.ExifProfile; + VerifyExifDataIsPresent(exif); + } + } + + [Theory] + [WithFile(TestImages.Png.PngWithMetadata, PixelTypes.Rgba32)] + public void Decode_IgnoresExifData_WhenIgnoreMetadataIsTrue(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + var decoder = new PngDecoder + { + IgnoreMetadata = true + }; + + using (Image image = provider.GetImage(decoder)) + { + Assert.Null(image.Metadata.ExifProfile); + } + } + [Fact] public void Decode_IgnoreMetadataIsFalse_TextChunkIsRead() { @@ -215,6 +250,29 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } } + [Theory] + [InlineData(TestImages.Png.PngWithMetadata)] + public void Identify_ReadsExifData(string imagePath) + { + var testFile = TestFile.Create(imagePath); + using (var stream = new MemoryStream(testFile.Bytes, false)) + { + IImageInfo imageInfo = Image.Identify(stream); + Assert.NotNull(imageInfo); + Assert.NotNull(imageInfo.Metadata.ExifProfile); + ExifProfile exif = imageInfo.Metadata.ExifProfile; + VerifyExifDataIsPresent(exif); + } + } + + private static void VerifyExifDataIsPresent(ExifProfile exif) + { + Assert.Equal(1, exif.Values.Count); + IExifValue software = exif.GetValue(ExifTag.Software); + Assert.NotNull(software); + Assert.Equal("ImageSharp", software.Value); + } + private static void VerifyTextDataIsPresent(PngMetadata meta) { Assert.NotNull(meta); diff --git a/tests/Images/Input/Png/PngWithMetaData.png b/tests/Images/Input/Png/PngWithMetaData.png index af417b1f307329d72b536ab69170c1a06399d745..b5d0d344d7cf111b4f5d1784fac9b4fb1439b61a 100644 GIT binary patch delta 251 zcmZ3=_MUZu3J-IDPl#)2Qgob=n8m~ziHRx#2I{F1o@t(*S_~Wv3=E76hKx)M+(4ET z5UT>QXKrG8YH&tkQ2~&1JGcAg#9gH-(j~4DB`&GO$wiq3C7Jno49WSq1x2aF#i=Q} zC8-r9q8%#tCdV-PFj`Jt$tVLfCaoxuAuT^YDY1wlCsCmwr!+TJAthA-$j(j7D@ncM z6&^PE6XOC#TcCPrEhC^+$r+h>sl}-b&QSVg!^~$h)<4=1|x&vL^h2(ALIT{R%G;HbetT(B(2B5$dFc)$dHzw zpOjbx)N|T1MB{|!S>I3(&(IT|At!v#XnV3Uc>ZFSSvfU1eDZq61&nS$jk1P}49OXp zd8x&z49-xxVovog6zWSG$*yO&byLjPG(bE!!a%Y|ZmJF38lczFSb250k`njxg HN@xNA#T9AI From 386d942e1203439580ce9b182991a3f10016d125 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 26 Apr 2020 20:29:30 +0200 Subject: [PATCH 3/3] Fix png test image: Some text chunks unintentional changed to none compressed --- tests/Images/Input/Png/PngWithMetaData.png | Bin 751 -> 777 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/Images/Input/Png/PngWithMetaData.png b/tests/Images/Input/Png/PngWithMetaData.png index b5d0d344d7cf111b4f5d1784fac9b4fb1439b61a..2f167bd794368f92d6c86014deb14530cce4b4c5 100644 GIT binary patch delta 173 zcmaFQ+Q~NIudYf}NJNQCYH@N=W3VjE<87n56X>7#Y%v5*gC+^OF*bfO<}QhG?A7JnI|k;Td|uGvtKt8EsEi z2G3vYGApMhhfiM5xPZ|Os8QCCks&!FGcUC`mBATGSInutY4G`G&sYC46Pw%@br&!E VDSBGMQ0~kVz>=Y|Wb#y|C;)~DL6QIf delta 147 zcmeBVd(S%IuZnbuYeb1lYH@N=WlGHn1;bD^xFfL%U1!|Dh tU|>kj$jnPEPGxY0(k~lkKAW-r$&QAn4c#vqnqRJ*zH@<>)a3O{Q2