From ad9f373ef7da1c762ce5ba9617a9c612f4674632 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Tue, 14 Apr 2020 18:27:42 +0200 Subject: [PATCH] Add support for writing IPTC metadata --- .../Formats/Jpeg/JpegEncoderCore.cs | 54 ++++++++++++++++--- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 32f4d22878..4791a04a0e 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -4,6 +4,7 @@ using System; using System.Buffers.Binary; using System.IO; +using System.Linq; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Jpeg.Components; @@ -13,6 +14,7 @@ using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; +using SixLabors.ImageSharp.Metadata.Profiles.Iptc; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Jpeg @@ -647,9 +649,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// Writes the EXIF profile. /// /// The exif profile. - /// - /// Thrown if the EXIF profile size exceeds the limit - /// private void WriteExifProfile(ExifProfile exifProfile) { if (exifProfile is null || exifProfile.Values.Count == 0) @@ -697,16 +696,56 @@ namespace SixLabors.ImageSharp.Formats.Jpeg } } + /// + /// Writes the IPTC metadata. + /// + /// The iptc metadata to write. + private void WriteIptcProfile(IptcProfile iptcProfile) + { + if (iptcProfile is null || !iptcProfile.Values.Any()) + { + return; + } + + iptcProfile.UpdateData(); + var data = iptcProfile.Data; + if (data.Length == 0) + { + return; + } + + var app13length = data.Length + ProfileResolver.AdobeImageResourceBlockMarker.Length + ProfileResolver.AdobeIptcMarker.Length + 2 + 4; + this.WriteAppHeader(app13length, JpegConstants.Markers.APP13); + this.outputStream.Write(this.buffer, 0, 4); + this.outputStream.Write(ProfileResolver.AdobeImageResourceBlockMarker); + this.outputStream.Write(ProfileResolver.AdobeIptcMarker); + this.outputStream.WriteByte(0); // a null name consists of two bytes of 0. + this.outputStream.WriteByte(0); + BinaryPrimitives.WriteInt32BigEndian(this.buffer, data.Length); + this.outputStream.Write(this.buffer, 0, 4); + this.outputStream.Write(data, 0, data.Length); + } + /// /// Writes the App1 header. /// - /// The length of the data the app1 marker contains + /// The length of the data the app1 marker contains. private void WriteApp1Header(int app1Length) + { + this.WriteAppHeader(app1Length, JpegConstants.Markers.APP1); + } + + /// + /// Writes a AppX header. + /// + /// The length of the data the app marker contains. + /// The app marker to write. + private void WriteAppHeader(int length, byte appMarker) { this.buffer[0] = JpegConstants.Markers.XFF; - this.buffer[1] = JpegConstants.Markers.APP1; // Application Marker - this.buffer[2] = (byte)((app1Length >> 8) & 0xFF); - this.buffer[3] = (byte)(app1Length & 0xFF); + this.buffer[1] = appMarker; + this.buffer[2] = (byte)((length >> 8) & 0xFF); + this.buffer[3] = (byte)(length & 0xFF); this.outputStream.Write(this.buffer, 0, 4); } @@ -805,6 +844,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg metadata.SyncProfiles(); this.WriteExifProfile(metadata.ExifProfile); this.WriteIccProfile(metadata.IccProfile); + this.WriteIptcProfile(metadata.IptcProfile); } ///