diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoder2.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder2.cs
new file mode 100644
index 0000000000..97439182d5
--- /dev/null
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoder2.cs
@@ -0,0 +1,30 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.IO;
+using System.Threading;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Formats.Bmp
+{
+ ///
+ /// Image decoder for generating an image out of a Windows bitmap stream.
+ ///
+ public class BmpDecoder2 : ImageDecoder
+ {
+ ///
+ public override Image DecodeSpecialized(BmpDecoderOptions options, Stream stream, CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ public override Image DecodeSpecialized(BmpDecoderOptions options, Stream stream, CancellationToken cancellationToken)
+ => this.DecodeSpecialized(options, stream, cancellationToken);
+
+ ///
+ public override IImageInfo IdentifySpecialized(BmpDecoderOptions options, Stream stream, CancellationToken cancellationToken)
+ => throw new NotImplementedException();
+ }
+}
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderOptions.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderOptions.cs
new file mode 100644
index 0000000000..74509d68f3
--- /dev/null
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderOptions.cs
@@ -0,0 +1,20 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Formats.Bmp
+{
+ ///
+ /// Image decoder options for decoding Windows bitmap streams.
+ ///
+ public sealed class BmpDecoderOptions : ISpecializedDecoderOptions
+ {
+ ///
+ public DecoderOptions GeneralOptions { get; set; } = new();
+
+ ///
+ /// Gets the value indicating how to deal with skipped pixels,
+ /// which can occur during decoding run length encoded bitmaps.
+ ///
+ public RleSkippedPixelHandling RleSkippedPixelHandling { get; }
+ }
+}
diff --git a/src/ImageSharp/Formats/DecoderOptions.cs b/src/ImageSharp/Formats/DecoderOptions.cs
new file mode 100644
index 0000000000..a690b06075
--- /dev/null
+++ b/src/ImageSharp/Formats/DecoderOptions.cs
@@ -0,0 +1,33 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Formats
+{
+ ///
+ /// Provides general configuration options for decoding image formats.
+ ///
+ public sealed class DecoderOptions
+ {
+ ///
+ /// Gets or sets a custom Configuration instance to be used by the image processing pipeline.
+ ///
+ public Configuration Configuration { get; set; } = Configuration.Default;
+
+ ///
+ /// Gets or sets the target size to decode the image into.
+ ///
+ public Size? TargetSize { get; set; } = null;
+
+ ///
+ /// Gets or sets a value indicating whether to ignore encoded metadata when decoding.
+ ///
+ public bool SkipMetadata { get; set; } = false;
+
+ ///
+ /// Gets or sets the number of image frames to decode.
+ /// Leave to decode all frames.
+ ///
+ // supported decoders may handle this internally but we will fallback to removeing additional frames after decode.
+ public int? MaxFrames { get; set; } = null;
+ }
+}
diff --git a/src/ImageSharp/Formats/IImageDecoder2.cs b/src/ImageSharp/Formats/IImageDecoder2.cs
new file mode 100644
index 0000000000..76d1a754d4
--- /dev/null
+++ b/src/ImageSharp/Formats/IImageDecoder2.cs
@@ -0,0 +1,37 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.IO;
+using System.Threading;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Formats
+{
+ ///
+ /// Encapsulates properties and methods required for decoding an image from a stream.
+ ///
+ public interface IImageDecoder2
+ {
+ ///
+ /// Decodes the image from the specified stream to an of a specific pixel type.
+ ///
+ /// The pixel format.
+ /// The general decoder options.
+ /// The containing image data.
+ /// The token to monitor for cancellation requests.
+ /// The .
+ /// Thrown if the encoded image contains errors.
+ Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
+ where TPixel : unmanaged, IPixel;
+
+ ///
+ /// Decodes the image from the specified stream to an .
+ ///
+ /// The general decoder options.
+ /// The containing image data.
+ /// The token to monitor for cancellation requests.
+ /// The .
+ /// Thrown if the encoded image contains errors.
+ Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken);
+ }
+}
diff --git a/src/ImageSharp/Formats/IImageInfoDetector2.cs b/src/ImageSharp/Formats/IImageInfoDetector2.cs
new file mode 100644
index 0000000000..3d340f06e8
--- /dev/null
+++ b/src/ImageSharp/Formats/IImageInfoDetector2.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.IO;
+using System.Threading;
+
+namespace SixLabors.ImageSharp.Formats
+{
+ ///
+ /// Encapsulates methods used for detecting the raw image information without fully decoding it.
+ ///
+ public interface IImageInfoDetector2
+ {
+ ///
+ /// Reads the raw image information from the specified stream.
+ ///
+ /// The general decoder options.
+ /// The containing image data.
+ /// The token to monitor for cancellation requests.
+ /// The object.
+ /// Thrown if the encoded image contains errors.
+ IImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken);
+ }
+}
diff --git a/src/ImageSharp/Formats/ISpecializedDecoderOptions.cs b/src/ImageSharp/Formats/ISpecializedDecoderOptions.cs
new file mode 100644
index 0000000000..b79938f08d
--- /dev/null
+++ b/src/ImageSharp/Formats/ISpecializedDecoderOptions.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Formats
+{
+ ///
+ /// Provides specialized configuration options for decoding image formats.
+ ///
+ public interface ISpecializedDecoderOptions
+ {
+ ///
+ /// Gets or sets the general decoder options.
+ ///
+ DecoderOptions GeneralOptions { get; set; }
+ }
+}
diff --git a/src/ImageSharp/Formats/ImageDecoder{T}.cs b/src/ImageSharp/Formats/ImageDecoder{T}.cs
new file mode 100644
index 0000000000..96080b3bed
--- /dev/null
+++ b/src/ImageSharp/Formats/ImageDecoder{T}.cs
@@ -0,0 +1,119 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.IO;
+using System.Threading;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing;
+
+namespace SixLabors.ImageSharp.Formats
+{
+ ///
+ /// The base class for all image decoders.
+ ///
+ /// The type of specialized decoder options.
+ public abstract class ImageDecoder : IImageInfoDetector2, IImageDecoder2
+ where T : ISpecializedDecoderOptions, new()
+ {
+ ///
+ public IImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
+ {
+ T specializedOptions = new() { GeneralOptions = options };
+ return this.IdentifySpecialized(specializedOptions, stream, cancellationToken);
+ }
+
+ ///
+ public Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
+ where TPixel : unmanaged, IPixel
+ {
+ T specializedOptions = new() { GeneralOptions = options };
+ Image image = this.DecodeSpecialized(specializedOptions, stream, cancellationToken);
+
+ Resize(options, image);
+
+ return image;
+ }
+
+ ///
+ public Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
+ {
+ T specializedOptions = new() { GeneralOptions = options };
+ Image image = this.DecodeSpecialized(specializedOptions, stream, cancellationToken);
+
+ Resize(options, image);
+
+ return image;
+ }
+
+ ///
+ /// Reads the raw image information from the specified stream.
+ ///
+ /// The specialized decoder options.
+ /// The containing image data.
+ /// The token to monitor for cancellation requests.
+ /// The object.
+ /// Thrown if the encoded image contains errors.
+ public abstract IImageInfo IdentifySpecialized(T options, Stream stream, CancellationToken cancellationToken);
+
+ ///
+ /// Decodes the image from the specified stream to an of a specific pixel type.
+ ///
+ /// The pixel format.
+ /// The specialized decoder options.
+ /// The containing image data.
+ /// The token to monitor for cancellation requests.
+ /// The .
+ /// Thrown if the encoded image contains errors.
+ public abstract Image DecodeSpecialized(T options, Stream stream, CancellationToken cancellationToken)
+ where TPixel : unmanaged, IPixel;
+
+ ///
+ /// Decodes the image from the specified stream to an of a specific pixel type.
+ ///
+ /// The specialized decoder options.
+ /// The containing image data.
+ /// The token to monitor for cancellation requests.
+ /// The .
+ /// Thrown if the encoded image contains errors.
+ public abstract Image DecodeSpecialized(T options, Stream stream, CancellationToken cancellationToken);
+
+ ///
+ /// Performs a resize operation against the decoded image. If the target size is not set, or the image size
+ /// already matches the target size, the image is untouched.
+ ///
+ /// The decoder options.
+ /// The decoded image.
+ protected static void Resize(DecoderOptions options, Image image)
+ {
+ if (ShouldResize(options, image))
+ {
+ ResizeOptions resizeOptions = new()
+ {
+ Size = options.TargetSize.Value,
+ Sampler = KnownResamplers.Box,
+ Mode = ResizeMode.Max
+ };
+
+ image.Mutate(x => x.Resize(resizeOptions));
+ }
+ }
+
+ ///
+ /// Determines whether the decoded image should be resized.
+ ///
+ /// The decoder options.
+ /// The decoded image.
+ /// if the image should be resized, otherwise; .
+ private static bool ShouldResize(DecoderOptions options, Image image)
+ {
+ if (options.TargetSize is null)
+ {
+ return false;
+ }
+
+ Size targetSize = options.TargetSize.Value;
+ Size currentSize = image.Size();
+ return currentSize.Width != targetSize.Width && currentSize.Height != targetSize.Height;
+ }
+ }
+}