diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 1310d90d26..bd5a9e10f0 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -6,6 +6,7 @@ using System.IO; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Formats.Jpeg.Components; +using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Icc; @@ -608,7 +609,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private void WriteExifProfile(ExifProfile exifProfile) { const int Max = 65533; - byte[] data = exifProfile?.ToByteArray(); + byte[] data = exifProfile?.ToByteArray(ProfileResolver.ExifMarker); if (data == null || data.Length == 0) { return; diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 9e0f5f877e..fedd46063d 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -536,7 +536,7 @@ namespace SixLabors.ImageSharp.Formats.Png { if (image.MetaData.ExifProfile?.Values.Count > 0) { - this.WriteChunk(stream, PngChunkType.Exif, image.MetaData.ExifProfile.ToByteArray(includeExifIdCode: false)); + this.WriteChunk(stream, PngChunkType.Exif, image.MetaData.ExifProfile.ToByteArray()); } } diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index 78fa63ae75..b38097060e 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; @@ -234,20 +233,13 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Converts this instance to a byte array. /// - /// Indicates, if the Exif ID code should be included. - /// The Exif Id Code is part of the JPEG APP1 segment. This Exif ID code should not be included in case of PNG's. - /// Defaults to true. + /// The Exif Id Code is part of the JPEG APP1 segment (Exif00). Those bytes will be written at + /// the beginning of the array. This Exif ID code should not be included in case of PNG's. /// The - public byte[] ToByteArray(bool includeExifIdCode = true) + public byte[] ToByteArray(ReadOnlySpan exifIdCode = default) { if (this.values == null) { - if (!includeExifIdCode && this.StartsWithExifIdCode(this.data)) - { - // skip the first 6 bytes (the Exif Code) - return this.data.Skip(6).ToArray(); - } - return this.data; } @@ -257,31 +249,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } var writer = new ExifWriter(this.values, this.Parts); - return writer.GetData(includeExifIdCode); - } - - /// - /// Checks if a byte array start with the Exif Code: ASCII "Exif" followed by two zeros. - /// - /// The byte array to check for the Exif Code. - /// True, if the byte array starts with the Exif Code - private bool StartsWithExifIdCode(byte[] exifBytes) - { - if (exifBytes.Length < 6) - { - return false; - } - - int exifLength = ProfileResolver.ExifMarker.Length; - for (int i = 0; i < ProfileResolver.ExifMarker.Length; i++) - { - if (exifBytes[i] != ProfileResolver.ExifMarker[i]) - { - return false; - } - } - - return true; + return writer.GetData(exifIdCode); } /// diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs index ff0c6bf5c9..1de5fbd5cf 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs @@ -5,7 +5,6 @@ using System; using System.Buffers.Binary; using System.Collections.Generic; using System.Text; -using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; using SixLabors.ImageSharp.Primitives; namespace SixLabors.ImageSharp.MetaData.Profiles.Exif @@ -42,15 +41,15 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Returns the EXIF data. /// - /// Indicates, if the Exif ID code should be included. - /// The Exif Id Code is part of the JPEG APP1 segment. This Exif ID code should not be included in case of PNG's. - /// Defaults to true. + /// The Exif Id Code is part of the JPEG APP1 segment (Exif00). Those bytes will be written at + /// the beginning of the array. This Exif ID code should not be included in case of PNG's. /// /// The . /// - public byte[] GetData(bool includeExifIdCode = true) + public byte[] GetData(ReadOnlySpan exifIdCode) { - uint startIndex = (uint)ProfileResolver.ExifMarker.Length; + uint exifIdCodeLength = exifIdCode.IsEmpty ? 0 : (uint)exifIdCode.Length; + uint startIndex = exifIdCodeLength; uint length; int exifIndex = -1; int gpsIndex = -1; @@ -86,17 +85,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return null; } - if (includeExifIdCode) - { - // Exif Id Code "Exif00" (6 bytes) - length += (uint)ProfileResolver.ExifMarker.Length; - } - else - { - // special case for PNG eXIf Chunk: - // if the Exif Code ("Exif00") is not included, the start index is 0 instead of 6 - startIndex = 0; - } + length += exifIdCodeLength; // two bytes for the byte Order marker 'II', followed by the number 42 (0x2A) and a 0, making 4 bytes total length += (uint)ExifConstants.LittleEndianByteOrderMarker.Length; @@ -106,10 +95,10 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif byte[] result = new byte[length]; int i = 0; - if (includeExifIdCode) + if (!exifIdCode.IsEmpty) { - ProfileResolver.ExifMarker.AsSpan().CopyTo(result); // 0-5 - i += ProfileResolver.ExifMarker.Length; + exifIdCode.CopyTo(result); // 0-5 + i += exifIdCode.Length; } // the byte order marker for little-endian, followed by the number 42 and a 0 diff --git a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs index 255451e0e6..7d0686aa76 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.PixelFormats; @@ -32,6 +33,7 @@ namespace SixLabors.ImageSharp.Tests ImageMetaData clone = metaData.Clone(); Assert.Equal(exifProfile.ToByteArray(), clone.ExifProfile.ToByteArray()); + Assert.Equal(exifProfile.ToByteArray(ProfileResolver.ExifMarker), clone.ExifProfile.ToByteArray(ProfileResolver.ExifMarker)); Assert.Equal(4, clone.HorizontalResolution); Assert.Equal(2, clone.VerticalResolution); Assert.Equal(imageProperty, clone.Properties[0]); diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs index 2192d134ed..7d4ddd3227 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs @@ -324,7 +324,7 @@ namespace SixLabors.ImageSharp.Tests // Force parsing of the profile. Assert.Equal(24, profile.Values.Count); - byte[] bytes = profile.ToByteArray(); + byte[] bytes = profile.ToByteArray(ProfileResolver.ExifMarker); Assert.Equal(495, bytes.Length); } @@ -360,21 +360,21 @@ namespace SixLabors.ImageSharp.Tests // arrange byte[] exifBytesWithExifCode = ProfileResolver.ExifMarker.Concat(ExifConstants.LittleEndianByteOrderMarker).ToArray(); byte[] exifBytesWithoutExifCode = ExifConstants.LittleEndianByteOrderMarker; - var profile = new ExifProfile(exifBytesWithExifCode); + ExifProfile profile = CreateExifProfile(); // act - byte[] actual = profile.ToByteArray(includeExifIdCode); + byte[] actual = profile.ToByteArray(includeExifIdCode ? ProfileResolver.ExifMarker : default(ReadOnlySpan)); // assert Assert.NotNull(actual); Assert.NotEmpty(actual); if (includeExifIdCode) { - Assert.Equal(exifBytesWithExifCode, actual); + Assert.Equal(exifBytesWithExifCode, actual.Take(exifBytesWithExifCode.Length).ToArray()); } else { - Assert.Equal(exifBytesWithoutExifCode, actual); + Assert.Equal(exifBytesWithoutExifCode, actual.Take(exifBytesWithoutExifCode.Length).ToArray()); } } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/AutoOrientTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/AutoOrientTests.cs index bae22e7a92..9f353f8132 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/AutoOrientTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/AutoOrientTests.cs @@ -9,6 +9,7 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { + using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; using SixLabors.ImageSharp.Processing.Transforms; public class AutoOrientTests : FileTestBase @@ -65,7 +66,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms var profile = new ExifProfile(); profile.SetValue(ExifTag.JPEGTables, orientation); - byte[] bytes = profile.ToByteArray(); + byte[] bytes = profile.ToByteArray(ProfileResolver.ExifMarker); // Change the tag into ExifTag.Orientation bytes[16] = 18; bytes[17] = 1;