diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs index c3a9c212ee..a451e111d2 100644 --- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs +++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs @@ -27,11 +27,11 @@ public static IImageEncoder DetectEncoder(this Image source, string filePath) Guard.NotNull(filePath, nameof(filePath)); string ext = Path.GetExtension(filePath); - if (!source.GetConfiguration().ImageFormatsManager.TryFindFormatByFileExtension(ext, out IImageFormat? format)) + if (!source.Configuration.ImageFormatsManager.TryFindFormatByFileExtension(ext, out IImageFormat? format)) { StringBuilder sb = new(); sb = sb.AppendLine(CultureInfo.InvariantCulture, $"No encoder was found for extension '{ext}'. Registered encoders include:"); - foreach (IImageFormat fmt in source.GetConfiguration().ImageFormats) + foreach (IImageFormat fmt in source.Configuration.ImageFormats) { sb = sb.AppendFormat(CultureInfo.InvariantCulture, " - {0} : {1}{2}", fmt.Name, string.Join(", ", fmt.FileExtensions), Environment.NewLine); } @@ -39,13 +39,13 @@ public static IImageEncoder DetectEncoder(this Image source, string filePath) throw new UnknownImageFormatException(sb.ToString()); } - IImageEncoder? encoder = source.GetConfiguration().ImageFormatsManager.GetEncoder(format); + IImageEncoder? encoder = source.Configuration.ImageFormatsManager.GetEncoder(format); if (encoder is null) { StringBuilder sb = new(); sb = sb.AppendLine(CultureInfo.InvariantCulture, $"No encoder was found for extension '{ext}' using image format '{format.Name}'. Registered encoders include:"); - foreach (KeyValuePair enc in source.GetConfiguration().ImageFormatsManager.ImageEncoders) + foreach (KeyValuePair enc in source.Configuration.ImageFormatsManager.ImageEncoders) { sb = sb.AppendFormat(CultureInfo.InvariantCulture, " - {0} : {1}{2}", enc.Key, enc.Value.GetType().Name, Environment.NewLine); } @@ -76,30 +76,6 @@ public static void AcceptVisitor(this Image source, IImageVisitor visitor) public static Task AcceptVisitorAsync(this Image source, IImageVisitorAsync visitor, CancellationToken cancellationToken = default) => source.AcceptAsync(visitor, cancellationToken); - /// - /// Gets the configuration for the image. - /// - /// The source image. - /// Returns the configuration. - public static Configuration GetConfiguration(this Image source) - => GetConfiguration((IConfigurationProvider)source); - - /// - /// Gets the configuration for the image frame. - /// - /// The source image. - /// Returns the configuration. - public static Configuration GetConfiguration(this ImageFrame source) - => GetConfiguration((IConfigurationProvider)source); - - /// - /// Gets the configuration. - /// - /// The source image - /// Returns the bounds of the image - private static Configuration GetConfiguration(IConfigurationProvider source) - => source?.Configuration ?? Configuration.Default; - /// /// Gets the representation of the pixels as a containing the backing pixel data of the image /// stored in row major order, as a list of contiguous blocks in the source image's pixel format. @@ -167,12 +143,4 @@ public static Memory DangerousGetPixelRowMemory(this Image - /// Gets the assigned to 'source'. - /// - /// The source image. - /// Returns the configuration. - internal static MemoryAllocator GetMemoryAllocator(this IConfigurationProvider source) - => GetConfiguration(source).MemoryAllocator; } diff --git a/src/ImageSharp/Advanced/IConfigurationProvider.cs b/src/ImageSharp/Advanced/IConfigurationProvider.cs index 086461f448..bb6d124f68 100644 --- a/src/ImageSharp/Advanced/IConfigurationProvider.cs +++ b/src/ImageSharp/Advanced/IConfigurationProvider.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Advanced; /// /// Defines the contract for objects that can provide access to configuration. /// -internal interface IConfigurationProvider +public interface IConfigurationProvider { /// /// Gets the configuration which allows altering default behaviour or extending the library. diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs index 13af25f6c7..cebceabe09 100644 --- a/src/ImageSharp/Color/Color.cs +++ b/src/ImageSharp/Color/Color.cs @@ -251,7 +251,17 @@ public Color WithAlpha(float alpha) /// /// A hexadecimal string representation of the value. [MethodImpl(InliningOptions.ShortMethod)] - public string ToHex() => this.data.ToRgba32().ToHex(); + public string ToHex() + { + if (this.boxedHighPrecisionPixel is not null) + { + Rgba32 rgba = default; + this.boxedHighPrecisionPixel.ToRgba32(ref rgba); + return rgba.ToHex(); + } + + return this.data.ToRgba32().ToHex(); + } /// public override string ToString() => this.ToHex(); diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs index aecea7dedf..0081f6a1ae 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs @@ -32,7 +32,7 @@ public sealed class BmpEncoder : QuantizingImageEncoder /// protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken) { - BmpEncoderCore encoder = new(this, image.GetMemoryAllocator()); + BmpEncoderCore encoder = new(this, image.Configuration.MemoryAllocator); encoder.Encode(image, stream, cancellationToken); } } diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 9d5b8d0cfd..076d1adf00 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -119,7 +119,7 @@ public void Encode(Image image, Stream stream, CancellationToken Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); - Configuration configuration = image.GetConfiguration(); + Configuration configuration = image.Configuration; ImageMetadata metadata = image.Metadata; BmpMetadata bmpMetadata = metadata.GetBmpMetadata(); this.bitsPerPixel ??= bmpMetadata.BitsPerPixel; diff --git a/src/ImageSharp/Formats/Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs index 386b1bd1c3..150ee9ccf0 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoder.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs @@ -18,7 +18,7 @@ public sealed class GifEncoder : QuantizingImageEncoder /// protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken) { - GifEncoderCore encoder = new(image.GetConfiguration(), this); + GifEncoderCore encoder = new(image.Configuration, this); encoder.Encode(image, stream, cancellationToken); } } diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index ccf8feaccd..926cc091c7 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -189,7 +189,7 @@ private void EncodeAdditionalFrames( // This frame is reused to store de-duplicated pixel buffers. // This is more expensive memory-wise than de-duplicating indexed buffer but allows us to deduplicate // frames using both local and global palettes. - using ImageFrame encodingFrame = new(previousFrame.GetConfiguration(), previousFrame.Size()); + using ImageFrame encodingFrame = new(previousFrame.Configuration, previousFrame.Size()); for (int i = 1; i < image.Frames.Count; i++) { diff --git a/src/ImageSharp/Formats/ImageEncoder.cs b/src/ImageSharp/Formats/ImageEncoder.cs index d6870f716b..4acd29e81c 100644 --- a/src/ImageSharp/Formats/ImageEncoder.cs +++ b/src/ImageSharp/Formats/ImageEncoder.cs @@ -42,7 +42,7 @@ protected abstract void Encode(Image image, Stream stream, Cance private void EncodeWithSeekableStream(Image image, Stream stream, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { - Configuration configuration = image.GetConfiguration(); + Configuration configuration = image.Configuration; if (stream.CanSeek) { this.Encode(image, stream, cancellationToken); @@ -59,7 +59,7 @@ private void EncodeWithSeekableStream(Image image, Stream stream private async Task EncodeWithSeekableStreamAsync(Image image, Stream stream, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { - Configuration configuration = image.GetConfiguration(); + Configuration configuration = image.Configuration; if (stream.CanSeek) { await DoEncodeAsync(stream).ConfigureAwait(false); diff --git a/src/ImageSharp/Formats/ImageExtensions.Save.cs b/src/ImageSharp/Formats/ImageExtensions.Save.cs index 30f576e5c4..7e5989d6fc 100644 --- a/src/ImageSharp/Formats/ImageExtensions.Save.cs +++ b/src/ImageSharp/Formats/ImageExtensions.Save.cs @@ -59,7 +59,7 @@ public static Task SaveAsBmpAsync(this Image source, string path, CancellationTo public static void SaveAsBmp(this Image source, string path, BmpEncoder encoder) => source.Save( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(BmpFormat.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(BmpFormat.Instance)); /// /// Saves the image to the given stream with the Bmp format. @@ -73,7 +73,7 @@ public static void SaveAsBmp(this Image source, string path, BmpEncoder encoder) public static Task SaveAsBmpAsync(this Image source, string path, BmpEncoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(BmpFormat.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(BmpFormat.Instance), cancellationToken); /// @@ -106,7 +106,7 @@ public static Task SaveAsBmpAsync(this Image source, Stream stream, Cancellation public static void SaveAsBmp(this Image source, Stream stream, BmpEncoder encoder) => source.Save( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(BmpFormat.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(BmpFormat.Instance)); /// /// Saves the image to the given stream with the Bmp format. @@ -120,7 +120,7 @@ public static void SaveAsBmp(this Image source, Stream stream, BmpEncoder encode public static Task SaveAsBmpAsync(this Image source, Stream stream, BmpEncoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(BmpFormat.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(BmpFormat.Instance), cancellationToken); /// @@ -161,7 +161,7 @@ public static Task SaveAsGifAsync(this Image source, string path, CancellationTo public static void SaveAsGif(this Image source, string path, GifEncoder encoder) => source.Save( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(GifFormat.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(GifFormat.Instance)); /// /// Saves the image to the given stream with the Gif format. @@ -175,7 +175,7 @@ public static void SaveAsGif(this Image source, string path, GifEncoder encoder) public static Task SaveAsGifAsync(this Image source, string path, GifEncoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(GifFormat.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(GifFormat.Instance), cancellationToken); /// @@ -208,7 +208,7 @@ public static Task SaveAsGifAsync(this Image source, Stream stream, Cancellation public static void SaveAsGif(this Image source, Stream stream, GifEncoder encoder) => source.Save( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(GifFormat.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(GifFormat.Instance)); /// /// Saves the image to the given stream with the Gif format. @@ -222,7 +222,7 @@ public static void SaveAsGif(this Image source, Stream stream, GifEncoder encode public static Task SaveAsGifAsync(this Image source, Stream stream, GifEncoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(GifFormat.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(GifFormat.Instance), cancellationToken); /// @@ -263,7 +263,7 @@ public static Task SaveAsJpegAsync(this Image source, string path, CancellationT public static void SaveAsJpeg(this Image source, string path, JpegEncoder encoder) => source.Save( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(JpegFormat.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(JpegFormat.Instance)); /// /// Saves the image to the given stream with the Jpeg format. @@ -277,7 +277,7 @@ public static void SaveAsJpeg(this Image source, string path, JpegEncoder encode public static Task SaveAsJpegAsync(this Image source, string path, JpegEncoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(JpegFormat.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(JpegFormat.Instance), cancellationToken); /// @@ -310,7 +310,7 @@ public static Task SaveAsJpegAsync(this Image source, Stream stream, Cancellatio public static void SaveAsJpeg(this Image source, Stream stream, JpegEncoder encoder) => source.Save( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(JpegFormat.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(JpegFormat.Instance)); /// /// Saves the image to the given stream with the Jpeg format. @@ -324,7 +324,7 @@ public static void SaveAsJpeg(this Image source, Stream stream, JpegEncoder enco public static Task SaveAsJpegAsync(this Image source, Stream stream, JpegEncoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(JpegFormat.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(JpegFormat.Instance), cancellationToken); /// @@ -365,7 +365,7 @@ public static Task SaveAsPbmAsync(this Image source, string path, CancellationTo public static void SaveAsPbm(this Image source, string path, PbmEncoder encoder) => source.Save( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(PbmFormat.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(PbmFormat.Instance)); /// /// Saves the image to the given stream with the Pbm format. @@ -379,7 +379,7 @@ public static void SaveAsPbm(this Image source, string path, PbmEncoder encoder) public static Task SaveAsPbmAsync(this Image source, string path, PbmEncoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(PbmFormat.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(PbmFormat.Instance), cancellationToken); /// @@ -412,7 +412,7 @@ public static Task SaveAsPbmAsync(this Image source, Stream stream, Cancellation public static void SaveAsPbm(this Image source, Stream stream, PbmEncoder encoder) => source.Save( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(PbmFormat.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(PbmFormat.Instance)); /// /// Saves the image to the given stream with the Pbm format. @@ -426,7 +426,7 @@ public static void SaveAsPbm(this Image source, Stream stream, PbmEncoder encode public static Task SaveAsPbmAsync(this Image source, Stream stream, PbmEncoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(PbmFormat.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(PbmFormat.Instance), cancellationToken); /// @@ -467,7 +467,7 @@ public static Task SaveAsPngAsync(this Image source, string path, CancellationTo public static void SaveAsPng(this Image source, string path, PngEncoder encoder) => source.Save( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(PngFormat.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(PngFormat.Instance)); /// /// Saves the image to the given stream with the Png format. @@ -481,7 +481,7 @@ public static void SaveAsPng(this Image source, string path, PngEncoder encoder) public static Task SaveAsPngAsync(this Image source, string path, PngEncoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(PngFormat.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(PngFormat.Instance), cancellationToken); /// @@ -514,7 +514,7 @@ public static Task SaveAsPngAsync(this Image source, Stream stream, Cancellation public static void SaveAsPng(this Image source, Stream stream, PngEncoder encoder) => source.Save( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(PngFormat.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(PngFormat.Instance)); /// /// Saves the image to the given stream with the Png format. @@ -528,7 +528,7 @@ public static void SaveAsPng(this Image source, Stream stream, PngEncoder encode public static Task SaveAsPngAsync(this Image source, Stream stream, PngEncoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(PngFormat.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(PngFormat.Instance), cancellationToken); /// @@ -569,7 +569,7 @@ public static Task SaveAsQoiAsync(this Image source, string path, CancellationTo public static void SaveAsQoi(this Image source, string path, QoiEncoder encoder) => source.Save( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(QoiFormat.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(QoiFormat.Instance)); /// /// Saves the image to the given stream with the Qoi format. @@ -583,7 +583,7 @@ public static void SaveAsQoi(this Image source, string path, QoiEncoder encoder) public static Task SaveAsQoiAsync(this Image source, string path, QoiEncoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(QoiFormat.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(QoiFormat.Instance), cancellationToken); /// @@ -616,7 +616,7 @@ public static Task SaveAsQoiAsync(this Image source, Stream stream, Cancellation public static void SaveAsQoi(this Image source, Stream stream, QoiEncoder encoder) => source.Save( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(QoiFormat.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(QoiFormat.Instance)); /// /// Saves the image to the given stream with the Qoi format. @@ -630,7 +630,7 @@ public static void SaveAsQoi(this Image source, Stream stream, QoiEncoder encode public static Task SaveAsQoiAsync(this Image source, Stream stream, QoiEncoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(QoiFormat.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(QoiFormat.Instance), cancellationToken); /// @@ -671,7 +671,7 @@ public static Task SaveAsTgaAsync(this Image source, string path, CancellationTo public static void SaveAsTga(this Image source, string path, TgaEncoder encoder) => source.Save( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(TgaFormat.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(TgaFormat.Instance)); /// /// Saves the image to the given stream with the Tga format. @@ -685,7 +685,7 @@ public static void SaveAsTga(this Image source, string path, TgaEncoder encoder) public static Task SaveAsTgaAsync(this Image source, string path, TgaEncoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(TgaFormat.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(TgaFormat.Instance), cancellationToken); /// @@ -718,7 +718,7 @@ public static Task SaveAsTgaAsync(this Image source, Stream stream, Cancellation public static void SaveAsTga(this Image source, Stream stream, TgaEncoder encoder) => source.Save( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(TgaFormat.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(TgaFormat.Instance)); /// /// Saves the image to the given stream with the Tga format. @@ -732,7 +732,7 @@ public static void SaveAsTga(this Image source, Stream stream, TgaEncoder encode public static Task SaveAsTgaAsync(this Image source, Stream stream, TgaEncoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(TgaFormat.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(TgaFormat.Instance), cancellationToken); /// @@ -773,7 +773,7 @@ public static Task SaveAsTiffAsync(this Image source, string path, CancellationT public static void SaveAsTiff(this Image source, string path, TiffEncoder encoder) => source.Save( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(TiffFormat.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(TiffFormat.Instance)); /// /// Saves the image to the given stream with the Tiff format. @@ -787,7 +787,7 @@ public static void SaveAsTiff(this Image source, string path, TiffEncoder encode public static Task SaveAsTiffAsync(this Image source, string path, TiffEncoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(TiffFormat.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(TiffFormat.Instance), cancellationToken); /// @@ -820,7 +820,7 @@ public static Task SaveAsTiffAsync(this Image source, Stream stream, Cancellatio public static void SaveAsTiff(this Image source, Stream stream, TiffEncoder encoder) => source.Save( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(TiffFormat.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(TiffFormat.Instance)); /// /// Saves the image to the given stream with the Tiff format. @@ -834,7 +834,7 @@ public static void SaveAsTiff(this Image source, Stream stream, TiffEncoder enco public static Task SaveAsTiffAsync(this Image source, Stream stream, TiffEncoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(TiffFormat.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(TiffFormat.Instance), cancellationToken); /// @@ -875,7 +875,7 @@ public static Task SaveAsWebpAsync(this Image source, string path, CancellationT public static void SaveAsWebp(this Image source, string path, WebpEncoder encoder) => source.Save( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(WebpFormat.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(WebpFormat.Instance)); /// /// Saves the image to the given stream with the Webp format. @@ -889,7 +889,7 @@ public static void SaveAsWebp(this Image source, string path, WebpEncoder encode public static Task SaveAsWebpAsync(this Image source, string path, WebpEncoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(WebpFormat.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(WebpFormat.Instance), cancellationToken); /// @@ -922,7 +922,7 @@ public static Task SaveAsWebpAsync(this Image source, Stream stream, Cancellatio public static void SaveAsWebp(this Image source, Stream stream, WebpEncoder encoder) => source.Save( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(WebpFormat.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(WebpFormat.Instance)); /// /// Saves the image to the given stream with the Webp format. @@ -936,7 +936,7 @@ public static void SaveAsWebp(this Image source, Stream stream, WebpEncoder enco public static Task SaveAsWebpAsync(this Image source, Stream stream, WebpEncoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(WebpFormat.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(WebpFormat.Instance), cancellationToken); } diff --git a/src/ImageSharp/Formats/ImageExtensions.Save.tt b/src/ImageSharp/Formats/ImageExtensions.Save.tt index 538f62d041..d4f1ed233b 100644 --- a/src/ImageSharp/Formats/ImageExtensions.Save.tt +++ b/src/ImageSharp/Formats/ImageExtensions.Save.tt @@ -78,7 +78,7 @@ public static partial class ImageExtensions public static void SaveAs<#= fmt #>(this Image source, string path, <#= fmt #>Encoder encoder) => source.Save( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(<#= fmt #>Format.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(<#= fmt #>Format.Instance)); /// /// Saves the image to the given stream with the <#= fmt #> format. @@ -92,7 +92,7 @@ public static partial class ImageExtensions public static Task SaveAs<#= fmt #>Async(this Image source, string path, <#= fmt #>Encoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( path, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(<#= fmt #>Format.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(<#= fmt #>Format.Instance), cancellationToken); /// @@ -125,7 +125,7 @@ public static partial class ImageExtensions public static void SaveAs<#= fmt #>(this Image source, Stream stream, <#= fmt #>Encoder encoder) => source.Save( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(<#= fmt #>Format.Instance)); + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(<#= fmt #>Format.Instance)); /// /// Saves the image to the given stream with the <#= fmt #> format. @@ -139,7 +139,7 @@ public static partial class ImageExtensions public static Task SaveAs<#= fmt #>Async(this Image source, Stream stream, <#= fmt #>Encoder encoder, CancellationToken cancellationToken = default) => source.SaveAsync( stream, - encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(<#= fmt #>Format.Instance), + encoder ?? source.Configuration.ImageFormatsManager.GetEncoder(<#= fmt #>Format.Instance), cancellationToken); <# diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/JpegFrame.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/JpegFrame.cs index 97a4a2dc0e..6ba0b82723 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/JpegFrame.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/JpegFrame.cs @@ -20,7 +20,7 @@ public JpegFrame(Image image, JpegFrameConfig frameConfig, bool interleaved) this.PixelWidth = image.Width; this.PixelHeight = image.Height; - MemoryAllocator allocator = image.GetConfiguration().MemoryAllocator; + MemoryAllocator allocator = image.Configuration.MemoryAllocator; JpegComponentConfig[] componentConfigs = frameConfig.Components; this.Components = new Component[componentConfigs.Length]; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/SpectralConverter{TPixel}.cs index 47a6029065..fc93db9bb0 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/SpectralConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/SpectralConverter{TPixel}.cs @@ -32,7 +32,7 @@ internal class SpectralConverter : SpectralConverter, IDisposable public SpectralConverter(JpegFrame frame, Image image, Block8x8F[] dequantTables) { - MemoryAllocator allocator = image.GetConfiguration().MemoryAllocator; + MemoryAllocator allocator = image.Configuration.MemoryAllocator; // iteration data int majorBlockWidth = frame.Components.Max((component) => component.SizeInBlocks.Width); diff --git a/src/ImageSharp/Formats/Pbm/PbmEncoder.cs b/src/ImageSharp/Formats/Pbm/PbmEncoder.cs index 0f492fae72..8258c91655 100644 --- a/src/ImageSharp/Formats/Pbm/PbmEncoder.cs +++ b/src/ImageSharp/Formats/Pbm/PbmEncoder.cs @@ -49,7 +49,7 @@ public sealed class PbmEncoder : ImageEncoder /// protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken) { - PbmEncoderCore encoder = new(image.GetConfiguration(), this); + PbmEncoderCore encoder = new(image.Configuration, this); encoder.Encode(image, stream, cancellationToken); } } diff --git a/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs b/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs index 4a07173a14..b6e31a3c28 100644 --- a/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs +++ b/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs @@ -78,7 +78,7 @@ public void Encode(Image image, Stream stream, CancellationToken private void SanitizeAndSetEncoderOptions(Image image) where TPixel : unmanaged, IPixel { - this.configuration = image.GetConfiguration(); + this.configuration = image.Configuration; PbmMetadata metadata = image.Metadata.GetPbmMetadata(); this.encoding = this.encoder.Encoding ?? metadata.Encoding; this.colorType = this.encoder.ColorType ?? metadata.ColorType; diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs index f273ac2b98..d226451389 100644 --- a/src/ImageSharp/Formats/Png/PngDecoder.cs +++ b/src/ImageSharp/Formats/Png/PngDecoder.cs @@ -61,24 +61,24 @@ protected override Image Decode(DecoderOptions options, Stream stream, Cancellat case PngColorType.Grayscale: if (bits == PngBitDepth.Bit16) { - return !meta.HasTransparency + return !meta.TransparentColor.HasValue ? this.Decode(options, stream, cancellationToken) : this.Decode(options, stream, cancellationToken); } - return !meta.HasTransparency + return !meta.TransparentColor.HasValue ? this.Decode(options, stream, cancellationToken) : this.Decode(options, stream, cancellationToken); case PngColorType.Rgb: if (bits == PngBitDepth.Bit16) { - return !meta.HasTransparency + return !meta.TransparentColor.HasValue ? this.Decode(options, stream, cancellationToken) : this.Decode(options, stream, cancellationToken); } - return !meta.HasTransparency + return !meta.TransparentColor.HasValue ? this.Decode(options, stream, cancellationToken) : this.Decode(options, stream, cancellationToken); diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index d1d29dca6b..065d861e71 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -172,21 +172,20 @@ public Image Decode(BufferedReadStream stream, CancellationToken if (image is null) { this.InitializeImage(metadata, out image); + + // Both PLTE and tRNS chunks, if present, have been read at this point as per spec. + AssignColorPalette(this.palette, this.paletteAlpha, pngMetadata); } this.ReadScanlines(chunk, image.Frames.RootFrame, pngMetadata, cancellationToken); break; case PngChunkType.Palette: - byte[] pal = new byte[chunk.Length]; - chunk.Data.GetSpan().CopyTo(pal); - this.palette = pal; + this.palette = chunk.Data.GetSpan().ToArray(); break; case PngChunkType.Transparency: - byte[] alpha = new byte[chunk.Length]; - chunk.Data.GetSpan().CopyTo(alpha); - this.paletteAlpha = alpha; - this.AssignTransparentMarkers(alpha, pngMetadata); + this.paletteAlpha = chunk.Data.GetSpan().ToArray(); + this.AssignTransparentMarkers(this.paletteAlpha, pngMetadata); break; case PngChunkType.Text: this.ReadTextChunk(metadata, pngMetadata, chunk.Data.GetSpan()); @@ -292,12 +291,15 @@ public ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellat this.SkipChunkDataAndCrc(chunk); break; + case PngChunkType.Palette: + this.palette = chunk.Data.GetSpan().ToArray(); + break; + case PngChunkType.Transparency: - byte[] alpha = new byte[chunk.Length]; - chunk.Data.GetSpan().CopyTo(alpha); - this.paletteAlpha = alpha; - this.AssignTransparentMarkers(alpha, pngMetadata); + this.paletteAlpha = chunk.Data.GetSpan().ToArray(); + this.AssignTransparentMarkers(this.paletteAlpha, pngMetadata); + // Spec says tRNS must be after PLTE so safe to exit. if (this.colorMetadataOnly) { goto EOF; @@ -370,6 +372,9 @@ public ImageInfo Identify(BufferedReadStream stream, CancellationToken cancellat PngThrowHelper.ThrowNoHeader(); } + // Both PLTE and tRNS chunks, if present, have been read at this point as per spec. + AssignColorPalette(this.palette, this.paletteAlpha, pngMetadata); + return new ImageInfo(new PixelTypeInfo(this.CalculateBitsPerPixel()), new(this.header.Width, this.header.Height), metadata); } finally @@ -766,9 +771,7 @@ private void ProcessDefilteredScanline(ReadOnlySpan defilteredScan this.header, scanlineSpan, rowSpan, - pngMetadata.HasTransparency, - pngMetadata.TransparentL16.GetValueOrDefault(), - pngMetadata.TransparentL8.GetValueOrDefault()); + pngMetadata.TransparentColor); break; @@ -787,8 +790,7 @@ private void ProcessDefilteredScanline(ReadOnlySpan defilteredScan this.header, scanlineSpan, rowSpan, - this.palette, - this.paletteAlpha); + pngMetadata.ColorTable); break; @@ -800,9 +802,7 @@ private void ProcessDefilteredScanline(ReadOnlySpan defilteredScan rowSpan, this.bytesPerPixel, this.bytesPerSample, - pngMetadata.HasTransparency, - pngMetadata.TransparentRgb48.GetValueOrDefault(), - pngMetadata.TransparentRgb24.GetValueOrDefault()); + pngMetadata.TransparentColor); break; @@ -860,9 +860,7 @@ private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defi rowSpan, (uint)pixelOffset, (uint)increment, - pngMetadata.HasTransparency, - pngMetadata.TransparentL16.GetValueOrDefault(), - pngMetadata.TransparentL8.GetValueOrDefault()); + pngMetadata.TransparentColor); break; @@ -885,8 +883,7 @@ private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defi rowSpan, (uint)pixelOffset, (uint)increment, - this.palette, - this.paletteAlpha); + pngMetadata.ColorTable); break; @@ -899,9 +896,7 @@ private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defi (uint)increment, this.bytesPerPixel, this.bytesPerSample, - pngMetadata.HasTransparency, - pngMetadata.TransparentRgb48.GetValueOrDefault(), - pngMetadata.TransparentRgb24.GetValueOrDefault()); + pngMetadata.TransparentColor); break; @@ -924,10 +919,44 @@ private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defi } } + /// + /// Decodes and assigns the color palette to the metadata + /// + /// The palette buffer. + /// The alpha palette buffer. + /// The png metadata. + private static void AssignColorPalette(ReadOnlySpan palette, ReadOnlySpan alpha, PngMetadata pngMetadata) + { + if (palette.Length == 0) + { + return; + } + + Color[] colorTable = new Color[palette.Length / Unsafe.SizeOf()]; + ReadOnlySpan rgbTable = MemoryMarshal.Cast(palette); + for (int i = 0; i < colorTable.Length; i++) + { + colorTable[i] = new Color(rgbTable[i]); + } + + if (alpha.Length > 0) + { + // The alpha chunk may contain as many transparency entries as there are palette entries + // (more than that would not make any sense) or as few as one. + for (int i = 0; i < alpha.Length; i++) + { + ref Color color = ref colorTable[i]; + color = color.WithAlpha(alpha[i] / 255F); + } + } + + pngMetadata.ColorTable = colorTable; + } + /// /// Decodes and assigns marker colors that identify transparent pixels in non indexed images. /// - /// The alpha tRNS array. + /// The alpha tRNS buffer. /// The png metadata. private void AssignTransparentMarkers(ReadOnlySpan alpha, PngMetadata pngMetadata) { @@ -941,16 +970,14 @@ private void AssignTransparentMarkers(ReadOnlySpan alpha, PngMetadata pngM ushort gc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(2, 2)); ushort bc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(4, 2)); - pngMetadata.TransparentRgb48 = new Rgb48(rc, gc, bc); - pngMetadata.HasTransparency = true; + pngMetadata.TransparentColor = new(new Rgb48(rc, gc, bc)); return; } byte r = ReadByteLittleEndian(alpha, 0); byte g = ReadByteLittleEndian(alpha, 2); byte b = ReadByteLittleEndian(alpha, 4); - pngMetadata.TransparentRgb24 = new Rgb24(r, g, b); - pngMetadata.HasTransparency = true; + pngMetadata.TransparentColor = new(new Rgb24(r, g, b)); } } else if (this.pngColorType == PngColorType.Grayscale) @@ -959,20 +986,14 @@ private void AssignTransparentMarkers(ReadOnlySpan alpha, PngMetadata pngM { if (this.header.BitDepth == 16) { - pngMetadata.TransparentL16 = new L16(BinaryPrimitives.ReadUInt16LittleEndian(alpha[..2])); + pngMetadata.TransparentColor = Color.FromPixel(new L16(BinaryPrimitives.ReadUInt16LittleEndian(alpha[..2]))); } else { - pngMetadata.TransparentL8 = new L8(ReadByteLittleEndian(alpha, 0)); + pngMetadata.TransparentColor = Color.FromPixel(new L8(ReadByteLittleEndian(alpha, 0))); } - - pngMetadata.HasTransparency = true; } } - else if (this.pngColorType == PngColorType.Palette && alpha.Length > 0) - { - pngMetadata.HasTransparency = true; - } } /// @@ -1461,7 +1482,7 @@ private bool TryReadChunk(Span buffer, out PngChunk chunk) // If we're reading color metadata only we're only interested in the IHDR and tRNS chunks. // We can skip all other chunk data in the stream for better performance. - if (this.colorMetadataOnly && type != PngChunkType.Header && type != PngChunkType.Transparency) + if (this.colorMetadataOnly && type != PngChunkType.Header && type != PngChunkType.Transparency && type != PngChunkType.Palette) { chunk = new PngChunk(length, type); diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index 595601522e..dcbaf3140d 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -2,7 +2,7 @@ // Licensed under the Six Labors Split License. #nullable disable -using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Processing.Processors.Quantization; namespace SixLabors.ImageSharp.Formats.Png; @@ -11,6 +11,16 @@ namespace SixLabors.ImageSharp.Formats.Png; /// public class PngEncoder : QuantizingImageEncoder { + /// + /// Initializes a new instance of the class. + /// + public PngEncoder() + + // Hack. TODO: Investigate means to fix/optimize the Wu quantizer. + // The Wu quantizer does not handle the default sampling strategy well for some larger images. + // It's expensive and the results are not better than the extensive strategy. + => this.PixelSamplingStrategy = new ExtensivePixelSamplingStrategy(); + /// /// Gets the number of bits per sample or per palette index (not per pixel). /// Not all values are allowed for all values. @@ -68,7 +78,7 @@ public class PngEncoder : QuantizingImageEncoder /// protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken) { - using PngEncoderCore encoder = new(image.GetMemoryAllocator(), image.GetConfiguration(), this); + using PngEncoderCore encoder = new(image.Configuration, this); encoder.Encode(image, stream, cancellationToken); } } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 175a9f777d..c16348b8d9 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -6,7 +6,6 @@ using System.Buffers.Binary; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Compression.Zlib; using SixLabors.ImageSharp.Formats.Png.Chunks; @@ -116,13 +115,12 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable /// /// Initializes a new instance of the class. /// - /// The to use for buffer allocations. /// The configuration. /// The encoder with options. - public PngEncoderCore(MemoryAllocator memoryAllocator, Configuration configuration, PngEncoder encoder) + public PngEncoderCore(Configuration configuration, PngEncoder encoder) { - this.memoryAllocator = memoryAllocator; this.configuration = configuration; + this.memoryAllocator = configuration.MemoryAllocator; this.encoder = encoder; } @@ -875,7 +873,7 @@ private void WriteGammaChunk(Stream stream) // 4-byte unsigned integer of gamma * 100,000. uint gammaValue = (uint)(this.gamma * 100_000F); - BinaryPrimitives.WriteUInt32BigEndian(this.chunkDataBuffer.Span.Slice(0, 4), gammaValue); + BinaryPrimitives.WriteUInt32BigEndian(this.chunkDataBuffer.Span[..4], gammaValue); this.WriteChunk(stream, PngChunkType.Gamma, this.chunkDataBuffer.Span, 0, 4); } @@ -889,7 +887,7 @@ private void WriteGammaChunk(Stream stream) /// The image metadata. private void WriteTransparencyChunk(Stream stream, PngMetadata pngMetadata) { - if (!pngMetadata.HasTransparency) + if (pngMetadata.TransparentColor is null) { return; } @@ -897,19 +895,19 @@ private void WriteTransparencyChunk(Stream stream, PngMetadata pngMetadata) Span alpha = this.chunkDataBuffer.Span; if (pngMetadata.ColorType == PngColorType.Rgb) { - if (pngMetadata.TransparentRgb48.HasValue && this.use16Bit) + if (this.use16Bit) { - Rgb48 rgb = pngMetadata.TransparentRgb48.Value; + Rgb48 rgb = pngMetadata.TransparentColor.Value.ToPixel(); BinaryPrimitives.WriteUInt16LittleEndian(alpha, rgb.R); BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(2, 2), rgb.G); BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(4, 2), rgb.B); this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer.Span, 0, 6); } - else if (pngMetadata.TransparentRgb24.HasValue) + else { alpha.Clear(); - Rgb24 rgb = pngMetadata.TransparentRgb24.Value; + Rgb24 rgb = pngMetadata.TransparentColor.Value.ToRgb24(); alpha[1] = rgb.R; alpha[3] = rgb.G; alpha[5] = rgb.B; @@ -918,15 +916,17 @@ private void WriteTransparencyChunk(Stream stream, PngMetadata pngMetadata) } else if (pngMetadata.ColorType == PngColorType.Grayscale) { - if (pngMetadata.TransparentL16.HasValue && this.use16Bit) + if (this.use16Bit) { - BinaryPrimitives.WriteUInt16LittleEndian(alpha, pngMetadata.TransparentL16.Value.PackedValue); + L16 l16 = pngMetadata.TransparentColor.Value.ToPixel(); + BinaryPrimitives.WriteUInt16LittleEndian(alpha, l16.PackedValue); this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer.Span, 0, 2); } - else if (pngMetadata.TransparentL8.HasValue) + else { + L8 l8 = pngMetadata.TransparentColor.Value.ToPixel(); alpha.Clear(); - alpha[1] = pngMetadata.TransparentL8.Value.PackedValue; + alpha[1] = l8.PackedValue; this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer.Span, 0, 2); } } @@ -1175,7 +1175,7 @@ private void WriteChunk(Stream stream, PngChunkType type, Span data, int o stream.Write(buffer); - uint crc = Crc32.Calculate(buffer.Slice(4)); // Write the type buffer + uint crc = Crc32.Calculate(buffer[4..]); // Write the type buffer if (data.Length > 0 && length > 0) { @@ -1290,11 +1290,23 @@ private static IndexedImageFrame CreateQuantizedFrame( } // Use the metadata to determine what quantization depth to use if no quantizer has been set. - IQuantizer quantizer = encoder.Quantizer - ?? new WuQuantizer(new QuantizerOptions { MaxColors = ColorNumerics.GetColorCountForBitDepth(bitDepth) }); + IQuantizer quantizer = encoder.Quantizer; + if (quantizer is null) + { + PngMetadata metadata = image.Metadata.GetPngMetadata(); + if (metadata.ColorTable is not null) + { + // Use the provided palette in total. The caller is responsible for setting values. + quantizer = new PaletteQuantizer(metadata.ColorTable.Value); + } + else + { + quantizer = new WuQuantizer(new QuantizerOptions { MaxColors = ColorNumerics.GetColorCountForBitDepth(bitDepth) }); + } + } // Create quantized frame returning the palette and set the bit depth. - using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(image.GetConfiguration()); + using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(image.Configuration); frameQuantizer.BuildPalette(encoder.PixelSamplingStrategy, image); return frameQuantizer.QuantizeFrame(image.Frames.RootFrame, image.Bounds); diff --git a/src/ImageSharp/Formats/Png/PngMetadata.cs b/src/ImageSharp/Formats/Png/PngMetadata.cs index 9ff3905fe1..8806c29b1a 100644 --- a/src/ImageSharp/Formats/Png/PngMetadata.cs +++ b/src/ImageSharp/Formats/Png/PngMetadata.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.PixelFormats; - namespace SixLabors.ImageSharp.Formats.Png; /// @@ -27,11 +25,12 @@ private PngMetadata(PngMetadata other) this.ColorType = other.ColorType; this.Gamma = other.Gamma; this.InterlaceMethod = other.InterlaceMethod; - this.HasTransparency = other.HasTransparency; - this.TransparentL8 = other.TransparentL8; - this.TransparentL16 = other.TransparentL16; - this.TransparentRgb24 = other.TransparentRgb24; - this.TransparentRgb48 = other.TransparentRgb48; + this.TransparentColor = other.TransparentColor; + + if (other.ColorTable?.Length > 0) + { + this.ColorTable = other.ColorTable.Value.ToArray(); + } for (int i = 0; i < other.TextData.Count; i++) { @@ -61,33 +60,14 @@ private PngMetadata(PngMetadata other) public float Gamma { get; set; } /// - /// Gets or sets the Rgb24 transparent color. - /// This represents any color in an 8 bit Rgb24 encoded png that should be transparent. - /// - public Rgb24? TransparentRgb24 { get; set; } - - /// - /// Gets or sets the Rgb48 transparent color. - /// This represents any color in a 16 bit Rgb24 encoded png that should be transparent. - /// - public Rgb48? TransparentRgb48 { get; set; } - - /// - /// Gets or sets the 8 bit grayscale transparent color. - /// This represents any color in an 8 bit grayscale encoded png that should be transparent. - /// - public L8? TransparentL8 { get; set; } - - /// - /// Gets or sets the 16 bit grayscale transparent color. - /// This represents any color in a 16 bit grayscale encoded png that should be transparent. + /// Gets or sets the color table, if any. /// - public L16? TransparentL16 { get; set; } + public ReadOnlyMemory? ColorTable { get; set; } /// - /// Gets or sets a value indicating whether the image contains a transparency chunk and markers were decoded. + /// Gets or sets the transparent color used with non palette based images, if a transparency chunk and markers were decoded. /// - public bool HasTransparency { get; set; } + public Color? TransparentColor { get; set; } /// /// Gets or sets the collection of text data stored within the iTXt, tEXt, and zTXt chunks. diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index 04a23308cc..b0afd9975e 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -18,9 +18,7 @@ public static void ProcessGrayscaleScanline( in PngHeader header, ReadOnlySpan scanlineSpan, Span rowSpan, - bool hasTrans, - L16 luminance16Trans, - L8 luminanceTrans) + Color? transparentColor) where TPixel : unmanaged, IPixel { TPixel pixel = default; @@ -28,7 +26,7 @@ public static void ProcessGrayscaleScanline( ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); int scaleFactor = 255 / (ColorNumerics.GetColorCountForBitDepth(header.BitDepth) - 1); - if (!hasTrans) + if (transparentColor is null) { if (header.BitDepth == 16) { @@ -55,13 +53,14 @@ public static void ProcessGrayscaleScanline( if (header.BitDepth == 16) { + L16 transparent = transparentColor.Value.ToPixel(); La32 source = default; int o = 0; for (nuint x = 0; x < (uint)header.Width; x++, o += 2) { ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); source.L = luminance; - source.A = luminance.Equals(luminance16Trans.PackedValue) ? ushort.MinValue : ushort.MaxValue; + source.A = luminance.Equals(transparent.PackedValue) ? ushort.MinValue : ushort.MaxValue; pixel.FromLa32(source); Unsafe.Add(ref rowSpanRef, x) = pixel; @@ -69,13 +68,13 @@ public static void ProcessGrayscaleScanline( } else { + byte transparent = (byte)(transparentColor.Value.ToPixel().PackedValue * scaleFactor); La16 source = default; - byte scaledLuminanceTrans = (byte)(luminanceTrans.PackedValue * scaleFactor); for (nuint x = 0; x < (uint)header.Width; x++) { byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * scaleFactor); source.L = luminance; - source.A = luminance.Equals(scaledLuminanceTrans) ? byte.MinValue : byte.MaxValue; + source.A = luminance.Equals(transparent) ? byte.MinValue : byte.MaxValue; pixel.FromLa16(source); Unsafe.Add(ref rowSpanRef, x) = pixel; @@ -89,9 +88,7 @@ public static void ProcessInterlacedGrayscaleScanline( Span rowSpan, uint pixelOffset, uint increment, - bool hasTrans, - L16 luminance16Trans, - L8 luminanceTrans) + Color? transparentColor) where TPixel : unmanaged, IPixel { TPixel pixel = default; @@ -99,7 +96,7 @@ public static void ProcessInterlacedGrayscaleScanline( ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); int scaleFactor = 255 / (ColorNumerics.GetColorCountForBitDepth(header.BitDepth) - 1); - if (!hasTrans) + if (transparentColor is null) { if (header.BitDepth == 16) { @@ -126,13 +123,14 @@ public static void ProcessInterlacedGrayscaleScanline( if (header.BitDepth == 16) { + L16 transparent = transparentColor.Value.ToPixel(); La32 source = default; int o = 0; for (nuint x = pixelOffset; x < (uint)header.Width; x += increment, o += 2) { ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); source.L = luminance; - source.A = luminance.Equals(luminance16Trans.PackedValue) ? ushort.MinValue : ushort.MaxValue; + source.A = luminance.Equals(transparent.PackedValue) ? ushort.MinValue : ushort.MaxValue; pixel.FromLa32(source); Unsafe.Add(ref rowSpanRef, x) = pixel; @@ -140,13 +138,13 @@ public static void ProcessInterlacedGrayscaleScanline( } else { + byte transparent = (byte)(transparentColor.Value.ToPixel().PackedValue * scaleFactor); La16 source = default; - byte scaledLuminanceTrans = (byte)(luminanceTrans.PackedValue * scaleFactor); for (nuint x = pixelOffset, o = 0; x < (uint)header.Width; x += increment, o++) { byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor); source.L = luminance; - source.A = luminance.Equals(scaledLuminanceTrans) ? byte.MinValue : byte.MaxValue; + source.A = luminance.Equals(transparent) ? byte.MinValue : byte.MaxValue; pixel.FromLa16(source); Unsafe.Add(ref rowSpanRef, x) = pixel; @@ -241,11 +239,10 @@ public static void ProcessPaletteScanline( in PngHeader header, ReadOnlySpan scanlineSpan, Span rowSpan, - ReadOnlySpan palette, - byte[] paletteAlpha) + ReadOnlyMemory? palette) where TPixel : unmanaged, IPixel { - if (palette.IsEmpty) + if (palette is null) { PngThrowHelper.ThrowMissingPalette(); } @@ -253,36 +250,13 @@ public static void ProcessPaletteScanline( TPixel pixel = default; ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); - ReadOnlySpan palettePixels = MemoryMarshal.Cast(palette); - ref Rgb24 palettePixelsRef = ref MemoryMarshal.GetReference(palettePixels); + ref Color paletteBase = ref MemoryMarshal.GetReference(palette.Value.Span); - if (paletteAlpha?.Length > 0) + for (nuint x = 0; x < (uint)header.Width; x++) { - // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha - // channel and we should try to read it. - Rgba32 rgba = default; - ref byte paletteAlphaRef = ref MemoryMarshal.GetArrayDataReference(paletteAlpha); - - for (nuint x = 0; x < (uint)header.Width; x++) - { - uint index = Unsafe.Add(ref scanlineSpanRef, x); - rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); - rgba.A = paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue; - - pixel.FromRgba32(rgba); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - for (nuint x = 0; x < (uint)header.Width; x++) - { - int index = Unsafe.Add(ref scanlineSpanRef, x); - Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index); - - pixel.FromRgb24(rgb); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } + uint index = Unsafe.Add(ref scanlineSpanRef, x); + pixel.FromRgba32(Unsafe.Add(ref paletteBase, index).ToRgba32()); + Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -292,42 +266,24 @@ public static void ProcessInterlacedPaletteScanline( Span rowSpan, uint pixelOffset, uint increment, - ReadOnlySpan palette, - byte[] paletteAlpha) + ReadOnlyMemory? palette) where TPixel : unmanaged, IPixel { + if (palette is null) + { + PngThrowHelper.ThrowMissingPalette(); + } + TPixel pixel = default; ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); - ReadOnlySpan palettePixels = MemoryMarshal.Cast(palette); - ref Rgb24 palettePixelsRef = ref MemoryMarshal.GetReference(palettePixels); + ref Color paletteBase = ref MemoryMarshal.GetReference(palette.Value.Span); - if (paletteAlpha?.Length > 0) + for (nuint x = pixelOffset, o = 0; x < (uint)header.Width; x += increment, o++) { - // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha - // channel and we should try to read it. - Rgba32 rgba = default; - ref byte paletteAlphaRef = ref MemoryMarshal.GetArrayDataReference(paletteAlpha); - for (nuint x = pixelOffset, o = 0; x < (uint)header.Width; x += increment, o++) - { - uint index = Unsafe.Add(ref scanlineSpanRef, o); - rgba.A = paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue; - rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); - - pixel.FromRgba32(rgba); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - for (nuint x = pixelOffset, o = 0; x < (uint)header.Width; x += increment, o++) - { - int index = Unsafe.Add(ref scanlineSpanRef, o); - Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index); - - pixel.FromRgb24(rgb); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } + uint index = Unsafe.Add(ref scanlineSpanRef, o); + pixel.FromRgba32(Unsafe.Add(ref paletteBase, index).ToRgba32()); + Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -338,15 +294,13 @@ public static void ProcessRgbScanline( Span rowSpan, int bytesPerPixel, int bytesPerSample, - bool hasTrans, - Rgb48 rgb48Trans, - Rgb24 rgb24Trans) + Color? transparentColor) where TPixel : unmanaged, IPixel { TPixel pixel = default; ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); - if (!hasTrans) + if (transparentColor is null) { if (header.BitDepth == 16) { @@ -372,6 +326,8 @@ public static void ProcessRgbScanline( if (header.BitDepth == 16) { + Rgb48 transparent = transparentColor.Value.ToPixel(); + Rgb48 rgb48 = default; Rgba64 rgba64 = default; int o = 0; @@ -382,7 +338,7 @@ public static void ProcessRgbScanline( rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); rgba64.Rgb = rgb48; - rgba64.A = rgb48.Equals(rgb48Trans) ? ushort.MinValue : ushort.MaxValue; + rgba64.A = rgb48.Equals(transparent) ? ushort.MinValue : ushort.MaxValue; pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; @@ -390,6 +346,8 @@ public static void ProcessRgbScanline( } else { + Rgb24 transparent = transparentColor.Value.ToPixel(); + Rgba32 rgba32 = default; ReadOnlySpan rgb24Span = MemoryMarshal.Cast(scanlineSpan); ref Rgb24 rgb24SpanRef = ref MemoryMarshal.GetReference(rgb24Span); @@ -397,7 +355,7 @@ public static void ProcessRgbScanline( { ref readonly Rgb24 rgb24 = ref Unsafe.Add(ref rgb24SpanRef, x); rgba32.Rgb = rgb24; - rgba32.A = rgb24.Equals(rgb24Trans) ? byte.MinValue : byte.MaxValue; + rgba32.A = rgb24.Equals(transparent) ? byte.MinValue : byte.MaxValue; pixel.FromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; @@ -413,21 +371,19 @@ public static void ProcessInterlacedRgbScanline( uint increment, int bytesPerPixel, int bytesPerSample, - bool hasTrans, - Rgb48 rgb48Trans, - Rgb24 rgb24Trans) + Color? transparentColor) where TPixel : unmanaged, IPixel { TPixel pixel = default; ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); + bool hasTransparency = transparentColor is not null; - if (header.BitDepth == 16) + if (transparentColor is null) { - if (hasTrans) + if (header.BitDepth == 16) { Rgb48 rgb48 = default; - Rgba64 rgba64 = default; int o = 0; for (nuint x = pixelOffset; x < (uint)header.Width; x += increment, o += bytesPerPixel) { @@ -435,24 +391,21 @@ public static void ProcessInterlacedRgbScanline( rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); - rgba64.Rgb = rgb48; - rgba64.A = rgb48.Equals(rgb48Trans) ? ushort.MinValue : ushort.MaxValue; - - pixel.FromRgba64(rgba64); + pixel.FromRgb48(rgb48); Unsafe.Add(ref rowSpanRef, x) = pixel; } } else { - Rgb48 rgb48 = default; + Rgb24 rgb = default; int o = 0; for (nuint x = pixelOffset; x < (uint)header.Width; x += increment, o += bytesPerPixel) { - rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); - rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); - rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); + rgb.R = Unsafe.Add(ref scanlineSpanRef, (uint)o); + rgb.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample)); + rgb.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample))); - pixel.FromRgb48(rgb48); + pixel.FromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -460,32 +413,40 @@ public static void ProcessInterlacedRgbScanline( return; } - if (hasTrans) + if (header.BitDepth == 16) { - Rgba32 rgba = default; + Rgb48 transparent = transparentColor.Value.ToPixel(); + + Rgb48 rgb48 = default; + Rgba64 rgba64 = default; int o = 0; for (nuint x = pixelOffset; x < (uint)header.Width; x += increment, o += bytesPerPixel) { - rgba.R = Unsafe.Add(ref scanlineSpanRef, (uint)o); - rgba.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample)); - rgba.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample))); - rgba.A = rgb24Trans.Equals(rgba.Rgb) ? byte.MinValue : byte.MaxValue; + rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); + rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); + rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); - pixel.FromRgba32(rgba); + rgba64.Rgb = rgb48; + rgba64.A = rgb48.Equals(transparent) ? ushort.MinValue : ushort.MaxValue; + + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } else { - Rgb24 rgb = default; + Rgb24 transparent = transparentColor.Value.ToPixel(); + + Rgba32 rgba = default; int o = 0; for (nuint x = pixelOffset; x < (uint)header.Width; x += increment, o += bytesPerPixel) { - rgb.R = Unsafe.Add(ref scanlineSpanRef, (uint)o); - rgb.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample)); - rgb.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample))); + rgba.R = Unsafe.Add(ref scanlineSpanRef, (uint)o); + rgba.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample)); + rgba.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample))); + rgba.A = transparent.Equals(rgba.Rgb) ? byte.MinValue : byte.MaxValue; - pixel.FromRgb24(rgb); + pixel.FromRgba32(rgba); Unsafe.Add(ref rowSpanRef, x) = pixel; } } diff --git a/src/ImageSharp/Formats/Qoi/QoiEncoder.cs b/src/ImageSharp/Formats/Qoi/QoiEncoder.cs index b3769d45cb..b9c2078b3f 100644 --- a/src/ImageSharp/Formats/Qoi/QoiEncoder.cs +++ b/src/ImageSharp/Formats/Qoi/QoiEncoder.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Advanced; - namespace SixLabors.ImageSharp.Formats.Qoi; /// @@ -27,7 +25,7 @@ public class QoiEncoder : ImageEncoder /// protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken) { - QoiEncoderCore encoder = new(this, image.GetMemoryAllocator(), image.GetConfiguration()); + QoiEncoderCore encoder = new(this, image.Configuration); encoder.Encode(image, stream, cancellationToken); } } diff --git a/src/ImageSharp/Formats/Qoi/QoiEncoderCore.cs b/src/ImageSharp/Formats/Qoi/QoiEncoderCore.cs index 40b246faf2..53f67e765d 100644 --- a/src/ImageSharp/Formats/Qoi/QoiEncoderCore.cs +++ b/src/ImageSharp/Formats/Qoi/QoiEncoderCore.cs @@ -33,13 +33,12 @@ internal class QoiEncoderCore : IImageEncoderInternals /// Initializes a new instance of the class. /// /// The encoder with options. - /// The to use for buffer allocations. /// The configuration of the Encoder. - public QoiEncoderCore(QoiEncoder encoder, MemoryAllocator memoryAllocator, Configuration configuration) + public QoiEncoderCore(QoiEncoder encoder, Configuration configuration) { this.encoder = encoder; - this.memoryAllocator = memoryAllocator; this.configuration = configuration; + this.memoryAllocator = configuration.MemoryAllocator; } /// diff --git a/src/ImageSharp/Formats/Tga/TgaEncoder.cs b/src/ImageSharp/Formats/Tga/TgaEncoder.cs index 71acf3ae83..09b12e6081 100644 --- a/src/ImageSharp/Formats/Tga/TgaEncoder.cs +++ b/src/ImageSharp/Formats/Tga/TgaEncoder.cs @@ -1,12 +1,10 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Advanced; - namespace SixLabors.ImageSharp.Formats.Tga; /// -/// Image encoder for writing an image to a stream as a targa truevision image. +/// Image encoder for writing an image to a stream as a Targa true-vision image. /// public sealed class TgaEncoder : ImageEncoder { @@ -23,7 +21,7 @@ public sealed class TgaEncoder : ImageEncoder /// protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken) { - TgaEncoderCore encoder = new(this, image.GetMemoryAllocator()); + TgaEncoderCore encoder = new(this, image.Configuration.MemoryAllocator); encoder.Encode(image, stream, cancellationToken); } } diff --git a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs index ad63bd356d..bbb476c017 100644 --- a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs @@ -112,7 +112,7 @@ public void Encode(Image image, Stream stream, CancellationToken } else { - this.WriteImage(image.GetConfiguration(), stream, image.Frames.RootFrame); + this.WriteImage(image.Configuration, stream, image.Frames.RootFrame); } stream.Flush(); diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoder.cs b/src/ImageSharp/Formats/Tiff/TiffEncoder.cs index fb5b9f2ed7..ea64e82899 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoder.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoder.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Compression.Zlib; using SixLabors.ImageSharp.Formats.Tiff.Constants; using SixLabors.ImageSharp.Processing; @@ -48,7 +47,7 @@ public class TiffEncoder : QuantizingImageEncoder /// protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken) { - TiffEncoderCore encode = new(this, image.GetMemoryAllocator()); + TiffEncoderCore encode = new(this, image.Configuration.MemoryAllocator); encode.Encode(image, stream, cancellationToken); } } diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs index d0634cf259..149f23f1bf 100644 --- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs @@ -128,7 +128,7 @@ public void Encode(Image image, Stream stream, CancellationToken Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); - this.configuration = image.GetConfiguration(); + this.configuration = image.Configuration; ImageFrameMetadata rootFrameMetaData = image.Frames.RootFrame.Metadata; TiffFrameMetadata rootFrameTiffMetaData = rootFrameMetaData.GetTiffMetadata(); diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index 1f7c7586eb..469e4c9ab0 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -502,7 +502,7 @@ private CrunchConfig[] EncoderAnalyze(ReadOnlySpan bgra, int width, int he doNotCache = true; // Go brute force on all transforms. - foreach (EntropyIx entropyIx in Enum.GetValues(typeof(EntropyIx)).Cast()) + foreach (EntropyIx entropyIx in Enum.GetValues()) { // We can only apply kPalette or kPaletteAndSpatial if we can indeed use a palette. if ((entropyIx != EntropyIx.Palette && entropyIx != EntropyIx.PaletteAndSpatial) || usePalette) diff --git a/src/ImageSharp/Formats/Webp/WebpEncoder.cs b/src/ImageSharp/Formats/Webp/WebpEncoder.cs index bd8303f1c8..29d0c9e3b0 100644 --- a/src/ImageSharp/Formats/Webp/WebpEncoder.cs +++ b/src/ImageSharp/Formats/Webp/WebpEncoder.cs @@ -82,7 +82,7 @@ public sealed class WebpEncoder : ImageEncoder /// protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken) { - WebpEncoderCore encoder = new(this, image.GetConfiguration()); + WebpEncoderCore encoder = new(this, image.Configuration); encoder.Encode(image, stream, cancellationToken); } } diff --git a/src/ImageSharp/Image.cs b/src/ImageSharp/Image.cs index cba32cb782..03a19a4be8 100644 --- a/src/ImageSharp/Image.cs +++ b/src/ImageSharp/Image.cs @@ -17,7 +17,6 @@ namespace SixLabors.ImageSharp; public abstract partial class Image : IDisposable, IConfigurationProvider { private bool isDisposed; - private readonly Configuration configuration; /// /// Initializes a new instance of the class. @@ -26,12 +25,12 @@ public abstract partial class Image : IDisposable, IConfigurationProvider /// The pixel type information. /// The image metadata. /// The size in px units. - protected Image(Configuration configuration, PixelTypeInfo pixelType, ImageMetadata? metadata, Size size) + protected Image(Configuration configuration, PixelTypeInfo pixelType, ImageMetadata metadata, Size size) { - this.configuration = configuration; + this.Configuration = configuration; this.PixelType = pixelType; this.Size = size; - this.Metadata = metadata ?? new ImageMetadata(); + this.Metadata = metadata; } /// @@ -45,7 +44,7 @@ protected Image(Configuration configuration, PixelTypeInfo pixelType, ImageMetad internal Image( Configuration configuration, PixelTypeInfo pixelType, - ImageMetadata? metadata, + ImageMetadata metadata, int width, int height) : this(configuration, pixelType, metadata, new Size(width, height)) @@ -53,7 +52,7 @@ internal Image( } /// - Configuration IConfigurationProvider.Configuration => this.configuration; + public Configuration Configuration { get; } /// /// Gets information about the image pixels. @@ -147,7 +146,7 @@ public Task SaveAsync(Stream stream, IImageEncoder encoder, CancellationToken ca /// The pixel format. /// The public Image CloneAs() - where TPixel2 : unmanaged, IPixel => this.CloneAs(this.GetConfiguration()); + where TPixel2 : unmanaged, IPixel => this.CloneAs(this.Configuration); /// /// Returns a copy of the image in the given pixel format. diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs index 75e4f13257..6c769a9d17 100644 --- a/src/ImageSharp/ImageExtensions.cs +++ b/src/ImageSharp/ImageExtensions.cs @@ -47,7 +47,7 @@ public static void Save(this Image source, string path, IImageEncoder encoder) { Guard.NotNull(path, nameof(path)); Guard.NotNull(encoder, nameof(encoder)); - using Stream fs = source.GetConfiguration().FileSystem.Create(path); + using Stream fs = source.Configuration.FileSystem.Create(path); source.Save(fs, encoder); } @@ -70,7 +70,7 @@ public static async Task SaveAsync( Guard.NotNull(path, nameof(path)); Guard.NotNull(encoder, nameof(encoder)); - await using Stream fs = source.GetConfiguration().FileSystem.CreateAsynchronous(path); + await using Stream fs = source.Configuration.FileSystem.CreateAsynchronous(path); await source.SaveAsync(fs, encoder, cancellationToken).ConfigureAwait(false); } @@ -94,14 +94,14 @@ public static void Save(this Image source, Stream stream, IImageFormat format) throw new NotSupportedException("Cannot write to the stream."); } - IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.GetEncoder(format); + IImageEncoder encoder = source.Configuration.ImageFormatsManager.GetEncoder(format); if (encoder is null) { StringBuilder sb = new(); sb.AppendLine("No encoder was found for the provided mime type. Registered encoders include:"); - foreach (KeyValuePair val in source.GetConfiguration().ImageFormatsManager.ImageEncoders) + foreach (KeyValuePair val in source.Configuration.ImageFormatsManager.ImageEncoders) { sb.AppendFormat(CultureInfo.InvariantCulture, " - {0} : {1}{2}", val.Key.Name, val.Value.GetType().Name, Environment.NewLine); } @@ -138,14 +138,14 @@ public static Task SaveAsync( throw new NotSupportedException("Cannot write to the stream."); } - IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.GetEncoder(format); + IImageEncoder encoder = source.Configuration.ImageFormatsManager.GetEncoder(format); if (encoder is null) { StringBuilder sb = new(); sb.AppendLine("No encoder was found for the provided mime type. Registered encoders include:"); - foreach (KeyValuePair val in source.GetConfiguration().ImageFormatsManager.ImageEncoders) + foreach (KeyValuePair val in source.Configuration.ImageFormatsManager.ImageEncoders) { sb.AppendFormat(CultureInfo.InvariantCulture, " - {0} : {1}{2}", val.Key.Name, val.Value.GetType().Name, Environment.NewLine); } diff --git a/src/ImageSharp/ImageFrame.cs b/src/ImageSharp/ImageFrame.cs index 1e5d40385c..2558e1a13a 100644 --- a/src/ImageSharp/ImageFrame.cs +++ b/src/ImageSharp/ImageFrame.cs @@ -15,8 +15,6 @@ namespace SixLabors.ImageSharp; /// public abstract partial class ImageFrame : IConfigurationProvider, IDisposable { - private readonly Configuration configuration; - /// /// Initializes a new instance of the class. /// @@ -26,10 +24,7 @@ public abstract partial class ImageFrame : IConfigurationProvider, IDisposable /// The . protected ImageFrame(Configuration configuration, int width, int height, ImageFrameMetadata metadata) { - Guard.NotNull(configuration, nameof(configuration)); - Guard.NotNull(metadata, nameof(metadata)); - - this.configuration = configuration ?? Configuration.Default; + this.Configuration = configuration; this.Width = width; this.Height = height; this.Metadata = metadata; @@ -51,19 +46,19 @@ protected ImageFrame(Configuration configuration, int width, int height, ImageFr public ImageFrameMetadata Metadata { get; } /// - Configuration IConfigurationProvider.Configuration => this.configuration; + public Configuration Configuration { get; } /// /// Gets the size of the frame. /// /// The - public Size Size() => new Size(this.Width, this.Height); + public Size Size() => new(this.Width, this.Height); /// /// Gets the bounds of the frame. /// /// The - public Rectangle Bounds() => new Rectangle(0, 0, this.Width, this.Height); + public Rectangle Bounds() => new(0, 0, this.Width, this.Height); /// public void Dispose() @@ -84,6 +79,7 @@ internal abstract void CopyPixelsTo(MemoryGroup /// Updates the size of the image frame. /// + /// The size. internal void UpdateSize(Size size) { this.Width = size.Width; diff --git a/src/ImageSharp/ImageFrameCollection{TPixel}.cs b/src/ImageSharp/ImageFrameCollection{TPixel}.cs index faa83b59e2..b32711ebf2 100644 --- a/src/ImageSharp/ImageFrameCollection{TPixel}.cs +++ b/src/ImageSharp/ImageFrameCollection{TPixel}.cs @@ -24,7 +24,7 @@ internal ImageFrameCollection(Image parent, int width, int height, TPixe this.parent = parent ?? throw new ArgumentNullException(nameof(parent)); // Frames are already cloned within the caller - this.frames.Add(new ImageFrame(parent.GetConfiguration(), width, height, backgroundColor)); + this.frames.Add(new ImageFrame(parent.Configuration, width, height, backgroundColor)); } internal ImageFrameCollection(Image parent, int width, int height, MemoryGroup memorySource) @@ -32,7 +32,7 @@ internal ImageFrameCollection(Image parent, int width, int height, Memor this.parent = parent ?? throw new ArgumentNullException(nameof(parent)); // Frames are already cloned within the caller - this.frames.Add(new ImageFrame(parent.GetConfiguration(), width, height, memorySource)); + this.frames.Add(new ImageFrame(parent.Configuration, width, height, memorySource)); } internal ImageFrameCollection(Image parent, IEnumerable> frames) @@ -138,7 +138,7 @@ public ImageFrame InsertFrame(int index, ImageFrame source) this.EnsureNotDisposed(); this.ValidateFrame(source); - ImageFrame clonedFrame = source.Clone(this.parent.GetConfiguration()); + ImageFrame clonedFrame = source.Clone(this.parent.Configuration); this.frames.Insert(index, clonedFrame); return clonedFrame; } @@ -153,7 +153,7 @@ public ImageFrame AddFrame(ImageFrame source) this.EnsureNotDisposed(); this.ValidateFrame(source); - ImageFrame clonedFrame = source.Clone(this.parent.GetConfiguration()); + ImageFrame clonedFrame = source.Clone(this.parent.Configuration); this.frames.Add(clonedFrame); return clonedFrame; } @@ -169,7 +169,7 @@ public ImageFrame AddFrame(ReadOnlySpan source) this.EnsureNotDisposed(); ImageFrame frame = ImageFrame.LoadPixelData( - this.parent.GetConfiguration(), + this.parent.Configuration, source, this.RootFrame.Width, this.RootFrame.Height); @@ -270,7 +270,7 @@ public override void MoveFrame(int sourceIndex, int destinationIndex) this.frames.Remove(frame); - return new Image(this.parent.GetConfiguration(), this.parent.Metadata.DeepClone(), new[] { frame }); + return new Image(this.parent.Configuration, this.parent.Metadata.DeepClone(), new[] { frame }); } /// @@ -285,7 +285,7 @@ public override void MoveFrame(int sourceIndex, int destinationIndex) ImageFrame frame = this[index]; ImageFrame clonedFrame = frame.Clone(); - return new Image(this.parent.GetConfiguration(), this.parent.Metadata.DeepClone(), new[] { clonedFrame }); + return new Image(this.parent.Configuration, this.parent.Metadata.DeepClone(), new[] { clonedFrame }); } /// @@ -299,7 +299,7 @@ public override void MoveFrame(int sourceIndex, int destinationIndex) this.EnsureNotDisposed(); ImageFrame frame = new( - this.parent.GetConfiguration(), + this.parent.Configuration, this.RootFrame.Width, this.RootFrame.Height); this.frames.Add(frame); @@ -365,7 +365,7 @@ protected override ImageFrame NonGenericCreateFrame(Color backgroundColor) => public ImageFrame CreateFrame(TPixel backgroundColor) { ImageFrame frame = new( - this.parent.GetConfiguration(), + this.parent.Configuration, this.RootFrame.Width, this.RootFrame.Height, backgroundColor); @@ -414,7 +414,7 @@ protected override void Dispose(bool disposing) private ImageFrame CopyNonCompatibleFrame(ImageFrame source) { ImageFrame result = new( - this.parent.GetConfiguration(), + this.parent.Configuration, source.Size(), source.Metadata.DeepClone()); source.CopyPixelsTo(result.PixelBuffer.FastMemoryGroup); diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 0e7eef11e9..0b6354d05d 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -66,7 +66,7 @@ internal ImageFrame(Configuration configuration, int width, int height, ImageFra Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); - this.PixelBuffer = this.GetConfiguration().MemoryAllocator.Allocate2D( + this.PixelBuffer = this.Configuration.MemoryAllocator.Allocate2D( width, height, configuration.PreferContiguousImageBuffers, @@ -99,7 +99,7 @@ internal ImageFrame(Configuration configuration, int width, int height, TPixel b Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); - this.PixelBuffer = this.GetConfiguration().MemoryAllocator.Allocate2D( + this.PixelBuffer = this.Configuration.MemoryAllocator.Allocate2D( width, height, configuration.PreferContiguousImageBuffers); @@ -146,7 +146,7 @@ internal ImageFrame(Configuration configuration, ImageFrame source) Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(source, nameof(source)); - this.PixelBuffer = this.GetConfiguration().MemoryAllocator.Allocate2D( + this.PixelBuffer = this.Configuration.MemoryAllocator.Allocate2D( source.PixelBuffer.Width, source.PixelBuffer.Height, configuration.PreferContiguousImageBuffers); @@ -371,7 +371,7 @@ internal override void CopyPixelsTo(MemoryGroup PixelOperations.Instance.To(this.GetConfiguration(), s, d)); + => PixelOperations.Instance.To(this.Configuration, s, d)); } /// @@ -381,7 +381,7 @@ internal override void CopyPixelsTo(MemoryGroup /// The - internal ImageFrame Clone() => this.Clone(this.GetConfiguration()); + internal ImageFrame Clone() => this.Clone(this.Configuration); /// /// Clones the current instance. @@ -396,7 +396,7 @@ internal override void CopyPixelsTo(MemoryGroupThe pixel format. /// The internal ImageFrame? CloneAs() - where TPixel2 : unmanaged, IPixel => this.CloneAs(this.GetConfiguration()); + where TPixel2 : unmanaged, IPixel => this.CloneAs(this.Configuration); /// /// Returns a copy of the image frame in the given pixel format. diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 75d4b173c8..b08c27c41b 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -22,8 +22,8 @@ - - 3.0 + + 3.1 diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 69654329c4..c24014e698 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -78,12 +78,12 @@ public Image(int width, int height) /// The height of the image in pixels. /// The images metadata. internal Image(Configuration configuration, int width, int height, ImageMetadata? metadata) - : base(configuration, PixelTypeInfo.Create(), metadata, width, height) + : base(configuration, PixelTypeInfo.Create(), metadata ?? new(), width, height) => this.frames = new ImageFrameCollection(this, width, height, default(TPixel)); /// /// Initializes a new instance of the class - /// wrapping an external pixel bufferx. + /// wrapping an external pixel buffer. /// /// The configuration providing initialization code which allows extending the library. /// Pixel buffer. @@ -129,7 +129,7 @@ internal Image( int height, TPixel backgroundColor, ImageMetadata? metadata) - : base(configuration, PixelTypeInfo.Create(), metadata, width, height) + : base(configuration, PixelTypeInfo.Create(), metadata ?? new(), width, height) => this.frames = new ImageFrameCollection(this, width, height, backgroundColor); /// @@ -328,7 +328,7 @@ public bool DangerousTryGetSinglePixelMemory(out Memory memory) /// Clones the current image /// /// Returns a new image with all the same metadata as the original. - public Image Clone() => this.Clone(this.GetConfiguration()); + public Image Clone() => this.Clone(this.Configuration); /// /// Clones the current image with the given configuration. diff --git a/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs index 798edf9b22..0bae193632 100644 --- a/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs +++ b/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs @@ -117,6 +117,11 @@ internal override MemoryGroup AllocateGroup( AllocationOptions options = AllocationOptions.None) { long totalLengthInBytes = totalLength * Unsafe.SizeOf(); + if (totalLengthInBytes < 0) + { + throw new InvalidMemoryOperationException("Attempted to allocate a MemoryGroup of a size that is not representable."); + } + if (totalLengthInBytes <= this.sharedArrayPoolThresholdInBytes) { var buffer = new SharedArrayPoolBuffer((int)totalLength); diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index f4b2dfc08c..39c6e62e15 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -9,9 +9,6 @@ namespace SixLabors.ImageSharp.Memory; /// Represents a buffer of value type objects /// interpreted as a 2D region of x elements. /// -/// -/// Before RC1, this class might be target of API changes, use it on your own risk! -/// /// The value type. public sealed class Buffer2D : IDisposable where T : struct diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs index 741df50f2d..4767ca852e 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs @@ -56,11 +56,6 @@ public abstract partial class ExifTag /// public static ExifTag IntergraphRegisters { get; } = new ExifTag(ExifTagValue.IntergraphRegisters); - /// - /// Gets the TimeZoneOffset exif tag. - /// - public static ExifTag TimeZoneOffset { get; } = new ExifTag(ExifTagValue.TimeZoneOffset); - /// /// Gets the offset to child IFDs exif tag. /// diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Rational.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Rational.cs index 96603b182a..e4fe13fe57 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Rational.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Rational.cs @@ -165,4 +165,9 @@ public abstract partial class ExifTag /// Gets the GPSDestDistance exif tag. /// public static ExifTag GPSDestDistance { get; } = new ExifTag(ExifTagValue.GPSDestDistance); + + /// + /// Gets the GPSHPositioningError exif tag. + /// + public static ExifTag GPSHPositioningError { get; } = new ExifTag(ExifTagValue.GPSHPositioningError); } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedShortArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedShortArray.cs new file mode 100644 index 0000000000..d6a9205143 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedShortArray.cs @@ -0,0 +1,13 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif; + +/// +public abstract partial class ExifTag +{ + /// + /// Gets the TimeZoneOffset exif tag. + /// + public static ExifTag TimeZoneOffset { get; } = new ExifTag(ExifTagValue.TimeZoneOffset); +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTagValue.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTagValue.cs index 3788a1296f..56e8a3ffd1 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTagValue.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTagValue.cs @@ -1691,6 +1691,11 @@ internal enum ExifTagValue /// GPSDifferential = 0x001E, + /// + /// GPSHPositioningError + /// + GPSHPositioningError = 0x001F, + /// /// Used in the Oce scanning process. /// Identifies the scanticket used in the scanning process. diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShortArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShortArray.cs index 8023fb8bca..206417f667 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShortArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShortArray.cs @@ -5,6 +5,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif; internal sealed class ExifSignedShortArray : ExifArrayValue { + public ExifSignedShortArray(ExifTag tag) + : base(tag) + { + } + public ExifSignedShortArray(ExifTagValue tag) : base(tag) { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs index 8aa54c3a40..93f67d46ad 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs @@ -144,8 +144,6 @@ internal static partial class ExifValues return new ExifLongArray(ExifTag.StripRowCounts); case ExifTagValue.IntergraphRegisters: return new ExifLongArray(ExifTag.IntergraphRegisters); - case ExifTagValue.TimeZoneOffset: - return new ExifLongArray(ExifTag.TimeZoneOffset); case ExifTagValue.SubIFDs: return new ExifLongArray(ExifTag.SubIFDs); @@ -243,6 +241,8 @@ internal static partial class ExifValues return new ExifRational(ExifTag.GPSDestBearing); case ExifTagValue.GPSDestDistance: return new ExifRational(ExifTag.GPSDestDistance); + case ExifTagValue.GPSHPositioningError: + return new ExifRational(ExifTag.GPSHPositioningError); case ExifTagValue.WhitePoint: return new ExifRationalArray(ExifTag.WhitePoint); @@ -417,6 +417,9 @@ internal static partial class ExifValues case ExifTagValue.Decode: return new ExifSignedRationalArray(ExifTag.Decode); + case ExifTagValue.TimeZoneOffset: + return new ExifSignedShortArray(ExifTag.TimeZoneOffset); + case ExifTagValue.ImageDescription: return new ExifString(ExifTag.ImageDescription); case ExifTagValue.Make: diff --git a/src/ImageSharp/Metadata/Profiles/ICC/IccReader.cs b/src/ImageSharp/Metadata/Profiles/ICC/IccReader.cs index 0fe01fbdb2..45074c9a6e 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/IccReader.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/IccReader.cs @@ -88,9 +88,9 @@ private static IccTagDataEntry[] ReadTagData(IccDataReader reader) foreach (IccTagTableEntry tag in tagTable) { IccTagDataEntry entry; - if (store.ContainsKey(tag.Offset)) + if (store.TryGetValue(tag.Offset, out IccTagDataEntry? value)) { - entry = store[tag.Offset]; + entry = value; } else { diff --git a/src/ImageSharp/Processing/Extensions/ProcessingExtensions.IntegralImage.cs b/src/ImageSharp/Processing/Extensions/ProcessingExtensions.IntegralImage.cs index fdf0967c53..713d4d5b77 100644 --- a/src/ImageSharp/Processing/Extensions/ProcessingExtensions.IntegralImage.cs +++ b/src/ImageSharp/Processing/Extensions/ProcessingExtensions.IntegralImage.cs @@ -54,7 +54,7 @@ public static Buffer2D CalculateIntegralImage(this ImageFrame CalculateIntegralImage(this ImageFrame source, Rectangle bounds) where TPixel : unmanaged, IPixel { - Configuration configuration = source.GetConfiguration(); + Configuration configuration = source.Configuration; var interest = Rectangle.Intersect(bounds, source.Bounds()); int startY = interest.Y; diff --git a/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs b/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs index f830ddfd09..784258aa51 100644 --- a/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs @@ -22,7 +22,7 @@ public static partial class ProcessingExtensions /// The source has been disposed. /// The processing operation failed. public static void Mutate(this Image source, Action operation) - => Mutate(source, source.GetConfiguration(), operation); + => Mutate(source, source.Configuration, operation); /// /// Mutates the source image by applying the image operation to it. @@ -57,7 +57,7 @@ public static void Mutate(this Image source, Configuration configuration, Action /// The processing operation failed. public static void Mutate(this Image source, Action operation) where TPixel : unmanaged, IPixel - => Mutate(source, source.GetConfiguration(), operation); + => Mutate(source, source.Configuration, operation); /// /// Mutates the source image by applying the image operation to it. @@ -97,7 +97,7 @@ IInternalImageProcessingContext operationsRunner /// The processing operation failed. public static void Mutate(this Image source, params IImageProcessor[] operations) where TPixel : unmanaged, IPixel - => Mutate(source, source.GetConfiguration(), operations); + => Mutate(source, source.Configuration, operations); /// /// Mutates the source image by applying the operations to it. @@ -135,7 +135,7 @@ IInternalImageProcessingContext operationsRunner /// The source has been disposed. /// The processing operation failed. public static Image Clone(this Image source, Action operation) - => Clone(source, source.GetConfiguration(), operation); + => Clone(source, source.Configuration, operation); /// /// Creates a deep clone of the current image. The clone is then mutated by the given operation. @@ -174,7 +174,7 @@ public static Image Clone(this Image source, Configuration configuration, Action /// The new . public static Image Clone(this Image source, Action operation) where TPixel : unmanaged, IPixel - => Clone(source, source.GetConfiguration(), operation); + => Clone(source, source.Configuration, operation); /// /// Creates a deep clone of the current image. The clone is then mutated by the given operation. @@ -217,7 +217,7 @@ IInternalImageProcessingContext operationsRunner /// The new public static Image Clone(this Image source, params IImageProcessor[] operations) where TPixel : unmanaged, IPixel - => Clone(source, source.GetConfiguration(), operations); + => Clone(source, source.Configuration, operations); /// /// Creates a deep clone of the current image. The clone is then mutated by the given operations. diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs index a231d6dee7..524153804c 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs @@ -111,7 +111,7 @@ public WuQuantizer(Configuration configuration, QuantizerOptions options) public QuantizerOptions Options { get; } /// - public ReadOnlyMemory Palette + public readonly ReadOnlyMemory Palette { get { @@ -362,7 +362,7 @@ private static Moment Top(ref Box cube, int direction, int position, ReadOnlySpa /// /// The source data. /// The bounds within the source image to quantize. - private void Build3DHistogram(Buffer2D source, Rectangle bounds) + private readonly void Build3DHistogram(Buffer2D source, Rectangle bounds) { Span momentSpan = this.momentsOwner.GetSpan(); @@ -393,7 +393,7 @@ private void Build3DHistogram(Buffer2D source, Rectangle bounds) /// Converts the histogram into moments so that we can rapidly calculate the sums of the above quantities over any desired box. /// /// The memory allocator used for allocating buffers. - private void Get3DMoments(MemoryAllocator allocator) + private readonly void Get3DMoments(MemoryAllocator allocator) { using IMemoryOwner volume = allocator.Allocate(IndexCount * IndexAlphaCount); using IMemoryOwner area = allocator.Allocate(IndexAlphaCount); @@ -462,7 +462,7 @@ private void Get3DMoments(MemoryAllocator allocator) /// /// The cube. /// The . - private double Variance(ref Box cube) + private readonly double Variance(ref Box cube) { ReadOnlySpan momentSpan = this.momentsOwner.GetSpan(); @@ -503,7 +503,7 @@ private double Variance(ref Box cube) /// The cutting point. /// The whole moment. /// The . - private float Maximize(ref Box cube, int direction, int first, int last, out int cut, Moment whole) + private readonly float Maximize(ref Box cube, int direction, int first, int last, out int cut, Moment whole) { ReadOnlySpan momentSpan = this.momentsOwner.GetSpan(); Moment bottom = Bottom(ref cube, direction, momentSpan); @@ -634,7 +634,7 @@ private bool Cut(ref Box set1, ref Box set2) /// /// The cube. /// A label. - private void Mark(ref Box cube, byte label) + private readonly void Mark(ref Box cube, byte label) { Span tagSpan = this.tagsOwner.GetSpan(); diff --git a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs index 9afc852b58..2eda61e41d 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs @@ -38,7 +38,7 @@ protected override void BeforeImageApply() // All frames have be the same size so we only need to calculate the correct dimensions for the first frame using (Image temp = new(this.Configuration, this.Source.Metadata.DeepClone(), new[] { this.Source.Frames.RootFrame.Clone() })) { - Configuration configuration = this.Source.GetConfiguration(); + Configuration configuration = this.Source.Configuration; // Detect the edges. new EdgeDetector2DProcessor(KnownEdgeDetectorKernels.Sobel, false).Execute(this.Configuration, temp, this.SourceRectangle); diff --git a/tests/ImageSharp.Tests/Color/ColorTests.cs b/tests/ImageSharp.Tests/Color/ColorTests.cs index 85e6eba78c..f7e2092176 100644 --- a/tests/ImageSharp.Tests/Color/ColorTests.cs +++ b/tests/ImageSharp.Tests/Color/ColorTests.cs @@ -18,25 +18,42 @@ public void WithAlpha() Assert.Equal(expected, (Rgba32)c2); } - [Fact] - public void Equality_WhenTrue() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void Equality_WhenTrue(bool highPrecision) { Color c1 = new Rgba64(100, 2000, 3000, 40000); Color c2 = new Rgba64(100, 2000, 3000, 40000); + if (highPrecision) + { + c1 = Color.FromPixel(c1.ToPixel()); + c2 = Color.FromPixel(c2.ToPixel()); + } + Assert.True(c1.Equals(c2)); Assert.True(c1 == c2); Assert.False(c1 != c2); Assert.True(c1.GetHashCode() == c2.GetHashCode()); } - [Fact] - public void Equality_WhenFalse() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void Equality_WhenFalse(bool highPrecision) { Color c1 = new Rgba64(100, 2000, 3000, 40000); Color c2 = new Rgba64(101, 2000, 3000, 40000); Color c3 = new Rgba64(100, 2000, 3000, 40001); + if (highPrecision) + { + c1 = Color.FromPixel(c1.ToPixel()); + c2 = Color.FromPixel(c2.ToPixel()); + c3 = Color.FromPixel(c3.ToPixel()); + } + Assert.False(c1.Equals(c2)); Assert.False(c2.Equals(c3)); Assert.False(c3.Equals(c1)); @@ -47,13 +64,20 @@ public void Equality_WhenFalse() Assert.False(c1.Equals(null)); } - [Fact] - public void ToHex() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void ToHex(bool highPrecision) { string expected = "ABCD1234"; - var color = Color.ParseHex(expected); - string actual = color.ToHex(); + Color color = Color.ParseHex(expected); + if (highPrecision) + { + color = Color.FromPixel(color.ToPixel()); + } + + string actual = color.ToHex(); Assert.Equal(expected, actual); } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 2dfd99439a..e216832853 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -539,7 +539,8 @@ public void Issue2209_Decode_HasTransparencyIsTrue(TestImageProvider image = provider.GetImage(PngDecoder.Instance); PngMetadata metadata = image.Metadata.GetPngMetadata(); - Assert.True(metadata.HasTransparency); + Assert.NotNull(metadata.ColorTable); + Assert.Contains(metadata.ColorTable.Value.ToArray(), x => x.ToRgba32().A < 255); } // https://github.com/SixLabors/ImageSharp/issues/2209 @@ -551,7 +552,8 @@ public void Issue2209_Identify_HasTransparencyIsTrue(string imagePath) using MemoryStream stream = new(testFile.Bytes, false); ImageInfo imageInfo = Image.Identify(stream); PngMetadata metadata = imageInfo.Metadata.GetPngMetadata(); - Assert.True(metadata.HasTransparency); + Assert.NotNull(metadata.ColorTable); + Assert.Contains(metadata.ColorTable.Value.ToArray(), x => x.ToRgba32().A < 255); } // https://github.com/SixLabors/ImageSharp/issues/410 diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index b20ec0675a..3c80cfe098 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -449,44 +449,17 @@ public void Encode_PreserveTrns(string imagePath, PngBitDepth pngBitDepth, PngCo TestFile testFile = TestFile.Create(imagePath); using Image input = testFile.CreateRgba32Image(); PngMetadata inMeta = input.Metadata.GetPngMetadata(); - Assert.True(inMeta.HasTransparency); + Assert.True(inMeta.TransparentColor.HasValue); using MemoryStream memStream = new(); input.Save(memStream, PngEncoder); memStream.Position = 0; using Image output = Image.Load(memStream); PngMetadata outMeta = output.Metadata.GetPngMetadata(); - Assert.True(outMeta.HasTransparency); - - switch (pngColorType) - { - case PngColorType.Grayscale: - if (pngBitDepth.Equals(PngBitDepth.Bit16)) - { - Assert.True(outMeta.TransparentL16.HasValue); - Assert.Equal(inMeta.TransparentL16, outMeta.TransparentL16); - } - else - { - Assert.True(outMeta.TransparentL8.HasValue); - Assert.Equal(inMeta.TransparentL8, outMeta.TransparentL8); - } - - break; - case PngColorType.Rgb: - if (pngBitDepth.Equals(PngBitDepth.Bit16)) - { - Assert.True(outMeta.TransparentRgb48.HasValue); - Assert.Equal(inMeta.TransparentRgb48, outMeta.TransparentRgb48); - } - else - { - Assert.True(outMeta.TransparentRgb24.HasValue); - Assert.Equal(inMeta.TransparentRgb24, outMeta.TransparentRgb24); - } - - break; - } + Assert.True(outMeta.TransparentColor.HasValue); + Assert.Equal(inMeta.TransparentColor, outMeta.TransparentColor); + Assert.Equal(pngBitDepth, outMeta.BitDepth); + Assert.Equal(pngColorType, outMeta.ColorType); } [Theory] diff --git a/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs b/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs index 258ee5b9f7..9b03a447a9 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs @@ -42,7 +42,7 @@ public void ConvertRgbToYuv_Works(TestImageProvider provider) { // arrange using Image image = provider.GetImage(); - Configuration config = image.GetConfiguration(); + Configuration config = image.Configuration; MemoryAllocator memoryAllocator = config.MemoryAllocator; int pixels = image.Width * image.Height; int uvWidth = (image.Width + 1) >> 1; @@ -158,7 +158,7 @@ public void ConvertRgbToYuv_WithAlpha_Works(TestImageProvider pr { // arrange using Image image = provider.GetImage(); - Configuration config = image.GetConfiguration(); + Configuration config = image.Configuration; MemoryAllocator memoryAllocator = config.MemoryAllocator; int pixels = image.Width * image.Height; int uvWidth = (image.Width + 1) >> 1; diff --git a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs index 9cfd393906..f9ff6ba69e 100644 --- a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs +++ b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs @@ -20,7 +20,7 @@ public class NonGeneric : ImageFrameCollectionTests public void AddFrame_OfDifferentPixelType() { using (Image sourceImage = new( - this.Image.GetConfiguration(), + this.Image.Configuration, this.Image.Width, this.Image.Height, Color.Blue)) @@ -41,7 +41,7 @@ public void AddFrame_OfDifferentPixelType() public void InsertFrame_OfDifferentPixelType() { using (Image sourceImage = new( - this.Image.GetConfiguration(), + this.Image.Configuration, this.Image.Width, this.Image.Height, Color.Blue)) @@ -278,8 +278,8 @@ public void ConstructGif_FromDifferentPixelTypes(TestImageProvider { using Image source = provider.GetImage(); - using Image dest = new(source.GetConfiguration(), source.Width, source.Height); - + using Image dest = new(source.Configuration, source.Width, source.Height); + // Giphy.gif has 5 frames ImportFrameAs(source.Frames, dest.Frames, 0); ImportFrameAs(source.Frames, dest.Frames, 1); diff --git a/tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs b/tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs index 87794f3357..5fc58a752b 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.SaveAsync.cs @@ -70,7 +70,7 @@ public async Task SaveStreamWithMime(string filename, string mimeType) { using Image image = new(5, 5); string ext = Path.GetExtension(filename); - image.GetConfiguration().ImageFormatsManager.TryFindFormatByFileExtension(ext, out IImageFormat format); + image.Configuration.ImageFormatsManager.TryFindFormatByFileExtension(ext, out IImageFormat format); Assert.Equal(mimeType, format!.DefaultMimeType); using MemoryStream stream = new(); diff --git a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs index 3239c57b1a..9aaefa41ef 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs @@ -136,7 +136,7 @@ public void WrapMemory_CreatedImageIsCorrect() ref Rgba32 pixel0 = ref imageMem.Span[0]; Assert.True(Unsafe.AreSame(ref array[0], ref pixel0)); - Assert.Equal(cfg, image.GetConfiguration()); + Assert.Equal(cfg, image.Configuration); Assert.Equal(metaData, image.Metadata); } } @@ -239,7 +239,7 @@ public void WrapMemory_FromBytes_CreatedImageIsCorrect() ref Rgba32 pixel0 = ref imageMem.Span[0]; Assert.True(Unsafe.AreSame(ref Unsafe.As(ref array[0]), ref pixel0)); - Assert.Equal(cfg, image.GetConfiguration()); + Assert.Equal(cfg, image.Configuration); Assert.Equal(metaData, image.Metadata); } } @@ -336,7 +336,7 @@ public unsafe void WrapMemory_FromPointer_CreatedImageIsCorrect() ref Rgba32 pixel_1 = ref imageSpan[imageSpan.Length - 1]; Assert.True(Unsafe.AreSame(ref array[array.Length - 1], ref pixel_1)); - Assert.Equal(cfg, image.GetConfiguration()); + Assert.Equal(cfg, image.Configuration); Assert.Equal(metaData, image.Metadata); } } diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index eefa81835e..ca51f7f5cb 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -6,6 +6,7 @@ using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.Memory; @@ -31,10 +32,14 @@ public void Width_Height() Assert.Equal(11 * 23, imageMem.Length); image.ComparePixelBufferTo(default(Rgba32)); - Assert.Equal(Configuration.Default, image.GetConfiguration()); + Assert.Equal(Configuration.Default, image.Configuration); } } + [Fact] + public void Width_Height_SizeNotRepresentable_ThrowsInvalidImageOperationException() + => Assert.Throws(() => new Image(int.MaxValue, int.MaxValue)); + [Fact] public void Configuration_Width_Height() { @@ -48,7 +53,7 @@ public void Configuration_Width_Height() Assert.Equal(11 * 23, imageMem.Length); image.ComparePixelBufferTo(default(Rgba32)); - Assert.Equal(configuration, image.GetConfiguration()); + Assert.Equal(configuration, image.Configuration); } } @@ -66,7 +71,7 @@ public void Configuration_Width_Height_BackgroundColor() Assert.Equal(11 * 23, imageMem.Length); image.ComparePixelBufferTo(color); - Assert.Equal(configuration, image.GetConfiguration()); + Assert.Equal(configuration, image.Configuration); } } @@ -83,7 +88,7 @@ public void CreateUninitialized() { Assert.Equal(21, image.Width); Assert.Equal(22, image.Height); - Assert.Same(configuration, image.GetConfiguration()); + Assert.Same(configuration, image.Configuration); Assert.Same(metadata, image.Metadata); Assert.Equal(dirtyValue, image[5, 5].PackedValue); diff --git a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs index 3403e3f17e..7e7c136635 100644 --- a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs +++ b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs @@ -107,6 +107,13 @@ public void AllocateGroup_MultipleTimes_ExceedPoolLimit() } } + [Fact] + public void AllocateGroup_SizeInBytesOverLongMaxValue_ThrowsInvalidMemoryOperationException() + { + var allocator = new UniformUnmanagedMemoryPoolMemoryAllocator(null); + Assert.Throws(() => allocator.AllocateGroup(int.MaxValue * (long)int.MaxValue, int.MaxValue)); + } + [Fact] public unsafe void Allocate_MemoryIsPinnableMultipleTimes() { diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs index 1adb7bd556..99cafa8960 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs @@ -70,8 +70,7 @@ public class ExifValuesTests { ExifTag.JPEGDCTables }, { ExifTag.JPEGACTables }, { ExifTag.StripRowCounts }, - { ExifTag.IntergraphRegisters }, - { ExifTag.TimeZoneOffset } + { ExifTag.IntergraphRegisters } }; public static TheoryData NumberTags => new TheoryData @@ -129,6 +128,7 @@ public class ExifValuesTests { ExifTag.GPSImgDirection }, { ExifTag.GPSDestBearing }, { ExifTag.GPSDestDistance }, + { ExifTag.GPSHPositioningError }, }; public static TheoryData RationalArrayTags => new TheoryData @@ -235,6 +235,11 @@ public class ExifValuesTests { ExifTag.Decode } }; + public static TheoryData SignedShortArrayTags => new TheoryData + { + { ExifTag.TimeZoneOffset } + }; + public static TheoryData StringTags => new TheoryData { { ExifTag.ImageDescription }, @@ -559,6 +564,21 @@ public void ExifSignedRationalArrayTests(ExifTag tag) Assert.Equal(expected, typed.Value); } + + [Theory] + [MemberData(nameof(SignedShortArrayTags))] + public void ExifSignedShortArrayTests(ExifTag tag) + { + short[] expected = new short[] { 21, 42 }; + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(expected.ToString())); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifSignedShortArray)value; + Assert.Equal(expected, typed.Value); + } + [Theory] [MemberData(nameof(StringTags))] public void ExifStringTests(ExifTag tag) diff --git a/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs b/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs index 98b5c8e980..403865e662 100644 --- a/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs +++ b/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs @@ -22,7 +22,7 @@ public BaseImageOperationsExtensionTest() this.options = new GraphicsOptions { Antialias = false }; this.source = new Image(91 + 324, 123 + 56); this.rect = new Rectangle(91, 123, 324, 56); // make this random? - this.internalOperations = new FakeImageOperationsProvider.FakeImageOperations(this.source.GetConfiguration(), this.source, false); + this.internalOperations = new FakeImageOperationsProvider.FakeImageOperations(this.source.Configuration, this.source, false); this.internalOperations.SetGraphicsOptions(this.options); this.operations = this.internalOperations; } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs index 0e53856dac..c94983ecd5 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs @@ -65,7 +65,7 @@ public void VerifyComplexComponents() // Make sure the kernel components are the same using Image image = new(1, 1); - Configuration configuration = image.GetConfiguration(); + Configuration configuration = image.Configuration; BokehBlurProcessor definition = new(10, BokehBlurProcessor.DefaultComponents, BokehBlurProcessor.DefaultGamma); using BokehBlurProcessor processor = (BokehBlurProcessor)definition.CreatePixelSpecificProcessor(configuration, image, image.Bounds); diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs index 52f160dedc..aa8ab397d2 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs @@ -28,7 +28,7 @@ public override ImageSimilarityReport CompareImagesOrFrames(); - Configuration configuration = expected.GetConfiguration(); + Configuration configuration = expected.Configuration; Buffer2D expectedBuffer = expected.PixelBuffer; Buffer2D actualBuffer = actual.PixelBuffer; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs index c541133079..93ed4c6fff 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs @@ -72,7 +72,7 @@ public override ImageSimilarityReport CompareImagesOrFrames(); - Configuration configuration = expected.GetConfiguration(); + Configuration configuration = expected.Configuration; Buffer2D expectedBuffer = expected.PixelBuffer; Buffer2D actualBuffer = actual.PixelBuffer; diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/ImageSharpPngEncoderWithDefaultConfiguration.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/ImageSharpPngEncoderWithDefaultConfiguration.cs index a4d305d97f..d32a6c93f1 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/ImageSharpPngEncoderWithDefaultConfiguration.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/ImageSharpPngEncoderWithDefaultConfiguration.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using SixLabors.ImageSharp.Formats.Png; -using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; @@ -15,10 +14,7 @@ public sealed class ImageSharpPngEncoderWithDefaultConfiguration : PngEncoder /// protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken) { - Configuration configuration = Configuration.Default; - MemoryAllocator allocator = configuration.MemoryAllocator; - - using PngEncoderCore encoder = new(allocator, configuration, this); + using PngEncoderCore encoder = new(Configuration.Default, this); encoder.Encode(image, stream, cancellationToken); } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs index e57da55895..04f59979f7 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs @@ -45,7 +45,7 @@ internal static unsafe Image From32bppArgbSystemDrawingBitmap(Bi long sourceRowByteCount = data.Stride; long destRowByteCount = w * sizeof(Bgra32); - Configuration configuration = image.GetConfiguration(); + Configuration configuration = image.Configuration; image.ProcessPixelRows(accessor => { using IMemoryOwner workBuffer = Configuration.Default.MemoryAllocator.Allocate(w); @@ -104,7 +104,7 @@ internal static unsafe Image From24bppRgbSystemDrawingBitmap(Bit long sourceRowByteCount = data.Stride; long destRowByteCount = w * sizeof(Bgr24); - Configuration configuration = image.GetConfiguration(); + Configuration configuration = image.Configuration; Buffer2D imageBuffer = image.Frames.RootFrame.PixelBuffer; using (IMemoryOwner workBuffer = Configuration.Default.MemoryAllocator.Allocate(w)) @@ -134,7 +134,7 @@ internal static unsafe Image From24bppRgbSystemDrawingBitmap(Bit internal static unsafe Bitmap To32bppArgbSystemDrawingBitmap(Image image) where TPixel : unmanaged, IPixel { - Configuration configuration = image.GetConfiguration(); + Configuration configuration = image.Configuration; int w = image.Width; int h = image.Height; @@ -148,7 +148,7 @@ internal static unsafe Bitmap To32bppArgbSystemDrawingBitmap(Image { - using IMemoryOwner workBuffer = image.GetConfiguration().MemoryAllocator.Allocate(w); + using IMemoryOwner workBuffer = image.Configuration.MemoryAllocator.Allocate(w); fixed (Bgra32* sourcePtr = &workBuffer.GetReference()) { for (int y = 0; y < h; y++) diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs index cbce961103..974e951f6f 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs @@ -342,8 +342,8 @@ private static void EnsureCustomConfigurationIsApplied(TestImageProvider using Image image2 = provider.GetImage(); using Image image3 = provider.GetImage(); - Assert.Same(customConfiguration, image2.GetConfiguration()); - Assert.Same(customConfiguration, image3.GetConfiguration()); + Assert.Same(customConfiguration, image2.Configuration); + Assert.Same(customConfiguration, image3.Configuration); } }