diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 4560af05a..a143723e1 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -213,6 +213,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg // Write the Start Of Image marker. this.WriteApplicationHeader((short)image.MetaData.HorizontalResolution, (short)image.MetaData.VerticalResolution); + // Write Exif and ICC profiles this.WriteProfiles(image); // Write the quantization tables. @@ -608,27 +609,57 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// private void WriteExifProfile(ExifProfile exifProfile) { - const int Max = 65533; + const int MaxBytesApp1 = 65533; + const int MaxBytesWithExifId = 65527; byte[] data = exifProfile?.ToByteArray(ProfileResolver.ExifMarker); if (data == null || data.Length == 0) { return; } - if (data.Length > Max) + int remaining = data.Length; + int bytesToWrite = remaining > MaxBytesApp1 ? MaxBytesApp1 : remaining; + int app1Length = bytesToWrite + 2; + + // write the app1 header + this.WriteApp1Header(app1Length); + + // write the exif data + this.outputStream.Write(data, 0, bytesToWrite); + remaining -= bytesToWrite; + + // if the exif data exceeds 64K, write it in multiple APP1 Markers + for (int idx = MaxBytesApp1; idx < data.Length; idx += MaxBytesWithExifId) { - throw new ImageFormatException($"Exif profile size exceeds limit of {Max} bytes."); - } + bytesToWrite = remaining > MaxBytesWithExifId ? MaxBytesWithExifId : remaining; + app1Length = bytesToWrite + 2 + 6; + + // write the app1 header + this.WriteApp1Header(app1Length); + + // write Exif00 marker + ProfileResolver.ExifMarker.AsSpan().CopyTo(this.buffer.AsSpan()); + this.outputStream.Write(this.buffer, 0, 6); - int length = data.Length + 2; + // write the exif data + this.outputStream.Write(data, idx, bytesToWrite); + remaining -= bytesToWrite; + } + } + + /// + /// Writes the App1 header. + /// + /// The length of the data the app1 marker contains + private void WriteApp1Header(int app1Length) + { this.buffer[0] = JpegConstants.Markers.XFF; this.buffer[1] = JpegConstants.Markers.APP1; // Application Marker - this.buffer[2] = (byte)((length >> 8) & 0xFF); - this.buffer[3] = (byte)(length & 0xFF); + this.buffer[2] = (byte)((app1Length >> 8) & 0xFF); + this.buffer[3] = (byte)(app1Length & 0xFF); this.outputStream.Write(this.buffer, 0, 4); - this.outputStream.Write(data, 0, data.Length); } ///