Skip to content

Improve Decoder/Encoder symmetry #2276

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 56 commits into from
Dec 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
19bdecc
Replace IImageDecoder
JimBobSquarePants Oct 28, 2022
31def5c
Replace IImageEncoder
JimBobSquarePants Oct 28, 2022
5726089
Make decoder options init only (except Configuration cos tests)
JimBobSquarePants Oct 28, 2022
7d5c05b
Delete ImageTests.ImageLoadTestBase.Fakes.cs
JimBobSquarePants Oct 28, 2022
93a1700
Use new not shared options.
JimBobSquarePants Oct 29, 2022
391442b
Merge branch 'main' into js/decoder-attempt-2
JimBobSquarePants Nov 9, 2022
5669626
Merge branch 'main' into js/decoder-attempt-2
JimBobSquarePants Nov 15, 2022
1d99413
Re-introduce IImageDecoder and split decoding pipelines.
JimBobSquarePants Nov 15, 2022
c550af8
Re-introduce IImageEncoder and split encoding pipelines.
JimBobSquarePants Nov 15, 2022
b1db34d
Rename base encoder
JimBobSquarePants Nov 15, 2022
dd88269
Stub code to prevent unnecessary stream copying on decode.
JimBobSquarePants Nov 15, 2022
b98e1df
Update AotCompilerTools.cs
JimBobSquarePants Nov 15, 2022
1dc7bbf
Update SpecializedImageDecoder{T}.cs
JimBobSquarePants Nov 15, 2022
afa204b
Use ScaleToTargetSize
JimBobSquarePants Nov 20, 2022
2721ad5
Enable optimization.
JimBobSquarePants Nov 20, 2022
0dc9949
Rename and move configuration module.
JimBobSquarePants Nov 20, 2022
b32755d
Merge branch 'main' into js/decoder-attempt-2
JimBobSquarePants Nov 21, 2022
32965d3
Simplify position checks.
JimBobSquarePants Nov 22, 2022
8fdd6b0
Use default cancellation token
JimBobSquarePants Nov 22, 2022
6978235
Feedback
JimBobSquarePants Nov 25, 2022
28243df
Better tests for stream synchronization
JimBobSquarePants Nov 25, 2022
4891dc3
Use real cancellation handling.
JimBobSquarePants Nov 25, 2022
47f1cda
Rename method
JimBobSquarePants Nov 27, 2022
4a613b6
Update src/ImageSharp/IO/BufferedReadStream.cs
JimBobSquarePants Nov 27, 2022
d8c8244
Merge branch 'js/decoder-attempt-2' of https://github.com/SixLabors/I…
JimBobSquarePants Nov 27, 2022
00ca204
re-create add original DecodeAsync_IsCancellable test
antonfirsov Dec 4, 2022
3a7c4f4
fix Decode_Cancellation tests
antonfirsov Dec 4, 2022
447cd85
enough to test this for one format in ImageTests
antonfirsov Dec 4, 2022
937e78c
cover JpegDecoder's own cancellation support
antonfirsov Dec 4, 2022
112b114
with BufferedReadStream decoder cancellation works for all decoders, …
antonfirsov Dec 4, 2022
d1c76e2
fix comments
antonfirsov Dec 4, 2022
f3a2aea
Merge pull request #2301 from SixLabors/af/decoder-tests
JimBobSquarePants Dec 4, 2022
0018845
fix Identify cancellation tests
antonfirsov Dec 4, 2022
6a07a51
one more fix
antonfirsov Dec 4, 2022
6675333
Merge branch 'af/decoder-tests' into js/decoder-attempt-2
antonfirsov Dec 4, 2022
1b1be0a
fix condition
antonfirsov Dec 5, 2022
ce7ef11
cancellation tests: larger images, don't go above 0.7
antonfirsov Dec 7, 2022
b9ba211
only test for pre-cancellation with IdentifyAsync
antonfirsov Dec 7, 2022
834f686
increase timeout
antonfirsov Dec 7, 2022
25e8d01
cancellation detection in png DecodePixelData
antonfirsov Dec 7, 2022
0eadea2
skip PNG cancellation tests for Unix
antonfirsov Dec 7, 2022
a58e6ff
Add more cancellation checks
JimBobSquarePants Dec 8, 2022
e2c5748
Base the buffer size on the stream length
JimBobSquarePants Dec 8, 2022
718bdc4
Experiment with a much shorter timeout.
JimBobSquarePants Dec 8, 2022
5f488ee
Revert "Experiment with a much shorter timeout."
JimBobSquarePants Dec 8, 2022
64b4045
disable gif cancellation tests
antonfirsov Dec 9, 2022
475825d
Merge branch 'js/decoder-attempt-2' of https://github.com/SixLabors/I…
antonfirsov Dec 9, 2022
9a55652
we should validate cancellation for each decoder separately
antonfirsov Dec 9, 2022
bb22d69
Disable cancellation tests on Unix entirely
antonfirsov Dec 9, 2022
2145794
Fix test file
JimBobSquarePants Dec 11, 2022
bd6e58c
Merge branch 'js/decoder-attempt-2' of https://github.com/SixLabors/I…
JimBobSquarePants Dec 11, 2022
1dd2d6e
Better error handling in action wrapper
JimBobSquarePants Dec 12, 2022
85dc0f3
[Experiment] do not timeout LoadAsync_IsCancellable
antonfirsov Dec 12, 2022
205e1b3
Make decoder cancellation token default.
JimBobSquarePants Dec 12, 2022
64c7a8e
Merge branch 'js/decoder-attempt-2' of https://github.com/SixLabors/I…
JimBobSquarePants Dec 12, 2022
4007a48
Use shared instances for all built-in decoders.
JimBobSquarePants Dec 13, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/ImageSharp/Advanced/AotCompilerTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ private static void AotCompileImageEncoder<TPixel, TEncoder>()
private static void AotCompileImageDecoder<TPixel, TDecoder>()
where TPixel : unmanaged, IPixel<TPixel>
where TDecoder : class, IImageDecoder
=> default(TDecoder).Decode<TPixel>(default, default, default);
=> default(TDecoder).Decode<TPixel>(default, default);

/// <summary>
/// This method pre-seeds the all <see cref="IImageProcessor" /> in the AoT compiler.
Expand Down
8 changes: 4 additions & 4 deletions src/ImageSharp/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ public Configuration()
/// Initializes a new instance of the <see cref="Configuration" /> class.
/// </summary>
/// <param name="configurationModules">A collection of configuration modules to register.</param>
public Configuration(params IConfigurationModule[] configurationModules)
public Configuration(params IImageFormatConfigurationModule[] configurationModules)
{
if (configurationModules != null)
{
foreach (IConfigurationModule p in configurationModules)
foreach (IImageFormatConfigurationModule p in configurationModules)
{
p.Configure(this);
}
Expand Down Expand Up @@ -180,7 +180,7 @@ public MemoryAllocator MemoryAllocator
/// Registers a new format provider.
/// </summary>
/// <param name="configuration">The configuration provider to call configure on.</param>
public void Configure(IConfigurationModule configuration)
public void Configure(IImageFormatConfigurationModule configuration)
{
Guard.NotNull(configuration, nameof(configuration));
configuration.Configure(this);
Expand All @@ -203,7 +203,7 @@ public void Configure(IConfigurationModule configuration)
};

/// <summary>
/// Creates the default instance with the following <see cref="IConfigurationModule"/>s preregistered:
/// Creates the default instance with the following <see cref="IImageFormatConfigurationModule"/>s preregistered:
/// <see cref="PngConfigurationModule"/>
/// <see cref="JpegConfigurationModule"/>
/// <see cref="GifConfigurationModule"/>
Expand Down
6 changes: 3 additions & 3 deletions src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

namespace SixLabors.ImageSharp.Formats.Bmp;

/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the bmp format.
/// </summary>
public sealed class BmpConfigurationModule : IConfigurationModule
public sealed class BmpConfigurationModule : IImageFormatConfigurationModule
{
/// <inheritdoc/>
public void Configure(Configuration configuration)
{
configuration.ImageFormatsManager.SetEncoder(BmpFormat.Instance, new BmpEncoder());
configuration.ImageFormatsManager.SetDecoder(BmpFormat.Instance, new BmpDecoder());
configuration.ImageFormatsManager.SetDecoder(BmpFormat.Instance, BmpDecoder.Instance);
configuration.ImageFormatsManager.AddImageFormatDetector(new BmpImageFormatDetector());
}
}
33 changes: 19 additions & 14 deletions src/ImageSharp/Formats/Bmp/BmpDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,19 @@ namespace SixLabors.ImageSharp.Formats.Bmp;
/// <summary>
/// Image decoder for generating an image out of a Windows bitmap stream.
/// </summary>
public class BmpDecoder : IImageDecoderSpecialized<BmpDecoderOptions>
public sealed class BmpDecoder : SpecializedImageDecoder<BmpDecoderOptions>
{
private BmpDecoder()
{
}

/// <summary>
/// Gets the shared instance.
/// </summary>
public static BmpDecoder Instance { get; } = new();

/// <inheritdoc/>
IImageInfo IImageInfoDetector.Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
protected override IImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream));
Expand All @@ -20,27 +29,23 @@ IImageInfo IImageInfoDetector.Identify(DecoderOptions options, Stream stream, Ca
}

/// <inheritdoc/>
Image<TPixel> IImageDecoder.Decode<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
=> ((IImageDecoderSpecialized<BmpDecoderOptions>)this).Decode<TPixel>(new() { GeneralOptions = options }, stream, cancellationToken);

/// <inheritdoc/>
Image IImageDecoder.Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
=> ((IImageDecoderSpecialized<BmpDecoderOptions>)this).Decode(new() { GeneralOptions = options }, stream, cancellationToken);

/// <inheritdoc/>
Image<TPixel> IImageDecoderSpecialized<BmpDecoderOptions>.Decode<TPixel>(BmpDecoderOptions options, Stream stream, CancellationToken cancellationToken)
protected override Image<TPixel> Decode<TPixel>(BmpDecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream));

Image<TPixel> image = new BmpDecoderCore(options).Decode<TPixel>(options.GeneralOptions.Configuration, stream, cancellationToken);

ImageDecoderUtilities.Resize(options.GeneralOptions, image);
ScaleToTargetSize(options.GeneralOptions, image);

return image;
}

/// <inheritdoc/>
Image IImageDecoderSpecialized<BmpDecoderOptions>.Decode(BmpDecoderOptions options, Stream stream, CancellationToken cancellationToken)
=> ((IImageDecoderSpecialized<BmpDecoderOptions>)this).Decode<Rgba32>(options, stream, cancellationToken);
protected override Image Decode(BmpDecoderOptions options, Stream stream, CancellationToken cancellationToken)
=> this.Decode<Rgba32>(options, stream, cancellationToken);

/// <inheritdoc/>
protected override BmpDecoderOptions CreateDefaultSpecializedOptions(DecoderOptions options)
=> new() { GeneralOptions = options };
}
6 changes: 3 additions & 3 deletions src/ImageSharp/Formats/Bmp/BmpDecoderOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp;
public sealed class BmpDecoderOptions : ISpecializedDecoderOptions
{
/// <inheritdoc/>
public DecoderOptions GeneralOptions { get; set; } = new();
public DecoderOptions GeneralOptions { get; init; } = new();

/// <summary>
/// Gets or sets the value indicating how to deal with skipped pixels,
/// Gets the value indicating how to deal with skipped pixels,
/// which can occur during decoding run length encoded bitmaps.
/// </summary>
public RleSkippedPixelHandling RleSkippedPixelHandling { get; set; }
public RleSkippedPixelHandling RleSkippedPixelHandling { get; init; }
}
11 changes: 2 additions & 9 deletions src/ImageSharp/Formats/Bmp/BmpEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,9 @@ public sealed class BmpEncoder : QuantizingImageEncoder
public bool SupportTransparency { get; init; }

/// <inheritdoc/>
public override void Encode<TPixel>(Image<TPixel> image, Stream stream)
protected override void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken)
{
BmpEncoderCore encoder = new(this, image.GetMemoryAllocator());
encoder.Encode(image, stream);
}

/// <inheritdoc/>
public override Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken)
{
BmpEncoderCore encoder = new(this, image.GetMemoryAllocator());
return encoder.EncodeAsync(image, stream, cancellationToken);
encoder.Encode(image, stream, cancellationToken);
}
}
6 changes: 3 additions & 3 deletions src/ImageSharp/Formats/Bmp/BmpFormat.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

namespace SixLabors.ImageSharp.Formats.Bmp;
Expand All @@ -13,7 +13,7 @@ private BmpFormat()
}

/// <summary>
/// Gets the current instance.
/// Gets the shared instance.
/// </summary>
public static BmpFormat Instance { get; } = new BmpFormat();

Expand All @@ -30,5 +30,5 @@ private BmpFormat()
public IEnumerable<string> FileExtensions => BmpConstants.FileExtensions;

/// <inheritdoc/>
public BmpMetadata CreateDefaultFormatMetadata() => new BmpMetadata();
public BmpMetadata CreateDefaultFormatMetadata() => new();
}
20 changes: 10 additions & 10 deletions src/ImageSharp/Formats/DecoderOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,27 @@ public sealed class DecoderOptions
internal static DecoderOptions Default { get; } = LazyOptions.Value;

/// <summary>
/// Gets or sets a custom Configuration instance to be used by the image processing pipeline.
/// Gets a custom configuration instance to be used by the image processing pipeline.
/// </summary>
public Configuration Configuration { get; set; } = Configuration.Default;
public Configuration Configuration { get; internal set; } = Configuration.Default;

/// <summary>
/// Gets or sets the target size to decode the image into.
/// Gets the target size to decode the image into. Scaling should use an operation equivalent to <see cref="ResizeMode.Max"/>.
/// </summary>
public Size? TargetSize { get; set; }
public Size? TargetSize { get; init; }

/// <summary>
/// Gets or sets the sampler to use when resizing during decoding.
/// Gets the sampler to use when resizing during decoding.
/// </summary>
public IResampler Sampler { get; set; } = KnownResamplers.Box;
public IResampler Sampler { get; init; } = KnownResamplers.Box;

/// <summary>
/// Gets or sets a value indicating whether to ignore encoded metadata when decoding.
/// Gets a value indicating whether to ignore encoded metadata when decoding.
/// </summary>
public bool SkipMetadata { get; set; }
public bool SkipMetadata { get; init; }

/// <summary>
/// Gets or sets the maximum number of image frames to decode, inclusive.
/// Gets the maximum number of image frames to decode, inclusive.
/// </summary>
public uint MaxFrames { get => this.maxFrames; set => this.maxFrames = Math.Clamp(value, 1, int.MaxValue); }
public uint MaxFrames { get => this.maxFrames; init => this.maxFrames = Math.Clamp(value, 1, int.MaxValue); }
}
6 changes: 3 additions & 3 deletions src/ImageSharp/Formats/Gif/GifConfigurationModule.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.

namespace SixLabors.ImageSharp.Formats.Gif;

/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the gif format.
/// </summary>
public sealed class GifConfigurationModule : IConfigurationModule
public sealed class GifConfigurationModule : IImageFormatConfigurationModule
{
/// <inheritdoc/>
public void Configure(Configuration configuration)
{
configuration.ImageFormatsManager.SetEncoder(GifFormat.Instance, new GifEncoder());
configuration.ImageFormatsManager.SetDecoder(GifFormat.Instance, new GifDecoder());
configuration.ImageFormatsManager.SetDecoder(GifFormat.Instance, GifDecoder.Instance);
configuration.ImageFormatsManager.AddImageFormatDetector(new GifImageFormatDetector());
}
}
21 changes: 15 additions & 6 deletions src/ImageSharp/Formats/Gif/GifDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,19 @@ namespace SixLabors.ImageSharp.Formats.Gif;
/// <summary>
/// Decoder for generating an image out of a gif encoded stream.
/// </summary>
public sealed class GifDecoder : IImageDecoder
public sealed class GifDecoder : ImageDecoder
{
private GifDecoder()
{
}

/// <summary>
/// Gets the shared instance.
/// </summary>
public static GifDecoder Instance { get; } = new();

/// <inheritdoc/>
IImageInfo IImageInfoDetector.Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
protected override IImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream));
Expand All @@ -20,20 +29,20 @@ IImageInfo IImageInfoDetector.Identify(DecoderOptions options, Stream stream, Ca
}

/// <inheritdoc/>
Image<TPixel> IImageDecoder.Decode<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
protected override Image<TPixel> Decode<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
{
Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream));

GifDecoderCore decoder = new(options);
Image<TPixel> image = decoder.Decode<TPixel>(options.Configuration, stream, cancellationToken);

ImageDecoderUtilities.Resize(options, image);
ScaleToTargetSize(options, image);

return image;
}

/// <inheritdoc/>
Image IImageDecoder.Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
=> ((IImageDecoder)this).Decode<Rgba32>(options, stream, cancellationToken);
protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
=> this.Decode<Rgba32>(options, stream, cancellationToken);
}
11 changes: 2 additions & 9 deletions src/ImageSharp/Formats/Gif/GifEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,9 @@ public sealed class GifEncoder : QuantizingImageEncoder
public GifColorTableMode? ColorTableMode { get; init; }

/// <inheritdoc/>
public override void Encode<TPixel>(Image<TPixel> image, Stream stream)
protected override void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken)
{
GifEncoderCore encoder = new(image.GetConfiguration(), this);
encoder.Encode(image, stream);
}

/// <inheritdoc/>
public override Task EncodeAsync<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken)
{
GifEncoderCore encoder = new(image.GetConfiguration(), this);
return encoder.EncodeAsync(image, stream, cancellationToken);
encoder.Encode(image, stream, cancellationToken);
}
}
2 changes: 1 addition & 1 deletion src/ImageSharp/Formats/Gif/GifFormat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ private GifFormat()
}

/// <summary>
/// Gets the current instance.
/// Gets the shared instance.
/// </summary>
public static GifFormat Instance { get; } = new();

Expand Down
59 changes: 46 additions & 13 deletions src/ImageSharp/Formats/IImageDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,68 @@
namespace SixLabors.ImageSharp.Formats;

/// <summary>
/// Encapsulates properties and methods required for decoding an image from a stream.
/// Defines the contract for all image decoders.
/// </summary>
public interface IImageDecoder : IImageInfoDetector
public interface IImageDecoder
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No reason for a separate interface here.

{
/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <returns>The <see cref="IImageInfo"/> object.</returns>
/// <exception cref="ImageFormatException">Thrown if the encoded image contains errors.</exception>
public IImageInfo Identify(DecoderOptions options, Stream stream);

/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The <see cref="Task{IImageInfo}"/> object.</returns>
/// <exception cref="ImageFormatException">Thrown if the encoded image contains errors.</exception>
public Task<IImageInfo> IdentifyAsync(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default);

/// <summary>
/// Decodes the image from the specified stream to an <see cref="Image{TPixel}"/> of a specific pixel type.
/// </summary>
/// <remarks>
/// This method is designed to support the ImageSharp internal infrastructure and is not recommended for direct use.
/// </remarks>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <exception cref="ImageFormatException">Thrown if the encoded image contains errors.</exception>
Image<TPixel> Decode<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
public Image<TPixel> Decode<TPixel>(DecoderOptions options, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>;

/// <summary>
/// Decodes the image from the specified stream to an <see cref="Image"/> of a specific pixel type.
/// </summary>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
/// <exception cref="ImageFormatException">Thrown if the encoded image contains errors.</exception>
public Image Decode(DecoderOptions options, Stream stream);

/// <summary>
/// Decodes the image from the specified stream to an <see cref="Image{TPixel}"/> of a specific pixel type.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
/// <exception cref="ImageFormatException">Thrown if the encoded image contains errors.</exception>
public Task<Image<TPixel>> DecodeAsync<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default)
where TPixel : unmanaged, IPixel<TPixel>;

/// <summary>
/// Decodes the image from the specified stream to an <see cref="Image"/>.
/// Decodes the image from the specified stream to an <see cref="Image"/> of a specific pixel type.
/// </summary>
/// <remarks>
/// This method is designed to support the ImageSharp internal infrastructure and is not recommended for direct use.
/// </remarks>
/// <param name="options">The general decoder options.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The <see cref="Image"/>.</returns>
/// <returns>A <see cref="Task{Image}"/> representing the asynchronous operation.</returns>
/// <exception cref="ImageFormatException">Thrown if the encoded image contains errors.</exception>
Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken);
public Task<Image> DecodeAsync(DecoderOptions options, Stream stream, CancellationToken cancellationToken = default);
}
Loading