diff --git a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.Operator.cs b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.Operator.cs index 39dec7ba98..3b2ab914b3 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.Operator.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.Operator.cs @@ -4,6 +4,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; +using SixLabors.ImageSharp.Common.Helpers; namespace SixLabors.ImageSharp.Formats.Jpeg.Components; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs index d70e85476e..2bd4b95fdd 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs @@ -42,6 +42,11 @@ internal class SpectralConverter : SpectralConverter, IDisposable /// private IMemoryOwner rgbBuffer; + /// + /// Proxy buffer used in packing from RGB to target TPixel pixels. + /// + private IMemoryOwner paddedProxyPixelRow; + /// /// Resulting 2D pixel buffer. /// @@ -158,8 +163,19 @@ internal class SpectralConverter : SpectralConverter, IDisposable SimdUtils.NormalizedFloatToByteSaturate(values.Component1, g); SimdUtils.NormalizedFloatToByteSaturate(values.Component2, b); - Span destination = this.pixelBuffer.DangerousGetRowSpan(yy); - PixelOperations.Instance.PackFromRgbPlanes(r, g, b, destination); + // PackFromRgbPlanes expects the destination to be padded, so try to get padded span containing extra elements from the next row. + // If we can't get such a padded row because we are on a MemoryGroup boundary or at the last row, + // pack pixels to a temporary, padded proxy buffer, then copy the relevant values to the destination row. + if (this.pixelBuffer.DangerousTryGetPaddedRowSpan(yy, 3, out Span destRow)) + { + PixelOperations.Instance.PackFromRgbPlanes(r, g, b, destRow); + } + else + { + Span proxyRow = this.paddedProxyPixelRow.GetSpan(); + PixelOperations.Instance.PackFromRgbPlanes(r, g, b, proxyRow); + proxyRow[..width].CopyTo(this.pixelBuffer.DangerousGetRowSpan(yy)); + } } this.pixelRowCounter += this.pixelRowsPerStep; @@ -198,6 +214,7 @@ internal class SpectralConverter : SpectralConverter, IDisposable pixelSize.Height, this.Configuration.PreferContiguousImageBuffers, AllocationOptions.Clean); + this.paddedProxyPixelRow = allocator.Allocate(pixelSize.Width + 3); // Component processors from spectral to RGB int bufferWidth = majorBlockWidth * blockPixelSize; @@ -258,6 +275,7 @@ internal class SpectralConverter : SpectralConverter, IDisposable } this.rgbBuffer?.Dispose(); + this.paddedProxyPixelRow?.Dispose(); this.pixelBuffer?.Dispose(); } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 47c8d45a63..c9b684009e 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -90,13 +90,11 @@ internal sealed unsafe partial class JpegEncoderCore this.WriteApp14Marker(frameConfig.AdobeColorTransformMarkerFlag.Value, buffer); } - if (!this.encoder.SkipMetadata) - { - // Profiles and comments are optional application metadata and must not leak into a containing format - // when the containing encoder has requested a metadata-free embedded JPEG payload. - this.WriteProfiles(metadata, buffer); - this.WriteComments(image.Configuration, jpegMetadata); - } + // Write Exif, XMP, ICC and IPTC profiles + this.WriteProfiles(metadata, buffer); + + // Write comments + this.WriteComments(image.Configuration, jpegMetadata); // Write the image dimensions. this.WriteStartOfFrame(image.Width, image.Height, frameConfig, buffer); diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index fe1de830f0..caf2393d89 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -1057,7 +1057,7 @@ internal sealed class PngEncoderCore : IDisposable /// CICP matrix coefficients other than Identity are not supported in PNG. private void WriteCicpChunk(Stream stream, ImageMetadata metaData) { - if (this.chunkFilter == PngChunkFilter.ExcludeAll || metaData.CicpProfile is null) + if (metaData.CicpProfile is null) { return; }