diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
index 24a4fa2f57..298bb8dbca 100644
--- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
@@ -4,7 +4,6 @@
using System.Buffers;
using System.Buffers.Binary;
using System.Runtime.InteropServices;
-using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
diff --git a/src/ImageSharp/Formats/Bmp/BmpMetadata.cs b/src/ImageSharp/Formats/Bmp/BmpMetadata.cs
index bad47bd0d5..c19ab44cf7 100644
--- a/src/ImageSharp/Formats/Bmp/BmpMetadata.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpMetadata.cs
@@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp;
///
/// Provides Bmp specific metadata information for the image.
///
-public class BmpMetadata : IFormatMetadata, IFormatFrameMetadata
+public class BmpMetadata : IFormatMetadata
{
///
/// Initializes a new instance of the class.
@@ -66,10 +66,6 @@ public class BmpMetadata : IFormatMetadata, IFormatFrameMetadata
- public static BmpMetadata FromFormatConnectingFrameMetadata(FormatConnectingFrameMetadata metadata)
- => new();
-
///
public PixelTypeInfo GetPixelTypeInfo()
{
@@ -140,10 +136,6 @@ public class BmpMetadata : IFormatMetadata, IFormatFrameMetadata
- public FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata()
- => new();
-
///
IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone();
diff --git a/src/ImageSharp/Formats/Bmp/MetadataExtensions.cs b/src/ImageSharp/Formats/Bmp/MetadataExtensions.cs
deleted file mode 100644
index 5297d0c989..0000000000
--- a/src/ImageSharp/Formats/Bmp/MetadataExtensions.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Six Labors Split License.
-
-using SixLabors.ImageSharp.Formats.Bmp;
-using SixLabors.ImageSharp.Metadata;
-
-namespace SixLabors.ImageSharp;
-
-///
-/// Extension methods for the type.
-///
-public static partial class MetadataExtensions
-{
- ///
- /// Gets the bmp format specific metadata for the image.
- ///
- /// The metadata this method extends.
- /// The .
- public static BmpMetadata GetBmpMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(BmpFormat.Instance);
-}
diff --git a/src/ImageSharp/Formats/EncodingType.cs b/src/ImageSharp/Formats/EncodingType.cs
new file mode 100644
index 0000000000..f4567ca43d
--- /dev/null
+++ b/src/ImageSharp/Formats/EncodingType.cs
@@ -0,0 +1,20 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+namespace SixLabors.ImageSharp.Formats;
+
+///
+/// Provides a way to specify the type of encoding to be used.
+///
+public enum EncodingType
+{
+ ///
+ /// Lossless encoding, which compresses data without any loss of information.
+ ///
+ Lossless,
+
+ ///
+ /// Lossy encoding, which compresses data by discarding some of it.
+ ///
+ Lossy
+}
diff --git a/src/ImageSharp/Formats/FormatConnectingMetadata.cs b/src/ImageSharp/Formats/FormatConnectingMetadata.cs
index 2acbe96990..07579c09e8 100644
--- a/src/ImageSharp/Formats/FormatConnectingMetadata.cs
+++ b/src/ImageSharp/Formats/FormatConnectingMetadata.cs
@@ -11,7 +11,12 @@ namespace SixLabors.ImageSharp.Formats;
public class FormatConnectingMetadata
{
///
- /// Gets the quality.
+ /// Gets the encoding type.
+ ///
+ public EncodingType EncodingType { get; init; }
+
+ ///
+ /// Gets the quality to use when is .
///
///
/// The value is usually between 1 and 100. Defaults to 100.
diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
index 5fd20d6ae2..90177ccc1b 100644
--- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
@@ -5,8 +5,6 @@ using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
-using SixLabors.ImageSharp.Formats.Png;
-using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Xmp;
@@ -85,7 +83,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
- GifMetadata gifMetadata = GetGifMetadata(image);
+ GifMetadata gifMetadata = image.Metadata.CloneGifMetadata();
this.colorTableMode ??= gifMetadata.ColorTableMode;
bool useGlobalTable = this.colorTableMode == FrameColorTableMode.Global;
@@ -178,56 +176,17 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
quantized?.Dispose();
}
- private static GifMetadata GetGifMetadata(Image image)
- where TPixel : unmanaged, IPixel
- {
- if (image.Metadata.TryGetGifMetadata(out GifMetadata? gif))
- {
- return gif.DeepClone();
- }
-
- if (image.Metadata.TryGetPngMetadata(out PngMetadata? png))
- {
- AnimatedImageMetadata ani = png.ToAnimatedImageMetadata();
- return GifMetadata.FromAnimatedMetadata(ani);
- }
-
- if (image.Metadata.TryGetWebpMetadata(out WebpMetadata? webp))
- {
- AnimatedImageMetadata ani = webp.ToAnimatedImageMetadata();
- return GifMetadata.FromAnimatedMetadata(ani);
- }
-
- // Return explicit new instance so we do not mutate the original metadata.
- return new();
- }
-
private static GifFrameMetadata GetGifFrameMetadata(ImageFrame frame, int transparencyIndex)
where TPixel : unmanaged, IPixel
{
- GifFrameMetadata? metadata = null;
- if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata? gif))
- {
- metadata = gif.DeepClone();
- }
- else if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png))
- {
- AnimatedImageFrameMetadata ani = png.ToAnimatedImageFrameMetadata();
- metadata = GifFrameMetadata.FromAnimatedMetadata(ani);
- }
- else if (frame.Metadata.TryGetWebpFrameMetadata(out WebpFrameMetadata? webp))
- {
- AnimatedImageFrameMetadata ani = webp.ToAnimatedImageFrameMetadata();
- metadata = GifFrameMetadata.FromAnimatedMetadata(ani);
- }
-
- if (metadata?.ColorTableMode == FrameColorTableMode.Global && transparencyIndex > -1)
+ GifFrameMetadata metadata = frame.Metadata.CloneGifMetadata();
+ if (metadata.ColorTableMode == FrameColorTableMode.Global && transparencyIndex > -1)
{
metadata.HasTransparency = true;
metadata.TransparencyIndex = ClampIndex(transparencyIndex);
}
- return metadata ?? new();
+ return metadata;
}
private void EncodeAdditionalFrames(
diff --git a/src/ImageSharp/Formats/Gif/GifMetadata.cs b/src/ImageSharp/Formats/Gif/GifMetadata.cs
index 90d3312c85..565038b55a 100644
--- a/src/ImageSharp/Formats/Gif/GifMetadata.cs
+++ b/src/ImageSharp/Formats/Gif/GifMetadata.cs
@@ -69,34 +69,6 @@ public class GifMetadata : IFormatMetadata
///
public IList Comments { get; set; } = [];
- internal static GifMetadata FromAnimatedMetadata(AnimatedImageMetadata metadata)
- {
- int index = 0;
- Color background = metadata.BackgroundColor;
- if (metadata.ColorTable.HasValue)
- {
- ReadOnlySpan colorTable = metadata.ColorTable.Value.Span;
- for (int i = 0; i < colorTable.Length; i++)
- {
- if (background != colorTable[i])
- {
- continue;
- }
-
- index = i;
- break;
- }
- }
-
- return new()
- {
- GlobalColorTable = metadata.ColorTable,
- ColorTableMode = metadata.ColorTableMode,
- RepeatCount = metadata.RepeatCount,
- BackgroundColorIndex = (byte)Numerics.Clamp(index, 0, 255),
- };
- }
-
///
public static GifMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata)
{
diff --git a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs
deleted file mode 100644
index 0f2d281f16..0000000000
--- a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Six Labors Split License.
-
-using System.Diagnostics.CodeAnalysis;
-using SixLabors.ImageSharp.Formats;
-using SixLabors.ImageSharp.Formats.Gif;
-using SixLabors.ImageSharp.Metadata;
-
-namespace SixLabors.ImageSharp;
-
-///
-/// Extension methods for the type.
-///
-public static partial class MetadataExtensions
-{
- ///
- /// Gets the gif format specific metadata for the image.
- ///
- /// The metadata this method extends.
- /// The .
- public static GifMetadata GetGifMetadata(this ImageMetadata source)
- => source.GetFormatMetadata(GifFormat.Instance);
-
- ///
- /// Gets the gif format specific metadata for the image.
- ///
- /// The metadata this method extends.
- ///
- /// When this method returns, contains the metadata associated with the specified image,
- /// if found; otherwise, the default value for the type of the metadata parameter.
- /// This parameter is passed uninitialized.
- ///
- ///
- /// if the gif metadata exists; otherwise, .
- ///
- public static bool TryGetGifMetadata(this ImageMetadata source, [NotNullWhen(true)] out GifMetadata? metadata)
- => source.TryGetFormatMetadata(GifFormat.Instance, out metadata);
-
- ///
- /// Gets the gif format specific metadata for the image frame.
- ///
- /// The metadata this method extends.
- /// The .
- public static GifFrameMetadata GetGifMetadata(this ImageFrameMetadata source)
- => source.GetFormatMetadata(GifFormat.Instance);
-
- ///
- /// Gets the gif format specific metadata for the image frame.
- ///
- /// The metadata this method extends.
- ///
- /// When this method returns, contains the metadata associated with the specified frame,
- /// if found; otherwise, the default value for the type of the metadata parameter.
- /// This parameter is passed uninitialized.
- ///
- ///
- /// if the gif frame metadata exists; otherwise, .
- ///
- public static bool TryGetGifMetadata(this ImageFrameMetadata source, [NotNullWhen(true)] out GifFrameMetadata? metadata)
- => source.TryGetFormatMetadata(GifFormat.Instance, out metadata);
-
- internal static AnimatedImageMetadata ToAnimatedImageMetadata(this GifMetadata source)
- {
- Color background = Color.Transparent;
- if (source.GlobalColorTable != null)
- {
- background = source.GlobalColorTable.Value.Span[source.BackgroundColorIndex];
- }
-
- return new()
- {
- ColorTable = source.GlobalColorTable,
- ColorTableMode = source.ColorTableMode,
- RepeatCount = source.RepeatCount,
- BackgroundColor = background,
- };
- }
-
- internal static AnimatedImageFrameMetadata ToAnimatedImageFrameMetadata(this GifFrameMetadata source)
- {
- // For most scenarios we would consider the blend method to be 'Over' however if a frame has a disposal method of 'RestoreToBackground' or
- // has a local palette with 256 colors and is not transparent we should use 'Source'.
- bool blendSource = source.DisposalMode == FrameDisposalMode.RestoreToBackground || (source.LocalColorTable?.Length == 256 && !source.HasTransparency);
-
- // If the color table is global and frame has no transparency. Consider it 'Source' also.
- blendSource |= source.ColorTableMode == FrameColorTableMode.Global && !source.HasTransparency;
-
- return new()
- {
- ColorTable = source.LocalColorTable,
- ColorTableMode = source.ColorTableMode,
- Duration = TimeSpan.FromMilliseconds(source.FrameDelay * 10),
- DisposalMode = source.DisposalMode,
- BlendMode = blendSource ? FrameBlendMode.Source : FrameBlendMode.Over,
- };
- }
-}
diff --git a/src/ImageSharp/Formats/IFormatFrameMetadata.cs b/src/ImageSharp/Formats/IFormatFrameMetadata.cs
index 4c5321073d..4eef93ad34 100644
--- a/src/ImageSharp/Formats/IFormatFrameMetadata.cs
+++ b/src/ImageSharp/Formats/IFormatFrameMetadata.cs
@@ -20,7 +20,7 @@ public interface IFormatFrameMetadata : IDeepCloneable
///
/// The metadata type implementing this interface.
public interface IFormatFrameMetadata : IFormatFrameMetadata, IDeepCloneable
- where TSelf : class, IFormatFrameMetadata, new()
+ where TSelf : class, IFormatFrameMetadata
{
///
/// Creates a new instance of the class from the given .
diff --git a/src/ImageSharp/Formats/IFormatMetadata.cs b/src/ImageSharp/Formats/IFormatMetadata.cs
index e0c32e8b26..8d695306e4 100644
--- a/src/ImageSharp/Formats/IFormatMetadata.cs
+++ b/src/ImageSharp/Formats/IFormatMetadata.cs
@@ -28,7 +28,7 @@ public interface IFormatMetadata : IDeepCloneable
///
/// The metadata type implementing this interface.
public interface IFormatMetadata : IFormatMetadata, IDeepCloneable
- where TSelf : class, IFormatMetadata, new()
+ where TSelf : class, IFormatMetadata
{
///
/// Creates a new instance of the class from the given .
diff --git a/src/ImageSharp/Formats/ImageDecoder.cs b/src/ImageSharp/Formats/ImageDecoder.cs
index ebb45d7013..4e79f79efc 100644
--- a/src/ImageSharp/Formats/ImageDecoder.cs
+++ b/src/ImageSharp/Formats/ImageDecoder.cs
@@ -2,6 +2,7 @@
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.IO;
+using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
@@ -231,7 +232,7 @@ public abstract class ImageDecoder : IImageDecoder
throw new NotSupportedException("Cannot read from the stream.");
}
- Task PeformActionAndResetPosition(Stream s, long position, CancellationToken ct)
+ Task PerformActionAndResetPosition(Stream s, long position, CancellationToken ct)
{
try
{
@@ -263,15 +264,15 @@ public abstract class ImageDecoder : IImageDecoder
// code below to copy the stream to an in-memory buffer before invoking the action.
if (stream is MemoryStream ms)
{
- return PeformActionAndResetPosition(ms, ms.Position, cancellationToken);
+ return PerformActionAndResetPosition(ms, ms.Position, cancellationToken);
}
if (stream is ChunkedMemoryStream cms)
{
- return PeformActionAndResetPosition(cms, cms.Position, cancellationToken);
+ return PerformActionAndResetPosition(cms, cms.Position, cancellationToken);
}
- return CopyToMemoryStreamAndActionAsync(options, stream, PeformActionAndResetPosition, cancellationToken);
+ return CopyToMemoryStreamAndActionAsync(options, stream, PerformActionAndResetPosition, cancellationToken);
}
private static async Task CopyToMemoryStreamAndActionAsync(
@@ -282,7 +283,7 @@ public abstract class ImageDecoder : IImageDecoder
{
long position = stream.CanSeek ? stream.Position : 0;
Configuration configuration = options.Configuration;
- using ChunkedMemoryStream memoryStream = new(configuration.MemoryAllocator);
+ await using ChunkedMemoryStream memoryStream = new(configuration.MemoryAllocator);
await stream.CopyToAsync(memoryStream, configuration.StreamProcessingBufferSize, cancellationToken).ConfigureAwait(false);
memoryStream.Position = 0;
return await action(memoryStream, position, cancellationToken).ConfigureAwait(false);
@@ -293,6 +294,11 @@ public abstract class ImageDecoder : IImageDecoder
if (configuration.ImageFormatsManager.TryFindFormatByDecoder(this, out IImageFormat? format))
{
image.Metadata.DecodedImageFormat = format;
+
+ foreach (ImageFrame frame in image.Frames)
+ {
+ frame.Metadata.DecodedImageFormat = format;
+ }
}
}
@@ -301,6 +307,11 @@ public abstract class ImageDecoder : IImageDecoder
if (configuration.ImageFormatsManager.TryFindFormatByDecoder(this, out IImageFormat? format))
{
info.Metadata.DecodedImageFormat = format;
+
+ foreach (ImageFrameMetadata frame in info.FrameMetadataCollection)
+ {
+ frame.DecodedImageFormat = format;
+ }
}
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs b/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs
index 8b123fa35d..f2f34ec496 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs
@@ -112,7 +112,7 @@ public class JpegMetadata : IFormatMetadata
public static JpegMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata)
{
JpegColorType color;
- PixelColorType colorType = metadata.PixelTypeInfo.ColorType ?? PixelColorType.YCbCr;
+ PixelColorType colorType = metadata.PixelTypeInfo.ColorType;
switch (colorType)
{
case PixelColorType.Luminance:
@@ -194,6 +194,7 @@ public class JpegMetadata : IFormatMetadata
public FormatConnectingMetadata ToFormatConnectingMetadata()
=> new()
{
+ EncodingType = EncodingType.Lossy,
PixelTypeInfo = this.GetPixelTypeInfo(),
Quality = this.Quality,
};
diff --git a/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs b/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs
deleted file mode 100644
index 7330e74b79..0000000000
--- a/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Six Labors Split License.
-
-using System.Text;
-using SixLabors.ImageSharp.Formats.Jpeg;
-using SixLabors.ImageSharp.Metadata;
-
-namespace SixLabors.ImageSharp;
-
-///
-/// Extension methods for the type.
-///
-public static partial class MetadataExtensions
-{
- ///
- /// Gets the jpeg format specific metadata for the image.
- ///
- /// The metadata this method extends.
- /// The .
- public static JpegMetadata GetJpegMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(JpegFormat.Instance);
-}
diff --git a/src/ImageSharp/Formats/Pbm/IPbmEncoderOptions.cs b/src/ImageSharp/Formats/Pbm/IPbmEncoderOptions.cs
deleted file mode 100644
index 7039ef2620..0000000000
--- a/src/ImageSharp/Formats/Pbm/IPbmEncoderOptions.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Six Labors Split License.
-
-namespace SixLabors.ImageSharp.Formats.Pbm;
-
-///
-/// Configuration options for use during PBM encoding.
-///
-internal interface IPbmEncoderOptions
-{
- ///
- /// Gets the encoding of the pixels.
- ///
- PbmEncoding? Encoding { get; }
-
- ///
- /// Gets the Color type of the resulting image.
- ///
- PbmColorType? ColorType { get; }
-
- ///
- /// Gets the Data Type of the pixel components.
- ///
- PbmComponentType? ComponentType { get; }
-}
diff --git a/src/ImageSharp/Formats/Pbm/MetadataExtensions.cs b/src/ImageSharp/Formats/Pbm/MetadataExtensions.cs
deleted file mode 100644
index 6d44e91a50..0000000000
--- a/src/ImageSharp/Formats/Pbm/MetadataExtensions.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Six Labors Split License.
-
-using SixLabors.ImageSharp.Formats.Pbm;
-using SixLabors.ImageSharp.Metadata;
-
-namespace SixLabors.ImageSharp;
-
-///
-/// Extension methods for the type.
-///
-public static partial class MetadataExtensions
-{
- ///
- /// Gets the pbm format specific metadata for the image.
- ///
- /// The metadata this method extends.
- /// The .
- public static PbmMetadata GetPbmMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(PbmFormat.Instance);
-}
diff --git a/src/ImageSharp/Formats/Pbm/PbmEncoder.cs b/src/ImageSharp/Formats/Pbm/PbmEncoder.cs
index 8258c91655..f7a9d79366 100644
--- a/src/ImageSharp/Formats/Pbm/PbmEncoder.cs
+++ b/src/ImageSharp/Formats/Pbm/PbmEncoder.cs
@@ -1,8 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-using SixLabors.ImageSharp.Advanced;
-
namespace SixLabors.ImageSharp.Formats.Pbm;
///
diff --git a/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs b/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs
index b6e31a3c28..5ae37d4e69 100644
--- a/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs
+++ b/src/ImageSharp/Formats/Pbm/PbmEncoderCore.cs
@@ -2,7 +2,6 @@
// Licensed under the Six Labors Split License.
using System.Buffers.Text;
-using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Pbm;
diff --git a/src/ImageSharp/Formats/Pbm/PbmMetadata.cs b/src/ImageSharp/Formats/Pbm/PbmMetadata.cs
index 49a36de41e..9b23aecac2 100644
--- a/src/ImageSharp/Formats/Pbm/PbmMetadata.cs
+++ b/src/ImageSharp/Formats/Pbm/PbmMetadata.cs
@@ -46,7 +46,7 @@ public class PbmMetadata : IFormatMetadata
public static PbmMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata)
{
PbmColorType color;
- PixelColorType colorType = metadata.PixelTypeInfo.ColorType ?? PixelColorType.Luminance;
+ PixelColorType colorType = metadata.PixelTypeInfo.ColorType;
switch (colorType)
{
diff --git a/src/ImageSharp/Formats/Png/MetadataExtensions.cs b/src/ImageSharp/Formats/Png/MetadataExtensions.cs
deleted file mode 100644
index 6da1fb5fdb..0000000000
--- a/src/ImageSharp/Formats/Png/MetadataExtensions.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Six Labors Split License.
-
-using System.Diagnostics.CodeAnalysis;
-using SixLabors.ImageSharp.Formats;
-using SixLabors.ImageSharp.Formats.Png;
-using SixLabors.ImageSharp.Metadata;
-
-namespace SixLabors.ImageSharp;
-
-///
-/// Extension methods for the type.
-///
-public static partial class MetadataExtensions
-{
- ///
- /// Gets the png format specific metadata for the image.
- ///
- /// The metadata this method extends.
- /// The .
- public static PngMetadata GetPngMetadata(this ImageMetadata source) => source.GetFormatMetadata(PngFormat.Instance);
-
- ///
- /// Gets the png format specific metadata for the image.
- ///
- /// The metadata this method extends.
- /// The metadata.
- ///
- /// if the png metadata exists; otherwise, .
- ///
- public static bool TryGetPngMetadata(this ImageMetadata source, [NotNullWhen(true)] out PngMetadata? metadata)
- => source.TryGetFormatMetadata(PngFormat.Instance, out metadata);
-
- ///
- /// Gets the png format specific metadata for the image frame.
- ///
- /// The metadata this method extends.
- /// The .
- public static PngFrameMetadata GetPngMetadata(this ImageFrameMetadata source) => source.GetFormatMetadata(PngFormat.Instance);
-
- ///
- /// Gets the png format specific metadata for the image frame.
- ///
- /// The metadata this method extends.
- /// The metadata.
- ///
- /// if the png frame metadata exists; otherwise, .
- ///
- public static bool TryGetPngMetadata(this ImageFrameMetadata source, [NotNullWhen(true)] out PngFrameMetadata? metadata)
- => source.TryGetFormatMetadata(PngFormat.Instance, out metadata);
-
- internal static AnimatedImageMetadata ToAnimatedImageMetadata(this PngMetadata source)
- => new()
- {
- ColorTable = source.ColorTable,
- ColorTableMode = FrameColorTableMode.Global,
- RepeatCount = (ushort)Numerics.Clamp(source.RepeatCount, 0, ushort.MaxValue),
- };
-
- internal static AnimatedImageFrameMetadata ToAnimatedImageFrameMetadata(this PngFrameMetadata source)
- {
- double delay = source.FrameDelay.ToDouble();
- if (double.IsNaN(delay))
- {
- delay = 0;
- }
-
- return new()
- {
- ColorTableMode = FrameColorTableMode.Global,
- Duration = TimeSpan.FromMilliseconds(delay * 1000),
- DisposalMode = GetMode(source.DisposalMode),
- BlendMode = source.BlendMode,
- };
- }
-
- private static FrameDisposalMode GetMode(FrameDisposalMode method) => method switch
- {
- FrameDisposalMode.DoNotDispose => FrameDisposalMode.DoNotDispose,
- FrameDisposalMode.RestoreToBackground => FrameDisposalMode.RestoreToBackground,
- FrameDisposalMode.RestoreToPrevious => FrameDisposalMode.RestoreToPrevious,
- _ => FrameDisposalMode.DoNotDispose,
- };
-}
diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs
index e62a14b5e0..cfea0e6020 100644
--- a/src/ImageSharp/Formats/Png/PngDecoder.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoder.cs
@@ -101,5 +101,5 @@ public sealed class PngDecoder : SpecializedImageDecoder
}
///
- protected override PngDecoderOptions CreateDefaultSpecializedOptions(DecoderOptions options) => new PngDecoderOptions() { GeneralOptions = options };
+ protected override PngDecoderOptions CreateDefaultSpecializedOptions(DecoderOptions options) => new() { GeneralOptions = options };
}
diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index d1528d08b4..a5ab739882 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
@@ -9,10 +9,8 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Compression.Zlib;
-using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Png.Chunks;
using SixLabors.ImageSharp.Formats.Png.Filters;
-using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
@@ -160,7 +158,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
this.height = image.Height;
ImageMetadata metadata = image.Metadata;
- PngMetadata pngMetadata = GetPngMetadata(image);
+ PngMetadata pngMetadata = metadata.ClonePngMetadata();
this.SanitizeAndSetEncoderOptions(this.encoder, pngMetadata, out this.use16Bit, out this.bytesPerPixel);
stream.Write(PngConstants.HeaderBytes);
@@ -211,7 +209,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
{
// Write the first animated frame.
currentFrame = image.Frames[currentFrameIndex];
- PngFrameMetadata frameMetadata = GetPngFrameMetadata(currentFrame);
+ PngFrameMetadata frameMetadata = currentFrame.Metadata.GetPngMetadata();
FrameDisposalMode previousDisposal = frameMetadata.DisposalMode;
FrameControl frameControl = this.WriteFrameControlChunk(stream, frameMetadata, currentFrame.Bounds(), 0);
uint sequenceNumber = 1;
@@ -241,7 +239,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
currentFrame = image.Frames[currentFrameIndex];
ImageFrame? nextFrame = currentFrameIndex < image.Frames.Count - 1 ? image.Frames[currentFrameIndex + 1] : null;
- frameMetadata = GetPngFrameMetadata(currentFrame);
+ frameMetadata = currentFrame.Metadata.GetPngMetadata();
bool blend = frameMetadata.BlendMode == FrameBlendMode.Over;
(bool difference, Rectangle bounds) =
@@ -288,54 +286,6 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
this.currentScanline?.Dispose();
}
- private static PngMetadata GetPngMetadata(Image image)
- where TPixel : unmanaged, IPixel
- {
- if (image.Metadata.TryGetPngMetadata(out PngMetadata? png))
- {
- return png.DeepClone();
- }
-
- if (image.Metadata.TryGetGifMetadata(out GifMetadata? gif))
- {
- AnimatedImageMetadata ani = gif.ToAnimatedImageMetadata();
- return PngMetadata.FromAnimatedMetadata(ani);
- }
-
- if (image.Metadata.TryGetWebpMetadata(out WebpMetadata? webp))
- {
- AnimatedImageMetadata ani = webp.ToAnimatedImageMetadata();
- return PngMetadata.FromAnimatedMetadata(ani);
- }
-
- // Return explicit new instance so we do not mutate the original metadata.
- return new();
- }
-
- private static PngFrameMetadata GetPngFrameMetadata(ImageFrame frame)
- where TPixel : unmanaged, IPixel
- {
- if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png))
- {
- return png.DeepClone();
- }
-
- if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata? gif))
- {
- AnimatedImageFrameMetadata ani = gif.ToAnimatedImageFrameMetadata();
- return PngFrameMetadata.FromAnimatedMetadata(ani);
- }
-
- if (frame.Metadata.TryGetWebpFrameMetadata(out WebpFrameMetadata? webp))
- {
- AnimatedImageFrameMetadata ani = webp.ToAnimatedImageFrameMetadata();
- return PngFrameMetadata.FromAnimatedMetadata(ani);
- }
-
- // Return explicit new instance so we do not mutate the original metadata.
- return new();
- }
-
///
/// Convert transparent pixels, to transparent black pixels, which can yield to better compression in some cases.
///
diff --git a/src/ImageSharp/Formats/Png/PngFrameMetadata.cs b/src/ImageSharp/Formats/Png/PngFrameMetadata.cs
index de141909ad..c142a1c8e0 100644
--- a/src/ImageSharp/Formats/Png/PngFrameMetadata.cs
+++ b/src/ImageSharp/Formats/Png/PngFrameMetadata.cs
@@ -57,22 +57,6 @@ public class PngFrameMetadata : IFormatFrameMetadata
this.BlendMode = frameControl.BlendMode;
}
- internal static PngFrameMetadata FromAnimatedMetadata(AnimatedImageFrameMetadata metadata)
- => new()
- {
- FrameDelay = new(metadata.Duration.TotalMilliseconds / 1000),
- DisposalMode = GetMode(metadata.DisposalMode),
- BlendMode = metadata.BlendMode,
- };
-
- private static FrameDisposalMode GetMode(FrameDisposalMode mode) => mode switch
- {
- FrameDisposalMode.RestoreToBackground => FrameDisposalMode.RestoreToBackground,
- FrameDisposalMode.RestoreToPrevious => FrameDisposalMode.RestoreToPrevious,
- FrameDisposalMode.DoNotDispose => FrameDisposalMode.DoNotDispose,
- _ => FrameDisposalMode.DoNotDispose,
- };
-
///
public static PngFrameMetadata FromFormatConnectingFrameMetadata(FormatConnectingFrameMetadata metadata)
=> new()
@@ -105,4 +89,12 @@ public class PngFrameMetadata : IFormatFrameMetadata
///
public PngFrameMetadata DeepClone() => new(this);
+
+ private static FrameDisposalMode GetMode(FrameDisposalMode mode) => mode switch
+ {
+ FrameDisposalMode.RestoreToBackground => FrameDisposalMode.RestoreToBackground,
+ FrameDisposalMode.RestoreToPrevious => FrameDisposalMode.RestoreToPrevious,
+ FrameDisposalMode.DoNotDispose => FrameDisposalMode.DoNotDispose,
+ _ => FrameDisposalMode.DoNotDispose,
+ };
}
diff --git a/src/ImageSharp/Formats/Png/PngMetadata.cs b/src/ImageSharp/Formats/Png/PngMetadata.cs
index d72dc51841..beb4ca5ae8 100644
--- a/src/ImageSharp/Formats/Png/PngMetadata.cs
+++ b/src/ImageSharp/Formats/Png/PngMetadata.cs
@@ -90,38 +90,6 @@ public class PngMetadata : IFormatMetadata
///
public bool AnimateRootFrame { get; set; } = true;
- internal static PngMetadata FromAnimatedMetadata(AnimatedImageMetadata metadata)
- {
- // Should the conversion be from a format that uses a 24bit palette entries (gif)
- // we need to clone and adjust the color table to allow for transparency.
- Color[]? colorTable = metadata.ColorTable?.ToArray();
- if (colorTable != null)
- {
- for (int i = 0; i < colorTable.Length; i++)
- {
- ref Color c = ref colorTable[i];
- if (c != metadata.BackgroundColor)
- {
- continue;
- }
-
- // Png treats background as fully empty
- c = Color.Transparent;
- break;
- }
- }
-
- return new()
- {
- ColorType = colorTable != null ? PngColorType.Palette : PngColorType.RgbWithAlpha,
- BitDepth = colorTable != null
- ? (PngBitDepth)Numerics.Clamp(ColorNumerics.GetBitsNeededForColorDepth(colorTable.Length), 1, 8)
- : PngBitDepth.Bit8,
- ColorTable = colorTable,
- RepeatCount = metadata.RepeatCount,
- };
- }
-
///
public static PngMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata)
{
@@ -145,8 +113,7 @@ public class PngMetadata : IFormatMetadata
}
PngColorType color;
- PixelColorType colorType =
- metadata.PixelTypeInfo.ColorType ?? PixelColorType.RGB | PixelColorType.Alpha;
+ PixelColorType colorType = metadata.PixelTypeInfo.ColorType;
switch (colorType)
{
diff --git a/src/ImageSharp/Formats/Qoi/MetadataExtensions.cs b/src/ImageSharp/Formats/Qoi/MetadataExtensions.cs
deleted file mode 100644
index 1e0fa88997..0000000000
--- a/src/ImageSharp/Formats/Qoi/MetadataExtensions.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Six Labors Split License.
-
-using SixLabors.ImageSharp.Formats.Qoi;
-using SixLabors.ImageSharp.Metadata;
-
-namespace SixLabors.ImageSharp;
-
-///
-/// Extension methods for the type.
-///
-public static partial class MetadataExtensions
-{
- ///
- /// Gets the qoi format specific metadata for the image.
- ///
- /// The metadata this method extends.
- /// The .
- public static QoiMetadata GetQoiMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(QoiFormat.Instance);
-}
diff --git a/src/ImageSharp/Formats/Qoi/QoiMetadata.cs b/src/ImageSharp/Formats/Qoi/QoiMetadata.cs
index c8bcd97480..e2062014d7 100644
--- a/src/ImageSharp/Formats/Qoi/QoiMetadata.cs
+++ b/src/ImageSharp/Formats/Qoi/QoiMetadata.cs
@@ -40,7 +40,7 @@ public class QoiMetadata : IFormatMetadata
///
public static QoiMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata)
{
- PixelColorType color = metadata.PixelTypeInfo.ColorType ?? PixelColorType.RGB;
+ PixelColorType color = metadata.PixelTypeInfo.ColorType;
if (color.HasFlag(PixelColorType.Alpha))
{
diff --git a/src/ImageSharp/Formats/Tga/MetadataExtensions.cs b/src/ImageSharp/Formats/Tga/MetadataExtensions.cs
deleted file mode 100644
index 8d5e357641..0000000000
--- a/src/ImageSharp/Formats/Tga/MetadataExtensions.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Six Labors Split License.
-
-using SixLabors.ImageSharp.Formats.Tga;
-using SixLabors.ImageSharp.Metadata;
-
-namespace SixLabors.ImageSharp;
-
-///
-/// Extension methods for the type.
-///
-public static partial class MetadataExtensions
-{
- ///
- /// Gets the tga format specific metadata for the image.
- ///
- /// The metadata this method extends.
- /// The .
- public static TgaMetadata GetTgaMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(TgaFormat.Instance);
-}
diff --git a/src/ImageSharp/Formats/Tiff/MetadataExtensions.cs b/src/ImageSharp/Formats/Tiff/MetadataExtensions.cs
deleted file mode 100644
index b06f5dd470..0000000000
--- a/src/ImageSharp/Formats/Tiff/MetadataExtensions.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Six Labors Split License.
-
-using SixLabors.ImageSharp.Formats.Tiff;
-using SixLabors.ImageSharp.Metadata;
-
-namespace SixLabors.ImageSharp;
-
-///
-/// Extension methods for the type.
-///
-public static partial class MetadataExtensions
-{
- ///
- /// Gets the tiff format specific metadata for the image.
- ///
- /// The metadata this method extends.
- /// The .
- public static TiffMetadata GetTiffMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(TiffFormat.Instance);
-
- ///
- /// Gets the tiff format specific metadata for the image frame.
- ///
- /// The metadata this method extends.
- /// The .
- public static TiffFrameMetadata GetTiffMetadata(this ImageFrameMetadata metadata) => metadata.GetFormatMetadata(TiffFormat.Instance);
-}
diff --git a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
index 546ff7947d..c8eeb1e31f 100644
--- a/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
@@ -395,7 +395,6 @@ internal sealed class TiffEncoderCore : IImageEncoderInternals
case TiffBitsPerPixel.Bit42:
case TiffBitsPerPixel.Bit48:
// Encoding not yet supported bits per pixel will default to 24 bits.
-
this.SetEncoderOptions(TiffBitsPerPixel.Bit24, TiffPhotometricInterpretation.Rgb, compression, predictor);
break;
case TiffBitsPerPixel.Bit64:
diff --git a/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs b/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs
index c8ff579a89..66662569c3 100644
--- a/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs
+++ b/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs
@@ -10,7 +10,7 @@ internal readonly struct WebpFrameData
///
public const uint HeaderSize = 16;
- public WebpFrameData(uint dataSize, uint x, uint y, uint width, uint height, uint duration, WebpBlendMethod blendingMethod, WebpDisposalMethod disposalMethod)
+ public WebpFrameData(uint dataSize, uint x, uint y, uint width, uint height, uint duration, FrameBlendMode blendingMethod, FrameDisposalMode disposalMethod)
{
this.DataSize = dataSize;
this.X = x;
@@ -30,12 +30,12 @@ internal readonly struct WebpFrameData
width,
height,
duration,
- (flags & 2) == 0 ? WebpBlendMethod.Over : WebpBlendMethod.Source,
- (flags & 1) == 1 ? WebpDisposalMethod.RestoreToBackground : WebpDisposalMethod.DoNotDispose)
+ (flags & 2) == 0 ? FrameBlendMode.Over : FrameBlendMode.Source,
+ (flags & 1) == 1 ? FrameDisposalMode.RestoreToBackground : FrameDisposalMode.DoNotDispose)
{
}
- public WebpFrameData(uint x, uint y, uint width, uint height, uint duration, WebpBlendMethod blendingMethod, WebpDisposalMethod disposalMethod)
+ public WebpFrameData(uint x, uint y, uint width, uint height, uint duration, FrameBlendMode blendingMethod, FrameDisposalMode disposalMethod)
: this(0, x, y, width, height, duration, blendingMethod, disposalMethod)
{
}
@@ -74,12 +74,12 @@ internal readonly struct WebpFrameData
///
/// Gets how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas.
///
- public WebpBlendMethod BlendingMethod { get; }
+ public FrameBlendMode BlendingMethod { get; }
///
/// Gets how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas.
///
- public WebpDisposalMethod DisposalMethod { get; }
+ public FrameDisposalMode DisposalMethod { get; }
public Rectangle Bounds => new((int)this.X, (int)this.Y, (int)this.Width, (int)this.Height);
@@ -91,13 +91,13 @@ internal readonly struct WebpFrameData
{
byte flags = 0;
- if (this.BlendingMethod is WebpBlendMethod.Source)
+ if (this.BlendingMethod is FrameBlendMode.Source)
{
// Set blending flag.
flags |= 2;
}
- if (this.DisposalMethod is WebpDisposalMethod.RestoreToBackground)
+ if (this.DisposalMethod is FrameDisposalMode.RestoreToBackground)
{
// Set disposal flag.
flags |= 1;
@@ -124,7 +124,7 @@ internal readonly struct WebpFrameData
{
Span buffer = stackalloc byte[4];
- WebpFrameData data = new(
+ return new(
dataSize: WebpChunkParsingUtils.ReadChunkSize(stream, buffer),
x: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer) * 2,
y: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer) * 2,
@@ -132,7 +132,5 @@ internal readonly struct WebpFrameData
height: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer) + 1,
duration: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer),
flags: stream.ReadByte());
-
- return data;
}
}
diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs
index f658e40f6f..58d007265b 100644
--- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs
+++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs
@@ -259,7 +259,7 @@ internal class Vp8LEncoder : IDisposable
if (hasAnimation)
{
- WebpMetadata webpMetadata = WebpCommonUtils.GetWebpMetadata(image);
+ WebpMetadata webpMetadata = image.Metadata.GetWebpMetadata();
BitWriterBase.WriteAnimationParameter(stream, webpMetadata.BackgroundColor, webpMetadata.RepeatCount);
}
diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs
index 40d91ecf1a..7e1ef93cfe 100644
--- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs
+++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs
@@ -332,7 +332,7 @@ internal class Vp8Encoder : IDisposable
if (hasAnimation)
{
- WebpMetadata webpMetadata = WebpCommonUtils.GetWebpMetadata(image);
+ WebpMetadata webpMetadata = image.Metadata.GetWebpMetadata();
BitWriterBase.WriteAnimationParameter(stream, webpMetadata.BackgroundColor, webpMetadata.RepeatCount);
}
@@ -376,7 +376,7 @@ internal class Vp8Encoder : IDisposable
where TPixel : unmanaged, IPixel
{
ImageFrame frame = image.Frames.RootFrame;
- this.Encode(stream, frame, image.Bounds, WebpCommonUtils.GetWebpFrameMetadata(frame), false, image);
+ this.Encode(stream, frame, image.Bounds, frame.Metadata.GetWebpMetadata(), false, image);
}
///
@@ -462,7 +462,7 @@ internal class Vp8Encoder : IDisposable
// Extract and encode alpha channel data, if present.
int alphaDataSize = 0;
bool alphaCompressionSucceeded = false;
- Span alphaData = Span.Empty;
+ Span alphaData = [];
IMemoryOwner encodedAlphaData = null;
try
{
diff --git a/src/ImageSharp/Formats/Webp/MetadataExtensions.cs b/src/ImageSharp/Formats/Webp/MetadataExtensions.cs
deleted file mode 100644
index 731d3f1ff2..0000000000
--- a/src/ImageSharp/Formats/Webp/MetadataExtensions.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Six Labors Split License.
-
-using System.Diagnostics.CodeAnalysis;
-using SixLabors.ImageSharp.Formats;
-using SixLabors.ImageSharp.Formats.Webp;
-using SixLabors.ImageSharp.Metadata;
-
-namespace SixLabors.ImageSharp;
-
-///
-/// Extension methods for the type.
-///
-public static partial class MetadataExtensions
-{
- ///
- /// Gets the webp format specific metadata for the image.
- ///
- /// The metadata this method extends.
- /// The .
- public static WebpMetadata GetWebpMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(WebpFormat.Instance);
-
- ///
- /// Gets the webp format specific metadata for the image.
- ///
- /// The metadata this method extends.
- /// The metadata.
- ///
- /// if the webp metadata exists; otherwise, .
- ///
- public static bool TryGetWebpMetadata(this ImageMetadata source, [NotNullWhen(true)] out WebpMetadata? metadata)
- => source.TryGetFormatMetadata(WebpFormat.Instance, out metadata);
-
- ///
- /// Gets the webp format specific metadata for the image frame.
- ///
- /// The metadata this method extends.
- /// The .
- public static WebpFrameMetadata GetWebpMetadata(this ImageFrameMetadata metadata) => metadata.GetFormatMetadata(WebpFormat.Instance);
-
- ///
- /// Gets the webp format specific metadata for the image frame.
- ///
- /// The metadata this method extends.
- /// The metadata.
- ///
- /// if the webp frame metadata exists; otherwise, .
- ///
- public static bool TryGetWebpFrameMetadata(this ImageFrameMetadata source, [NotNullWhen(true)] out WebpFrameMetadata? metadata)
- => source.TryGetFormatMetadata(WebpFormat.Instance, out metadata);
-
- internal static AnimatedImageMetadata ToAnimatedImageMetadata(this WebpMetadata source)
- => new()
- {
- ColorTableMode = FrameColorTableMode.Global,
- RepeatCount = source.RepeatCount,
- BackgroundColor = source.BackgroundColor
- };
-
- internal static AnimatedImageFrameMetadata ToAnimatedImageFrameMetadata(this WebpFrameMetadata source)
- => new()
- {
- ColorTableMode = FrameColorTableMode.Global,
- Duration = TimeSpan.FromMilliseconds(source.FrameDelay),
- DisposalMode = GetMode(source.DisposalMethod),
- BlendMode = source.BlendMethod == WebpBlendMethod.Over ? FrameBlendMode.Over : FrameBlendMode.Source,
- };
-
- private static FrameDisposalMode GetMode(WebpDisposalMethod method) => method switch
- {
- WebpDisposalMethod.RestoreToBackground => FrameDisposalMode.RestoreToBackground,
- WebpDisposalMethod.DoNotDispose => FrameDisposalMode.DoNotDispose,
- _ => FrameDisposalMode.DoNotDispose,
- };
-}
diff --git a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs
index 70372fe985..72405e480e 100644
--- a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs
+++ b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs
@@ -195,14 +195,14 @@ internal class WebpAnimationDecoder : IDisposable
Rectangle regionRectangle = frameData.Bounds;
- if (frameData.DisposalMethod is WebpDisposalMethod.RestoreToBackground)
+ if (frameData.DisposalMethod is FrameDisposalMode.RestoreToBackground)
{
this.RestoreToBackground(imageFrame, backgroundColor);
}
using Buffer2D decodedImageFrame = this.DecodeImageFrameData(frameData, webpInfo);
- bool blend = previousFrame != null && frameData.BlendingMethod == WebpBlendMethod.Over;
+ bool blend = previousFrame != null && frameData.BlendingMethod == FrameBlendMode.Over;
DrawDecodedImageFrameOnCanvas(decodedImageFrame, imageFrame, regionRectangle, blend);
previousFrame = currentFrame ?? image.Frames.RootFrame;
diff --git a/src/ImageSharp/Formats/Webp/WebpBlendMethod.cs b/src/ImageSharp/Formats/Webp/WebpBlendMethod.cs
deleted file mode 100644
index f16f7650c7..0000000000
--- a/src/ImageSharp/Formats/Webp/WebpBlendMethod.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Six Labors Split License.
-
-namespace SixLabors.ImageSharp.Formats.Webp;
-
-///
-/// Indicates how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas.
-///
-public enum WebpBlendMethod
-{
- ///
- /// Do not blend. After disposing of the previous frame,
- /// render the current frame on the canvas by overwriting the rectangle covered by the current frame.
- ///
- Source = 0,
-
- ///
- /// Use alpha blending. After disposing of the previous frame, render the current frame on the canvas using alpha-blending.
- /// If the current frame does not have an alpha channel, assume alpha value of 255, effectively replacing the rectangle.
- ///
- Over = 1,
-}
diff --git a/src/ImageSharp/Formats/Webp/WebpCommonUtils.cs b/src/ImageSharp/Formats/Webp/WebpCommonUtils.cs
index 49482260bb..a1e9821c09 100644
--- a/src/ImageSharp/Formats/Webp/WebpCommonUtils.cs
+++ b/src/ImageSharp/Formats/Webp/WebpCommonUtils.cs
@@ -4,8 +4,6 @@
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
-using SixLabors.ImageSharp.Formats.Gif;
-using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Webp;
@@ -15,54 +13,6 @@ namespace SixLabors.ImageSharp.Formats.Webp;
///
internal static class WebpCommonUtils
{
- public static WebpMetadata GetWebpMetadata(Image image)
- where TPixel : unmanaged, IPixel
- {
- if (image.Metadata.TryGetWebpMetadata(out WebpMetadata? webp))
- {
- return (WebpMetadata)webp.DeepClone();
- }
-
- if (image.Metadata.TryGetGifMetadata(out GifMetadata? gif))
- {
- AnimatedImageMetadata ani = gif.ToAnimatedImageMetadata();
- return WebpMetadata.FromAnimatedMetadata(ani);
- }
-
- if (image.Metadata.TryGetPngMetadata(out PngMetadata? png))
- {
- AnimatedImageMetadata ani = png.ToAnimatedImageMetadata();
- return WebpMetadata.FromAnimatedMetadata(ani);
- }
-
- // Return explicit new instance so we do not mutate the original metadata.
- return new();
- }
-
- public static WebpFrameMetadata GetWebpFrameMetadata(ImageFrame frame)
- where TPixel : unmanaged, IPixel
- {
- if (frame.Metadata.TryGetWebpFrameMetadata(out WebpFrameMetadata? webp))
- {
- return (WebpFrameMetadata)webp.DeepClone();
- }
-
- if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata? gif))
- {
- AnimatedImageFrameMetadata ani = gif.ToAnimatedImageFrameMetadata();
- return WebpFrameMetadata.FromAnimatedMetadata(ani);
- }
-
- if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png))
- {
- AnimatedImageFrameMetadata ani = png.ToAnimatedImageFrameMetadata();
- return WebpFrameMetadata.FromAnimatedMetadata(ani);
- }
-
- // Return explicit new instance so we do not mutate the original metadata.
- return new();
- }
-
///
/// Checks if the pixel row is not opaque.
///
diff --git a/src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs b/src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs
deleted file mode 100644
index 47cc83951d..0000000000
--- a/src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Six Labors Split License.
-
-namespace SixLabors.ImageSharp.Formats.Webp;
-
-///
-/// Indicates how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas.
-///
-public enum WebpDisposalMethod
-{
- ///
- /// Do not dispose. Leave the canvas as is.
- ///
- DoNotDispose = 0,
-
- ///
- /// Dispose to background color. Fill the rectangle on the canvas covered by the current frame with background color specified in the ANIM chunk.
- ///
- RestoreToBackground = 1
-}
diff --git a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs
index d29759f9a1..21ce444b11 100644
--- a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs
+++ b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs
@@ -5,6 +5,7 @@ using SixLabors.ImageSharp.Formats.Webp.Chunks;
using SixLabors.ImageSharp.Formats.Webp.Lossless;
using SixLabors.ImageSharp.Formats.Webp.Lossy;
using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Webp;
@@ -124,7 +125,7 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals
}
else
{
- WebpMetadata webpMetadata = WebpCommonUtils.GetWebpMetadata(image);
+ WebpMetadata webpMetadata = image.Metadata.GetWebpMetadata();
lossless = webpMetadata.FileFormat == WebpFileFormatType.Lossless;
}
@@ -150,12 +151,12 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals
// Encode the first frame.
ImageFrame previousFrame = image.Frames.RootFrame;
- WebpFrameMetadata frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(previousFrame);
+ WebpFrameMetadata frameMetadata = previousFrame.Metadata.GetWebpMetadata();
hasAlpha |= encoder.Encode(previousFrame, previousFrame.Bounds(), frameMetadata, stream, hasAnimation);
if (hasAnimation)
{
- WebpDisposalMethod previousDisposal = frameMetadata.DisposalMethod;
+ FrameDisposalMode previousDisposal = frameMetadata.DisposalMethod;
// Encode additional frames
// This frame is reused to store de-duplicated pixel buffers.
@@ -163,12 +164,12 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals
for (int i = 1; i < image.Frames.Count; i++)
{
- ImageFrame? prev = previousDisposal == WebpDisposalMethod.RestoreToBackground ? null : previousFrame;
+ ImageFrame? prev = previousDisposal == FrameDisposalMode.RestoreToBackground ? null : previousFrame;
ImageFrame currentFrame = image.Frames[i];
ImageFrame? nextFrame = i < image.Frames.Count - 1 ? image.Frames[i + 1] : null;
- frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(currentFrame);
- bool blend = frameMetadata.BlendMethod == WebpBlendMethod.Over;
+ frameMetadata = currentFrame.Metadata.GetWebpMetadata();
+ bool blend = frameMetadata.BlendMethod == FrameBlendMode.Over;
(bool difference, Rectangle bounds) =
AnimationUtilities.DeDuplicatePixels(
@@ -227,8 +228,8 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals
// Encode the first frame.
ImageFrame previousFrame = image.Frames.RootFrame;
- WebpFrameMetadata frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(previousFrame);
- WebpDisposalMethod previousDisposal = frameMetadata.DisposalMethod;
+ WebpFrameMetadata frameMetadata = previousFrame.Metadata.GetWebpMetadata();
+ FrameDisposalMode previousDisposal = frameMetadata.DisposalMethod;
hasAlpha |= encoder.EncodeAnimation(previousFrame, stream, previousFrame.Bounds(), frameMetadata);
@@ -238,12 +239,12 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals
for (int i = 1; i < image.Frames.Count; i++)
{
- ImageFrame? prev = previousDisposal == WebpDisposalMethod.RestoreToBackground ? null : previousFrame;
+ ImageFrame? prev = previousDisposal == FrameDisposalMode.RestoreToBackground ? null : previousFrame;
ImageFrame currentFrame = image.Frames[i];
ImageFrame? nextFrame = i < image.Frames.Count - 1 ? image.Frames[i + 1] : null;
- frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(currentFrame);
- bool blend = frameMetadata.BlendMethod == WebpBlendMethod.Over;
+ frameMetadata = currentFrame.Metadata.GetWebpMetadata();
+ bool blend = frameMetadata.BlendMethod == FrameBlendMode.Over;
(bool difference, Rectangle bounds) =
AnimationUtilities.DeDuplicatePixels(
diff --git a/src/ImageSharp/Formats/Webp/WebpFileFormatType.cs b/src/ImageSharp/Formats/Webp/WebpFileFormatType.cs
index 1ed9bbb431..6f606cdf46 100644
--- a/src/ImageSharp/Formats/Webp/WebpFileFormatType.cs
+++ b/src/ImageSharp/Formats/Webp/WebpFileFormatType.cs
@@ -9,12 +9,12 @@ namespace SixLabors.ImageSharp.Formats.Webp;
public enum WebpFileFormatType
{
///
- /// The lossless webp format.
+ /// The lossless Webp format, which compresses data without any loss of information.
///
Lossless,
///
- /// The lossy webp format.
+ /// The lossy Webp format, which compresses data by discarding some of it.
///
Lossy,
}
diff --git a/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs b/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs
index cd1b5d5905..45e182d223 100644
--- a/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs
+++ b/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs
@@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Webp;
///
/// Provides webp specific metadata information for the image frame.
///
-public class WebpFrameMetadata : IDeepCloneable
+public class WebpFrameMetadata : IFormatFrameMetadata
{
///
/// Initializes a new instance of the class.
@@ -29,12 +29,12 @@ public class WebpFrameMetadata : IDeepCloneable
///
/// Gets or sets how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas.
///
- public WebpBlendMethod BlendMethod { get; set; }
+ public FrameBlendMode BlendMethod { get; set; }
///
/// Gets or sets how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas.
///
- public WebpDisposalMethod DisposalMethod { get; set; }
+ public FrameDisposalMode DisposalMethod { get; set; }
///
/// Gets or sets the frame duration. The time to wait before displaying the next frame,
@@ -43,13 +43,34 @@ public class WebpFrameMetadata : IDeepCloneable
public uint FrameDelay { get; set; }
///
- public IDeepCloneable DeepClone() => new WebpFrameMetadata(this);
-
- internal static WebpFrameMetadata FromAnimatedMetadata(AnimatedImageFrameMetadata metadata)
+ public static WebpFrameMetadata FromFormatConnectingFrameMetadata(FormatConnectingFrameMetadata metadata)
=> new()
{
FrameDelay = (uint)metadata.Duration.TotalMilliseconds,
- BlendMethod = metadata.BlendMode == FrameBlendMode.Source ? WebpBlendMethod.Source : WebpBlendMethod.Over,
- DisposalMethod = metadata.DisposalMode == FrameDisposalMode.RestoreToBackground ? WebpDisposalMethod.RestoreToBackground : WebpDisposalMethod.DoNotDispose
+ BlendMethod = metadata.BlendMode,
+ DisposalMethod = GetMode(metadata.DisposalMode)
+ };
+
+ ///
+ public FormatConnectingFrameMetadata ToFormatConnectingFrameMetadata()
+ => new()
+ {
+ ColorTableMode = FrameColorTableMode.Global,
+ Duration = TimeSpan.FromMilliseconds(this.FrameDelay),
+ DisposalMode = this.DisposalMethod,
+ BlendMode = this.BlendMethod,
};
+
+ ///
+ IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone();
+
+ ///
+ public WebpFrameMetadata DeepClone() => new(this);
+
+ private static FrameDisposalMode GetMode(FrameDisposalMode mode) => mode switch
+ {
+ FrameDisposalMode.RestoreToBackground => FrameDisposalMode.RestoreToBackground,
+ FrameDisposalMode.DoNotDispose => FrameDisposalMode.DoNotDispose,
+ _ => FrameDisposalMode.DoNotDispose,
+ };
}
diff --git a/src/ImageSharp/Formats/Webp/WebpMetadata.cs b/src/ImageSharp/Formats/Webp/WebpMetadata.cs
index a42435fd4a..33ebbbf6dc 100644
--- a/src/ImageSharp/Formats/Webp/WebpMetadata.cs
+++ b/src/ImageSharp/Formats/Webp/WebpMetadata.cs
@@ -54,24 +54,16 @@ public class WebpMetadata : IFormatMetadata
/// Gets or sets the default background color of the canvas when animating.
/// This color may be used to fill the unused space on the canvas around the frames,
/// as well as the transparent pixels of the first frame.
- /// The background color is also used when the Disposal method is .
+ /// The background color is also used when the Disposal method is .
///
public Color BackgroundColor { get; set; }
- internal static WebpMetadata FromAnimatedMetadata(AnimatedImageMetadata metadata)
- => new()
- {
- FileFormat = WebpFileFormatType.Lossless,
- BackgroundColor = metadata.BackgroundColor,
- RepeatCount = metadata.RepeatCount
- };
-
///
public static WebpMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata)
{
WebpBitsPerPixel bitsPerPixel;
WebpColorType color;
- PixelColorType colorType = metadata.PixelTypeInfo.ColorType ?? PixelColorType.RGB | PixelColorType.Alpha;
+ PixelColorType colorType = metadata.PixelTypeInfo.ColorType;
switch (colorType)
{
case PixelColorType.RGB:
@@ -100,9 +92,9 @@ public class WebpMetadata : IFormatMetadata
{
BitsPerPixel = bitsPerPixel,
ColorType = color,
- FileFormat = WebpFileFormatType.Lossless,
BackgroundColor = metadata.BackgroundColor,
- RepeatCount = metadata.RepeatCount
+ RepeatCount = metadata.RepeatCount,
+ FileFormat = metadata.EncodingType == EncodingType.Lossless ? WebpFileFormatType.Lossless : WebpFileFormatType.Lossy
};
}
@@ -146,6 +138,7 @@ public class WebpMetadata : IFormatMetadata
public FormatConnectingMetadata ToFormatConnectingMetadata()
=> new()
{
+ EncodingType = this.FileFormat == WebpFileFormatType.Lossless ? EncodingType.Lossless : EncodingType.Lossy,
PixelTypeInfo = this.GetPixelTypeInfo(),
ColorTableMode = FrameColorTableMode.Global,
RepeatCount = this.RepeatCount,
diff --git a/src/ImageSharp/Formats/ImageExtensions.Save.cs b/src/ImageSharp/Formats/_Generated/ImageExtensions.Save.cs
similarity index 99%
rename from src/ImageSharp/Formats/ImageExtensions.Save.cs
rename to src/ImageSharp/Formats/_Generated/ImageExtensions.Save.cs
index 7e5989d6fc..5d7f84acfb 100644
--- a/src/ImageSharp/Formats/ImageExtensions.Save.cs
+++ b/src/ImageSharp/Formats/_Generated/ImageExtensions.Save.cs
@@ -2,8 +2,6 @@
// Licensed under the Six Labors Split License.
//
-using SixLabors.ImageSharp.Advanced;
-
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
diff --git a/src/ImageSharp/Formats/ImageExtensions.Save.tt b/src/ImageSharp/Formats/_Generated/ImageExtensions.Save.tt
similarity index 95%
rename from src/ImageSharp/Formats/ImageExtensions.Save.tt
rename to src/ImageSharp/Formats/_Generated/ImageExtensions.Save.tt
index d4f1ed233b..144dd83625 100644
--- a/src/ImageSharp/Formats/ImageExtensions.Save.tt
+++ b/src/ImageSharp/Formats/_Generated/ImageExtensions.Save.tt
@@ -1,25 +1,8 @@
-<#@ template language="C#" #>
+<#@include file="_Formats.ttinclude" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
-// Copyright (c) Six Labors.
-// Licensed under the Six Labors Split License.
-
//
-using SixLabors.ImageSharp.Advanced;
-
<#
- var formats = new []{
- "Bmp",
- "Gif",
- "Jpeg",
- "Pbm",
- "Png",
- "Qoi",
- "Tga",
- "Tiff",
- "Webp",
- };
-
foreach (string fmt in formats)
{
#>
diff --git a/src/ImageSharp/Formats/_Generated/ImageMetadataExtensions.cs b/src/ImageSharp/Formats/_Generated/ImageMetadataExtensions.cs
new file mode 100644
index 0000000000..826f5905b1
--- /dev/null
+++ b/src/ImageSharp/Formats/_Generated/ImageMetadataExtensions.cs
@@ -0,0 +1,283 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+//
+using SixLabors.ImageSharp.Metadata;
+using SixLabors.ImageSharp.Formats.Bmp;
+using SixLabors.ImageSharp.Formats.Gif;
+using SixLabors.ImageSharp.Formats.Jpeg;
+using SixLabors.ImageSharp.Formats.Pbm;
+using SixLabors.ImageSharp.Formats.Png;
+using SixLabors.ImageSharp.Formats.Qoi;
+using SixLabors.ImageSharp.Formats.Tga;
+using SixLabors.ImageSharp.Formats.Tiff;
+using SixLabors.ImageSharp.Formats.Webp;
+
+namespace SixLabors.ImageSharp;
+
+///
+/// Extension methods for the and types.
+///
+public static class ImageMetadataExtensions
+{
+ ///
+ /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata
+ /// or the requested format default constructor.
+ /// This instance will be added to the metadata for future requests.
+ ///
+ /// The image metadata.
+ ///
+ /// The
+ ///
+ public static BmpMetadata GetBmpMetadata(this ImageMetadata source) => source.GetFormatMetadata(BmpFormat.Instance);
+
+ ///
+ /// Creates a new cloned instance of from the .
+ /// The instance is created via
+ ///
+ /// The image metadata.
+ /// The new
+ public static BmpMetadata CloneBmpMetadata(this ImageMetadata source) => source.CloneFormatMetadata(BmpFormat.Instance);
+
+ ///
+ /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata
+ /// or the requested format default constructor.
+ /// This instance will be added to the metadata for future requests.
+ ///
+ /// The image metadata.
+ ///
+ /// The
+ ///
+ public static GifMetadata GetGifMetadata(this ImageMetadata source) => source.GetFormatMetadata(GifFormat.Instance);
+
+ ///
+ /// Creates a new cloned instance of from the .
+ /// The instance is created via
+ ///
+ /// The image metadata.
+ /// The new
+ public static GifMetadata CloneGifMetadata(this ImageMetadata source) => source.CloneFormatMetadata(GifFormat.Instance);
+
+ ///
+ /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata
+ /// or the requested format default constructor.
+ /// This instance will be added to the metadata for future requests.
+ ///
+ /// The image metadata.
+ ///
+ /// The
+ ///
+ public static JpegMetadata GetJpegMetadata(this ImageMetadata source) => source.GetFormatMetadata(JpegFormat.Instance);
+
+ ///
+ /// Creates a new cloned instance of from the .
+ /// The instance is created via
+ ///
+ /// The image metadata.
+ /// The new
+ public static JpegMetadata CloneJpegMetadata(this ImageMetadata source) => source.CloneFormatMetadata(JpegFormat.Instance);
+
+ ///
+ /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata
+ /// or the requested format default constructor.
+ /// This instance will be added to the metadata for future requests.
+ ///
+ /// The image metadata.
+ ///
+ /// The
+ ///
+ public static PbmMetadata GetPbmMetadata(this ImageMetadata source) => source.GetFormatMetadata(PbmFormat.Instance);
+
+ ///
+ /// Creates a new cloned instance of from the .
+ /// The instance is created via
+ ///
+ /// The image metadata.
+ /// The new
+ public static PbmMetadata ClonePbmMetadata(this ImageMetadata source) => source.CloneFormatMetadata(PbmFormat.Instance);
+
+ ///
+ /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata
+ /// or the requested format default constructor.
+ /// This instance will be added to the metadata for future requests.
+ ///
+ /// The image metadata.
+ ///
+ /// The
+ ///
+ public static PngMetadata GetPngMetadata(this ImageMetadata source) => source.GetFormatMetadata(PngFormat.Instance);
+
+ ///
+ /// Creates a new cloned instance of from the .
+ /// The instance is created via
+ ///
+ /// The image metadata.
+ /// The new
+ public static PngMetadata ClonePngMetadata(this ImageMetadata source) => source.CloneFormatMetadata(PngFormat.Instance);
+
+ ///
+ /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata
+ /// or the requested format default constructor.
+ /// This instance will be added to the metadata for future requests.
+ ///
+ /// The image metadata.
+ ///
+ /// The
+ ///
+ public static QoiMetadata GetQoiMetadata(this ImageMetadata source) => source.GetFormatMetadata(QoiFormat.Instance);
+
+ ///
+ /// Creates a new cloned instance of from the .
+ /// The instance is created via
+ ///
+ /// The image metadata.
+ /// The new
+ public static QoiMetadata CloneQoiMetadata(this ImageMetadata source) => source.CloneFormatMetadata(QoiFormat.Instance);
+
+ ///
+ /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata
+ /// or the requested format default constructor.
+ /// This instance will be added to the metadata for future requests.
+ ///
+ /// The image metadata.
+ ///
+ /// The
+ ///
+ public static TgaMetadata GetTgaMetadata(this ImageMetadata source) => source.GetFormatMetadata(TgaFormat.Instance);
+
+ ///
+ /// Creates a new cloned instance of from the .
+ /// The instance is created via
+ ///
+ /// The image metadata.
+ /// The new
+ public static TgaMetadata CloneTgaMetadata(this ImageMetadata source) => source.CloneFormatMetadata(TgaFormat.Instance);
+
+ ///
+ /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata
+ /// or the requested format default constructor.
+ /// This instance will be added to the metadata for future requests.
+ ///
+ /// The image metadata.
+ ///
+ /// The
+ ///
+ public static TiffMetadata GetTiffMetadata(this ImageMetadata source) => source.GetFormatMetadata(TiffFormat.Instance);
+
+ ///
+ /// Creates a new cloned instance of from the .
+ /// The instance is created via
+ ///
+ /// The image metadata.
+ /// The new
+ public static TiffMetadata CloneTiffMetadata(this ImageMetadata source) => source.CloneFormatMetadata(TiffFormat.Instance);
+
+ ///
+ /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata
+ /// or the requested format default constructor.
+ /// This instance will be added to the metadata for future requests.
+ ///
+ /// The image metadata.
+ ///
+ /// The
+ ///
+ public static WebpMetadata GetWebpMetadata(this ImageMetadata source) => source.GetFormatMetadata(WebpFormat.Instance);
+
+ ///
+ /// Creates a new cloned instance of from the .
+ /// The instance is created via
+ ///
+ /// The image metadata.
+ /// The new
+ public static WebpMetadata CloneWebpMetadata(this ImageMetadata source) => source.CloneFormatMetadata(WebpFormat.Instance);
+
+
+ ///
+ /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata
+ /// or the requested format default constructor.
+ /// This instance will be added to the metadata for future requests.
+ ///
+ /// The image frame metadata.
+ ///
+ /// The
+ ///
+ public static GifFrameMetadata GetGifMetadata(this ImageFrameMetadata source) => source.GetFormatMetadata(GifFormat.Instance);
+
+ ///
+ /// Creates a new cloned instance of from the .
+ /// The instance is created via
+ ///
+ /// The image frame metadata.
+ /// The new
+ public static GifFrameMetadata CloneGifMetadata(this ImageFrameMetadata source) => source.CloneFormatMetadata(GifFormat.Instance);
+
+ ///
+ /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata
+ /// or the requested format default constructor.
+ /// This instance will be added to the metadata for future requests.
+ ///
+ /// The image frame metadata.
+ ///
+ /// The
+ ///
+ public static PngFrameMetadata GetPngMetadata(this ImageFrameMetadata source) => source.GetFormatMetadata(PngFormat.Instance);
+
+ ///
+ /// Creates a new cloned instance of from the .
+ /// The instance is created via
+ ///
+ /// The image frame metadata.
+ /// The new
+ public static PngFrameMetadata ClonePngMetadata(this ImageFrameMetadata source) => source.CloneFormatMetadata(PngFormat.Instance);
+
+ ///
+ /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata
+ /// or the requested format default constructor.
+ /// This instance will be added to the metadata for future requests.
+ ///
+ /// The image frame metadata.
+ ///
+ /// The
+ ///
+ public static TiffFrameMetadata GetTiffMetadata(this ImageFrameMetadata source) => source.GetFormatMetadata(TiffFormat.Instance);
+
+ ///
+ /// Creates a new cloned instance of from the .
+ /// The instance is created via
+ ///
+ /// The image frame metadata.
+ /// The new
+ public static TiffFrameMetadata CloneTiffMetadata(this ImageFrameMetadata source) => source.CloneFormatMetadata(TiffFormat.Instance);
+
+ ///
+ /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata
+ /// or the requested format default constructor.
+ /// This instance will be added to the metadata for future requests.
+ ///
+ /// The image frame metadata.
+ ///
+ /// The
+ ///
+ public static WebpFrameMetadata GetWebpMetadata(this ImageFrameMetadata source) => source.GetFormatMetadata(WebpFormat.Instance);
+
+ ///
+ /// Creates a new cloned instance of from the .
+ /// The instance is created via
+ ///
+ /// The image frame metadata.
+ /// The new
+ public static WebpFrameMetadata CloneWebpMetadata(this ImageFrameMetadata source) => source.CloneFormatMetadata(WebpFormat.Instance);
+}
diff --git a/src/ImageSharp/Formats/_Generated/ImageMetadataExtensions.tt b/src/ImageSharp/Formats/_Generated/ImageMetadataExtensions.tt
new file mode 100644
index 0000000000..e4db85ed59
--- /dev/null
+++ b/src/ImageSharp/Formats/_Generated/ImageMetadataExtensions.tt
@@ -0,0 +1,77 @@
+<#@include file="_Formats.ttinclude" #>
+<#@ import namespace="System.Text" #>
+<#@ import namespace="System.Collections.Generic" #>
+//
+using SixLabors.ImageSharp.Metadata;
+<#
+ foreach (string fmt in formats)
+ {
+#>
+using SixLabors.ImageSharp.Formats.<#= fmt #>;
+<#
+
+ }
+#>
+
+namespace SixLabors.ImageSharp;
+
+///
+/// Extension methods for the and types.
+///
+public static class ImageMetadataExtensions
+{
+<#
+ foreach (string fmt in formats)
+ {
+#>
+ ///
+ /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata
+ /// or the requested format default constructor.
+ /// This instance will be added to the metadata for future requests.
+ ///
+ /// The image metadata.
+ ///
+ /// The
+ ///
+ public static <#= fmt #>Metadata Get<#= fmt #>Metadata(this ImageMetadata source) => source.GetFormatMetadata(<#= fmt #>Format.Instance);
+
+ ///
+ /// Creates a new cloned instance of from the .
+ /// The instance is created via
+ ///
+ /// The image metadata.
+ /// The new
+ public static <#= fmt #>Metadata Clone<#= fmt #>Metadata(this ImageMetadata source) => source.CloneFormatMetadata(<#= fmt #>Format.Instance);
+
+<#
+ }
+#>
+<#
+ foreach (string fmt in frameFormats)
+ {
+#>
+
+ ///
+ /// Gets the from .
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata
+ /// or the requested format default constructor.
+ /// This instance will be added to the metadata for future requests.
+ ///
+ /// The image frame metadata.
+ ///
+ /// The
+ ///
+ public static <#= fmt #>FrameMetadata Get<#= fmt #>Metadata(this ImageFrameMetadata source) => source.GetFormatMetadata(<#= fmt #>Format.Instance);
+
+ ///
+ /// Creates a new cloned instance of from the .
+ /// The instance is created via
+ ///
+ /// The image frame metadata.
+ /// The new
+ public static <#= fmt #>FrameMetadata Clone<#= fmt #>Metadata(this ImageFrameMetadata source) => source.CloneFormatMetadata(<#= fmt #>Format.Instance);
+<#
+ }
+#>
+}
diff --git a/src/ImageSharp/Formats/_Generated/_Formats.ttinclude b/src/ImageSharp/Formats/_Generated/_Formats.ttinclude
new file mode 100644
index 0000000000..24ac66a70b
--- /dev/null
+++ b/src/ImageSharp/Formats/_Generated/_Formats.ttinclude
@@ -0,0 +1,24 @@
+<#@ template debug="false" hostspecific="false" language="C#" #>
+<#@ assembly name="System.Core" #>
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+<#+
+ private static readonly string[] formats = new []{
+ "Bmp",
+ "Gif",
+ "Jpeg",
+ "Pbm",
+ "Png",
+ "Qoi",
+ "Tga",
+ "Tiff",
+ "Webp",
+ };
+
+ private static readonly string[] frameFormats = new []{
+ "Gif",
+ "Png",
+ "Tiff",
+ "Webp",
+ };
+#>
diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj
index 6096bd33e3..d3c4034717 100644
--- a/src/ImageSharp/ImageSharp.csproj
+++ b/src/ImageSharp/ImageSharp.csproj
@@ -52,6 +52,11 @@
+
+ True
+ True
+ ImageMetadataExtensions.tt
+
True
True
@@ -142,7 +147,7 @@
True
PorterDuffFunctions.Generated.tt
-
+
True
True
ImageExtensions.Save.tt
@@ -150,6 +155,10 @@
+
+ ImageMetadataExtensions.cs
+ TextTemplatingFileGenerator
+
TextTemplatingFileGenerator
Block8x8F.Generated.cs
@@ -222,7 +231,7 @@
DefaultPixelBlenders.Generated.cs
TextTemplatingFileGenerator
-
+
TextTemplatingFileGenerator
ImageExtensions.Save.cs
diff --git a/src/ImageSharp/Metadata/ImageFrameMetadata.cs b/src/ImageSharp/Metadata/ImageFrameMetadata.cs
index 1c0330d5d0..afda71879f 100644
--- a/src/ImageSharp/Metadata/ImageFrameMetadata.cs
+++ b/src/ImageSharp/Metadata/ImageFrameMetadata.cs
@@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Metadata;
///
public sealed class ImageFrameMetadata : IDeepCloneable
{
- private readonly Dictionary formatMetadata = new();
+ private readonly Dictionary formatMetadata = [];
///
/// Initializes a new instance of the class.
@@ -35,9 +35,9 @@ public sealed class ImageFrameMetadata : IDeepCloneable
{
DebugGuard.NotNull(other, nameof(other));
- foreach (KeyValuePair meta in other.formatMetadata)
+ foreach (KeyValuePair meta in other.formatMetadata)
{
- this.formatMetadata.Add(meta.Key, meta.Value.DeepClone());
+ this.formatMetadata.Add(meta.Key, (IFormatFrameMetadata)meta.Value.DeepClone());
}
this.ExifProfile = other.ExifProfile?.DeepClone();
@@ -45,6 +45,10 @@ public sealed class ImageFrameMetadata : IDeepCloneable
this.IptcProfile = other.IptcProfile?.DeepClone();
this.XmpProfile = other.XmpProfile?.DeepClone();
this.CicpProfile = other.CicpProfile?.DeepClone();
+
+ // NOTE: This clone is actually shallow but we share the same format
+ // instances for all images in the configuration.
+ this.DecodedImageFormat = other.DecodedImageFormat;
}
///
@@ -72,12 +76,19 @@ public sealed class ImageFrameMetadata : IDeepCloneable
///
public CicpProfile? CicpProfile { get; set; }
+ ///
+ /// Gets the original format, if any, the image was decode from.
+ ///
+ public IImageFormat? DecodedImageFormat { get; internal set; }
+
///
public ImageFrameMetadata DeepClone() => new(this);
///
- /// Gets the metadata value associated with the specified key. This method will always return a result creating
- /// a new instance and binding it to the frame metadata if none is found.
+ /// Gets the metadata value associated with the specified key.
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata
+ /// or the requested format default constructor.
+ /// This instance will be added to the metadata for future requests.
///
/// The type of format metadata.
/// The type of format frame metadata.
@@ -87,43 +98,37 @@ public sealed class ImageFrameMetadata : IDeepCloneable
///
public TFormatFrameMetadata GetFormatMetadata(IImageFormat key)
where TFormatMetadata : class
- where TFormatFrameMetadata : class, IDeepCloneable
+ where TFormatFrameMetadata : class, IFormatFrameMetadata
{
- if (this.formatMetadata.TryGetValue(key, out IDeepCloneable? meta))
+ if (this.formatMetadata.TryGetValue(key, out IFormatFrameMetadata? meta))
{
return (TFormatFrameMetadata)meta;
}
+ // None found. Check if we have a decoded format to convert from.
+ if (this.DecodedImageFormat is not null
+ && this.formatMetadata.TryGetValue(this.DecodedImageFormat, out IFormatFrameMetadata? decodedMetadata))
+ {
+ return TFormatFrameMetadata.FromFormatConnectingFrameMetadata(decodedMetadata.ToFormatConnectingFrameMetadata());
+ }
+
TFormatFrameMetadata newMeta = key.CreateDefaultFormatFrameMetadata();
this.formatMetadata[key] = newMeta;
return newMeta;
}
///
- /// Gets the metadata value associated with the specified key.
+ /// Creates a new instance the metadata value associated with the specified key.
+ /// The instance is created from a clone generated via .
///
- /// The type of format metadata.
+ /// The type of metadata.
/// The type of format frame metadata.
/// The key of the value to get.
- ///
- /// When this method returns, contains the metadata associated with the specified key,
- /// if the key is found; otherwise, the default value for the type of the metadata parameter.
- /// This parameter is passed uninitialized.
- ///
///
- /// if the frame metadata exists for the specified key; otherwise, .
+ /// The .
///
- public bool TryGetFormatMetadata(IImageFormat key, out TFormatFrameMetadata? metadata)
+ public TFormatFrameMetadata CloneFormatMetadata(IImageFormat key)
where TFormatMetadata : class
- where TFormatFrameMetadata : class, IDeepCloneable
- {
- if (this.formatMetadata.TryGetValue(key, out IDeepCloneable? meta))
- {
- metadata = (TFormatFrameMetadata)meta;
- return true;
- }
-
- metadata = default;
- return false;
- }
+ where TFormatFrameMetadata : class, IFormatFrameMetadata
+ => ((IDeepCloneable)this.GetFormatMetadata(key)).DeepClone();
}
diff --git a/src/ImageSharp/Metadata/ImageMetadata.cs b/src/ImageSharp/Metadata/ImageMetadata.cs
index ceeea42cfc..b521f8eeed 100644
--- a/src/ImageSharp/Metadata/ImageMetadata.cs
+++ b/src/ImageSharp/Metadata/ImageMetadata.cs
@@ -33,7 +33,7 @@ public sealed class ImageMetadata : IDeepCloneable
///
public const PixelResolutionUnit DefaultPixelResolutionUnits = PixelResolutionUnit.PixelsPerInch;
- private readonly Dictionary formatMetadata = [];
+ private readonly Dictionary formatMetadata = [];
private double horizontalResolution;
private double verticalResolution;
@@ -60,9 +60,9 @@ public sealed class ImageMetadata : IDeepCloneable
this.VerticalResolution = other.VerticalResolution;
this.ResolutionUnits = other.ResolutionUnits;
- foreach (KeyValuePair meta in other.formatMetadata)
+ foreach (KeyValuePair meta in other.formatMetadata)
{
- this.formatMetadata.Add(meta.Key, meta.Value.DeepClone());
+ this.formatMetadata.Add(meta.Key, (IFormatMetadata)meta.Value.DeepClone());
}
this.ExifProfile = other.ExifProfile?.DeepClone();
@@ -170,7 +170,10 @@ public sealed class ImageMetadata : IDeepCloneable
public IImageFormat? DecodedImageFormat { get; internal set; }
///
- /// Gets the metadata value associated with the specified key.
+ /// Gets the metadata value associated with the specified key.
+ /// If none is found, an instance is created either by conversion from the decoded image format metadata
+ /// or the requested format default constructor.
+ /// This instance will be added to the metadata for future requests.
///
/// The type of metadata.
/// The key of the value to get.
@@ -178,47 +181,44 @@ public sealed class ImageMetadata : IDeepCloneable
/// The .
///
public TFormatMetadata GetFormatMetadata(IImageFormat key)
- where TFormatMetadata : class, IDeepCloneable
+ where TFormatMetadata : class, IFormatMetadata
{
- if (this.formatMetadata.TryGetValue(key, out IDeepCloneable? meta))
+ // Check for existing metadata.
+ if (this.formatMetadata.TryGetValue(key, out IFormatMetadata? meta))
{
return (TFormatMetadata)meta;
}
+ // None found. Check if we have a decoded format to convert from.
+ if (this.DecodedImageFormat is not null
+ && this.formatMetadata.TryGetValue(this.DecodedImageFormat, out IFormatMetadata? decodedMetadata))
+ {
+ return TFormatMetadata.FromFormatConnectingMetadata(decodedMetadata.ToFormatConnectingMetadata());
+ }
+
+ // Fall back to a default instance.
TFormatMetadata newMeta = key.CreateDefaultFormatMetadata();
this.formatMetadata[key] = newMeta;
return newMeta;
}
///
- /// Gets the metadata value associated with the specified key.
+ /// Creates a new instance the metadata value associated with the specified key.
+ /// The instance is created from a clone generated via .
///
- /// The type of format metadata.
+ /// The type of metadata.
/// The key of the value to get.
- ///
- /// When this method returns, contains the metadata associated with the specified key,
- /// if the key is found; otherwise, the default value for the type of the metadata parameter.
- /// This parameter is passed uninitialized.
- ///
///
- /// if the frame metadata exists for the specified key; otherwise, .
+ /// The .
///
- public bool TryGetFormatMetadata(IImageFormat key, out TFormatMetadata? metadata)
- where TFormatMetadata : class, IDeepCloneable
- {
- if (this.formatMetadata.TryGetValue(key, out IDeepCloneable? meta))
- {
- metadata = (TFormatMetadata)meta;
- return true;
- }
-
- metadata = default;
- return false;
- }
+ public TFormatMetadata CloneFormatMetadata(IImageFormat key)
+ where TFormatMetadata : class, IFormatMetadata, new()
+ => ((IDeepCloneable)this.GetFormatMetadata(key)).DeepClone();
///
public ImageMetadata DeepClone() => new(this);
+ /// TODO: This should be called on save.
///
/// Synchronizes the profiles with the current metadata.
///
diff --git a/src/ImageSharp/PixelFormats/PixelTypeInfo.cs b/src/ImageSharp/PixelFormats/PixelTypeInfo.cs
index 7cd1284f48..7865b9900e 100644
--- a/src/ImageSharp/PixelFormats/PixelTypeInfo.cs
+++ b/src/ImageSharp/PixelFormats/PixelTypeInfo.cs
@@ -31,13 +31,13 @@ public readonly struct PixelTypeInfo(int bitsPerPixel)
///
/// Gets the pixel color type.
///
- public PixelColorType? ColorType { get; init; }
+ public PixelColorType ColorType { get; init; }
///
/// Gets the pixel alpha transparency behavior.
/// means unknown, unspecified.
///
- public PixelAlphaRepresentation? AlphaRepresentation { get; init; }
+ public PixelAlphaRepresentation AlphaRepresentation { get; init; }
///
/// Creates a new instance.
diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs
index f7a398ec14..64564ae1d8 100644
--- a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs
@@ -16,7 +16,7 @@ public class BmpMetadataTests
{
BmpMetadata meta = new()
{ BitsPerPixel = BmpBitsPerPixel.Bit24, InfoHeaderType = BmpInfoHeaderType.Os2Version2 };
- BmpMetadata clone = (BmpMetadata)meta.DeepClone();
+ BmpMetadata clone = meta.DeepClone();
clone.BitsPerPixel = BmpBitsPerPixel.Bit32;
clone.InfoHeaderType = BmpInfoHeaderType.WinVersion2;
diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs
index aeb3bab7bb..77ac51e8a1 100644
--- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs
@@ -242,33 +242,11 @@ public class GifEncoderTests
where TPixel : unmanaged, IPixel
{
using Image image = provider.GetImage();
-
- int count = 0;
- foreach (ImageFrame frame in image.Frames)
- {
- if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata _))
- {
- count++;
- }
- }
-
provider.Utility.SaveTestOutputFile(image, extension: "gif");
using FileStream fs = File.OpenRead(provider.Utility.GetTestOutputFileName("gif"));
using Image image2 = Image.Load(fs);
-
Assert.Equal(image.Frames.Count, image2.Frames.Count);
-
- count = 0;
- foreach (ImageFrame frame in image2.Frames)
- {
- if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata _))
- {
- count++;
- }
- }
-
- Assert.Equal(image2.Frames.Count, count);
}
[Theory]
@@ -358,10 +336,10 @@ public class GifEncoderTests
switch (webpF.DisposalMethod)
{
- case WebpDisposalMethod.RestoreToBackground:
+ case FrameDisposalMode.RestoreToBackground:
Assert.Equal(FrameDisposalMode.RestoreToBackground, gifF.DisposalMode);
break;
- case WebpDisposalMethod.DoNotDispose:
+ case FrameDisposalMode.DoNotDispose:
default:
Assert.Equal(FrameDisposalMode.DoNotDispose, gifF.DisposalMode);
break;
diff --git a/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs
index a69d9d9ba7..243a62d592 100644
--- a/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Pbm/PbmMetadataTests.cs
@@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Pbm;
using static SixLabors.ImageSharp.Tests.TestImages.Pbm;
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
index f40e537a15..009327c17f 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs
@@ -526,10 +526,10 @@ public partial class PngEncoderTests
switch (webpF.BlendMethod)
{
- case WebpBlendMethod.Source:
+ case FrameBlendMode.Source:
Assert.Equal(FrameBlendMode.Source, pngF.BlendMode);
break;
- case WebpBlendMethod.Over:
+ case FrameBlendMode.Over:
default:
Assert.Equal(FrameBlendMode.Over, pngF.BlendMode);
break;
@@ -537,10 +537,10 @@ public partial class PngEncoderTests
switch (webpF.DisposalMethod)
{
- case WebpDisposalMethod.RestoreToBackground:
+ case FrameDisposalMode.RestoreToBackground:
Assert.Equal(FrameDisposalMode.RestoreToBackground, pngF.DisposalMode);
break;
- case WebpDisposalMethod.DoNotDispose:
+ case FrameDisposalMode.DoNotDispose:
default:
Assert.Equal(FrameDisposalMode.DoNotDispose, pngF.DisposalMode);
break;
diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs
index 4d72363075..aff1b35946 100644
--- a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs
@@ -98,13 +98,13 @@ public class WebpEncoderTests
switch (gifF.DisposalMode)
{
case FrameDisposalMode.RestoreToBackground:
- Assert.Equal(WebpDisposalMethod.RestoreToBackground, webpF.DisposalMethod);
+ Assert.Equal(FrameDisposalMode.RestoreToBackground, webpF.DisposalMethod);
break;
case FrameDisposalMode.RestoreToPrevious:
case FrameDisposalMode.Unspecified:
case FrameDisposalMode.DoNotDispose:
default:
- Assert.Equal(WebpDisposalMethod.DoNotDispose, webpF.DisposalMethod);
+ Assert.Equal(FrameDisposalMode.DoNotDispose, webpF.DisposalMethod);
break;
}
}
@@ -147,22 +147,22 @@ public class WebpEncoderTests
switch (pngF.BlendMode)
{
case FrameBlendMode.Source:
- Assert.Equal(WebpBlendMethod.Source, webpF.BlendMethod);
+ Assert.Equal(FrameBlendMode.Source, webpF.BlendMethod);
break;
case FrameBlendMode.Over:
default:
- Assert.Equal(WebpBlendMethod.Over, webpF.BlendMethod);
+ Assert.Equal(FrameBlendMode.Over, webpF.BlendMethod);
break;
}
switch (pngF.DisposalMode)
{
case FrameDisposalMode.RestoreToBackground:
- Assert.Equal(WebpDisposalMethod.RestoreToBackground, webpF.DisposalMethod);
+ Assert.Equal(FrameDisposalMode.RestoreToBackground, webpF.DisposalMethod);
break;
case FrameDisposalMode.DoNotDispose:
default:
- Assert.Equal(WebpDisposalMethod.DoNotDispose, webpF.DisposalMethod);
+ Assert.Equal(FrameDisposalMode.DoNotDispose, webpF.DisposalMethod);
break;
}
}
@@ -220,7 +220,7 @@ public class WebpEncoderTests
};
using Image image = provider.GetImage();
- string testOutputDetails = string.Concat("lossless", "_q", quality);
+ string testOutputDetails = $"lossless_q{quality}";
image.VerifyEncoder(provider, "webp", testOutputDetails, encoder);
}
@@ -250,7 +250,7 @@ public class WebpEncoderTests
};
using Image image = provider.GetImage();
- string testOutputDetails = string.Concat("lossless", "_m", method, "_q", quality);
+ string testOutputDetails = $"lossless_m{method}_q{quality}";
image.VerifyEncoder(provider, "webp", testOutputDetails, encoder);
}
@@ -290,7 +290,7 @@ public class WebpEncoderTests
};
using Image image = provider.GetImage();
- string testOutputDetails = string.Concat("nearlossless", "_q", nearLosslessQuality);
+ string testOutputDetails = $"nearlossless_q{nearLosslessQuality}";
image.VerifyEncoder(provider, "webp", testOutputDetails, encoder, customComparer: GetComparer(nearLosslessQuality));
}
@@ -314,7 +314,7 @@ public class WebpEncoderTests
};
using Image image = provider.GetImage();
- string testOutputDetails = string.Concat("lossless", "_m", method);
+ string testOutputDetails = $"lossless_m{method}";
image.VerifyEncoder(provider, "webp", testOutputDetails, encoder);
}
@@ -344,7 +344,7 @@ public class WebpEncoderTests
};
using Image image = provider.GetImage();
- string testOutputDetails = string.Concat("lossy", "_q", quality);
+ string testOutputDetails = $"lossy_q{quality}";
image.VerifyEncoder(provider, "webp", testOutputDetails, encoder, customComparer: GetComparer(quality));
}
@@ -364,7 +364,7 @@ public class WebpEncoderTests
};
using Image image = provider.GetImage();
- string testOutputDetails = string.Concat("lossy", "_f", filterStrength);
+ string testOutputDetails = $"lossy_f{filterStrength}";
image.VerifyEncoder(provider, "webp", testOutputDetails, encoder, customComparer: GetComparer(75));
}
@@ -384,7 +384,7 @@ public class WebpEncoderTests
};
using Image image = provider.GetImage();
- string testOutputDetails = string.Concat("lossy", "_sns", snsStrength);
+ string testOutputDetails = $"lossy_sns{snsStrength}";
image.VerifyEncoder(provider, "webp", testOutputDetails, encoder, customComparer: GetComparer(75));
}
@@ -414,7 +414,7 @@ public class WebpEncoderTests
};
using Image image = provider.GetImage();
- string testOutputDetails = string.Concat("lossy", "_m", method, "_q", quality);
+ string testOutputDetails = $"lossy_m{method}_q{quality}";
image.VerifyEncoder(provider, "webp", testOutputDetails, encoder, customComparer: GetComparer(quality));
}