Skip to content

Commit 74e2b7c

Browse files
Merge pull request #2180 from SixLabors/js/decoder-options
Introduce Shared General Decoder Options plus Specialization
2 parents 1b6728b + 92ac2d7 commit 74e2b7c

File tree

128 files changed

+3493
-3941
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+3493
-3941
lines changed

src/ImageSharp/Advanced/AotCompilerTools.cs

+10-12
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ private static unsafe void AotCompileImage<TPixel>()
178178
img.CloneAs<Short2>(default);
179179
img.CloneAs<Short4>(default);
180180

181-
ImageFrame.LoadPixelData<TPixel>(default, default(ReadOnlySpan<TPixel>), default, default);
181+
ImageFrame.LoadPixelData(default, default(ReadOnlySpan<TPixel>), default, default);
182182
ImageFrame.LoadPixelData<TPixel>(default, default(ReadOnlySpan<byte>), default, default);
183183
}
184184

@@ -217,14 +217,14 @@ private static void AotCompileImageEncoderInternals<TPixel>()
217217
private static void AotCompileImageDecoderInternals<TPixel>()
218218
where TPixel : unmanaged, IPixel<TPixel>
219219
{
220-
default(WebpDecoderCore).Decode<TPixel>(default, default, default);
221-
default(BmpDecoderCore).Decode<TPixel>(default, default, default);
222-
default(GifDecoderCore).Decode<TPixel>(default, default, default);
223-
default(JpegDecoderCore).Decode<TPixel>(default, default, default);
224-
default(PbmDecoderCore).Decode<TPixel>(default, default, default);
225-
default(PngDecoderCore).Decode<TPixel>(default, default, default);
226-
default(TgaDecoderCore).Decode<TPixel>(default, default, default);
227-
default(TiffDecoderCore).Decode<TPixel>(default, default, default);
220+
default(WebpDecoderCore).Decode<TPixel>(default, default);
221+
default(BmpDecoderCore).Decode<TPixel>(default, default);
222+
default(GifDecoderCore).Decode<TPixel>(default, default);
223+
default(JpegDecoderCore).Decode<TPixel>(default, default);
224+
default(PbmDecoderCore).Decode<TPixel>(default, default);
225+
default(PngDecoderCore).Decode<TPixel>(default, default);
226+
default(TgaDecoderCore).Decode<TPixel>(default, default);
227+
default(TiffDecoderCore).Decode<TPixel>(default, default);
228228
}
229229

230230
/// <summary>
@@ -286,9 +286,7 @@ private static void AotCompileImageEncoder<TPixel, TEncoder>()
286286
private static void AotCompileImageDecoder<TPixel, TDecoder>()
287287
where TPixel : unmanaged, IPixel<TPixel>
288288
where TDecoder : class, IImageDecoder
289-
{
290-
default(TDecoder).Decode<TPixel>(default, default, default);
291-
}
289+
=> default(TDecoder).Decode<TPixel>(default, default, default);
292290

293291
/// <summary>
294292
/// This method pre-seeds the all <see cref="IImageProcessor" /> in the AoT compiler.

src/ImageSharp/Formats/Bmp/BmpDecoder.cs

+22-25
Original file line numberDiff line numberDiff line change
@@ -10,43 +10,40 @@ namespace SixLabors.ImageSharp.Formats.Bmp
1010
/// <summary>
1111
/// Image decoder for generating an image out of a Windows bitmap stream.
1212
/// </summary>
13-
/// <remarks>
14-
/// Does not support the following formats at the moment:
15-
/// <list type="bullet">
16-
/// <item>JPG</item>
17-
/// <item>PNG</item>
18-
/// <item>Some OS/2 specific subtypes like: Bitmap Array, Color Icon, Color Pointer, Icon, Pointer.</item>
19-
/// </list>
20-
/// Formats will be supported in a later releases. We advise always
21-
/// to use only 24 Bit Windows bitmaps.
22-
/// </remarks>
23-
public sealed class BmpDecoder : IImageDecoder, IBmpDecoderOptions, IImageInfoDetector
13+
public class BmpDecoder : IImageDecoderSpecialized<BmpDecoderOptions>
2414
{
25-
/// <summary>
26-
/// Gets or sets a value indicating how to deal with skipped pixels, which can occur during decoding run length encoded bitmaps.
27-
/// </summary>
28-
public RleSkippedPixelHandling RleSkippedPixelHandling { get; set; } = RleSkippedPixelHandling.Black;
29-
3015
/// <inheritdoc/>
31-
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream, CancellationToken cancellationToken)
32-
where TPixel : unmanaged, IPixel<TPixel>
16+
IImageInfo IImageInfoDetector.Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
3317
{
18+
Guard.NotNull(options, nameof(options));
3419
Guard.NotNull(stream, nameof(stream));
3520

36-
var decoder = new BmpDecoderCore(configuration, this);
37-
return decoder.Decode<TPixel>(configuration, stream, cancellationToken);
21+
return new BmpDecoderCore(new() { GeneralOptions = options }).Identify(options.Configuration, stream, cancellationToken);
3822
}
3923

40-
/// <inheritdoc />
41-
public Image Decode(Configuration configuration, Stream stream, CancellationToken cancellationToken)
42-
=> this.Decode<Rgba32>(configuration, stream, cancellationToken);
24+
/// <inheritdoc/>
25+
Image<TPixel> IImageDecoder.Decode<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
26+
=> ((IImageDecoderSpecialized<BmpDecoderOptions>)this).Decode<TPixel>(new() { GeneralOptions = options }, stream, cancellationToken);
27+
28+
/// <inheritdoc/>
29+
Image IImageDecoder.Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
30+
=> ((IImageDecoderSpecialized<BmpDecoderOptions>)this).Decode(new() { GeneralOptions = options }, stream, cancellationToken);
4331

4432
/// <inheritdoc/>
45-
public IImageInfo Identify(Configuration configuration, Stream stream, CancellationToken cancellationToken)
33+
Image<TPixel> IImageDecoderSpecialized<BmpDecoderOptions>.Decode<TPixel>(BmpDecoderOptions options, Stream stream, CancellationToken cancellationToken)
4634
{
35+
Guard.NotNull(options, nameof(options));
4736
Guard.NotNull(stream, nameof(stream));
4837

49-
return new BmpDecoderCore(configuration, this).Identify(configuration, stream, cancellationToken);
38+
Image<TPixel> image = new BmpDecoderCore(options).Decode<TPixel>(options.GeneralOptions.Configuration, stream, cancellationToken);
39+
40+
ImageDecoderUtilities.Resize(options.GeneralOptions, image);
41+
42+
return image;
5043
}
44+
45+
/// <inheritdoc/>
46+
Image IImageDecoderSpecialized<BmpDecoderOptions>.Decode(BmpDecoderOptions options, Stream stream, CancellationToken cancellationToken)
47+
=> ((IImageDecoderSpecialized<BmpDecoderOptions>)this).Decode<Rgba32>(options, stream, cancellationToken);
5148
}
5249
}

src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

+23-19
Original file line numberDiff line numberDiff line change
@@ -89,34 +89,38 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
8989
/// </summary>
9090
private BmpInfoHeader infoHeader;
9191

92+
/// <summary>
93+
/// The global configuration.
94+
/// </summary>
95+
private readonly Configuration configuration;
96+
9297
/// <summary>
9398
/// Used for allocating memory during processing operations.
9499
/// </summary>
95100
private readonly MemoryAllocator memoryAllocator;
96101

97102
/// <summary>
98-
/// The bitmap decoder options.
103+
/// How to deal with skipped pixels,
104+
/// which can occur during decoding run length encoded bitmaps.
99105
/// </summary>
100-
private readonly IBmpDecoderOptions options;
106+
private readonly RleSkippedPixelHandling rleSkippedPixelHandling;
101107

102108
/// <summary>
103109
/// Initializes a new instance of the <see cref="BmpDecoderCore"/> class.
104110
/// </summary>
105-
/// <param name="configuration">The configuration.</param>
106111
/// <param name="options">The options.</param>
107-
public BmpDecoderCore(Configuration configuration, IBmpDecoderOptions options)
112+
public BmpDecoderCore(BmpDecoderOptions options)
108113
{
109-
this.Configuration = configuration;
110-
this.memoryAllocator = configuration.MemoryAllocator;
111-
this.options = options;
114+
this.Options = options.GeneralOptions;
115+
this.rleSkippedPixelHandling = options.RleSkippedPixelHandling;
116+
this.configuration = options.GeneralOptions.Configuration;
117+
this.memoryAllocator = this.configuration.MemoryAllocator;
112118
}
113119

114120
/// <inheritdoc />
115-
public Configuration Configuration { get; }
121+
public DecoderOptions Options { get; }
116122

117-
/// <summary>
118-
/// Gets the dimensions of the image.
119-
/// </summary>
123+
/// <inheritdoc />
120124
public Size Dimensions => new(this.infoHeader.Width, this.infoHeader.Height);
121125

122126
/// <inheritdoc />
@@ -128,7 +132,7 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
128132
{
129133
int bytesPerColorMapEntry = this.ReadImageHeaders(stream, out bool inverted, out byte[] palette);
130134

131-
image = new Image<TPixel>(this.Configuration, this.infoHeader.Width, this.infoHeader.Height, this.metadata);
135+
image = new Image<TPixel>(this.configuration, this.infoHeader.Width, this.infoHeader.Height, this.metadata);
132136

133137
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
134138

@@ -325,7 +329,7 @@ private void ReadRle<TPixel>(BmpCompression compression, Buffer2D<TPixel> pixels
325329
byte colorIdx = bufferRow[x];
326330
if (undefinedPixelsSpan[rowStartIdx + x])
327331
{
328-
switch (this.options.RleSkippedPixelHandling)
332+
switch (this.rleSkippedPixelHandling)
329333
{
330334
case RleSkippedPixelHandling.FirstColorOfPalette:
331335
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref colors[colorIdx * 4]));
@@ -397,7 +401,7 @@ private void ReadRle24<TPixel>(Buffer2D<TPixel> pixels, int width, int height, b
397401
int idx = rowStartIdx + (x * 3);
398402
if (undefinedPixelsSpan[yMulWidth + x])
399403
{
400-
switch (this.options.RleSkippedPixelHandling)
404+
switch (this.rleSkippedPixelHandling)
401405
{
402406
case RleSkippedPixelHandling.FirstColorOfPalette:
403407
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref bufferSpan[idx]));
@@ -943,7 +947,7 @@ private void ReadRgb24<TPixel>(Buffer2D<TPixel> pixels, int width, int height, b
943947
int newY = Invert(y, height, inverted);
944948
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(newY);
945949
PixelOperations<TPixel>.Instance.FromBgr24Bytes(
946-
this.Configuration,
950+
this.configuration,
947951
rowSpan,
948952
pixelSpan,
949953
width);
@@ -971,7 +975,7 @@ private void ReadRgb32Fast<TPixel>(Buffer2D<TPixel> pixels, int width, int heigh
971975
int newY = Invert(y, height, inverted);
972976
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(newY);
973977
PixelOperations<TPixel>.Instance.FromBgra32Bytes(
974-
this.Configuration,
978+
this.configuration,
975979
rowSpan,
976980
pixelSpan,
977981
width);
@@ -1006,7 +1010,7 @@ private void ReadRgb32Slow<TPixel>(Buffer2D<TPixel> pixels, int width, int heigh
10061010
this.stream.Read(rowSpan);
10071011

10081012
PixelOperations<Bgra32>.Instance.FromBgra32Bytes(
1009-
this.Configuration,
1013+
this.configuration,
10101014
rowSpan,
10111015
bgraRowSpan,
10121016
width);
@@ -1042,7 +1046,7 @@ private void ReadRgb32Slow<TPixel>(Buffer2D<TPixel> pixels, int width, int heigh
10421046
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(newY);
10431047

10441048
PixelOperations<TPixel>.Instance.FromBgra32Bytes(
1045-
this.Configuration,
1049+
this.configuration,
10461050
rowSpan,
10471051
pixelSpan,
10481052
width);
@@ -1056,7 +1060,7 @@ private void ReadRgb32Slow<TPixel>(Buffer2D<TPixel> pixels, int width, int heigh
10561060
{
10571061
this.stream.Read(rowSpan);
10581062
PixelOperations<Bgra32>.Instance.FromBgra32Bytes(
1059-
this.Configuration,
1063+
this.configuration,
10601064
rowSpan,
10611065
bgraRowSpan,
10621066
width);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
namespace SixLabors.ImageSharp.Formats.Bmp
5+
{
6+
/// <summary>
7+
/// Configuration options for decoding Windows Bitmap images.
8+
/// </summary>
9+
public sealed class BmpDecoderOptions : ISpecializedDecoderOptions
10+
{
11+
/// <inheritdoc/>
12+
public DecoderOptions GeneralOptions { get; set; } = new();
13+
14+
/// <summary>
15+
/// Gets or sets the value indicating how to deal with skipped pixels,
16+
/// which can occur during decoding run length encoded bitmaps.
17+
/// </summary>
18+
public RleSkippedPixelHandling RleSkippedPixelHandling { get; set; }
19+
}
20+
}

src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs

-16
This file was deleted.
+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
using System;
5+
using SixLabors.ImageSharp.Processing;
6+
using SixLabors.ImageSharp.Processing.Processors.Transforms;
7+
8+
namespace SixLabors.ImageSharp.Formats
9+
{
10+
/// <summary>
11+
/// Provides general configuration options for decoding image formats.
12+
/// </summary>
13+
public sealed class DecoderOptions
14+
{
15+
private static readonly Lazy<DecoderOptions> LazyOptions = new(() => new());
16+
17+
private uint maxFrames = int.MaxValue;
18+
19+
/// <summary>
20+
/// Gets the shared default general decoder options instance.
21+
/// </summary>
22+
internal static DecoderOptions Default { get; } = LazyOptions.Value;
23+
24+
/// <summary>
25+
/// Gets or sets a custom Configuration instance to be used by the image processing pipeline.
26+
/// </summary>
27+
public Configuration Configuration { get; set; } = Configuration.Default;
28+
29+
/// <summary>
30+
/// Gets or sets the target size to decode the image into.
31+
/// </summary>
32+
public Size? TargetSize { get; set; } = null;
33+
34+
/// <summary>
35+
/// Gets or sets the sampler to use when resizing during decoding.
36+
/// </summary>
37+
public IResampler Sampler { get; set; } = KnownResamplers.Box;
38+
39+
/// <summary>
40+
/// Gets or sets a value indicating whether to ignore encoded metadata when decoding.
41+
/// </summary>
42+
public bool SkipMetadata { get; set; } = false;
43+
44+
/// <summary>
45+
/// Gets or sets the maximum number of image frames to decode, inclusive.
46+
/// </summary>
47+
public uint MaxFrames { get => this.maxFrames; set => this.maxFrames = Math.Clamp(value, 1, int.MaxValue); }
48+
}
49+
}

src/ImageSharp/Formats/Gif/GifDecoder.cs

+18-23
Original file line numberDiff line numberDiff line change
@@ -3,45 +3,40 @@
33

44
using System.IO;
55
using System.Threading;
6-
using SixLabors.ImageSharp.Metadata;
76
using SixLabors.ImageSharp.PixelFormats;
87

98
namespace SixLabors.ImageSharp.Formats.Gif
109
{
1110
/// <summary>
1211
/// Decoder for generating an image out of a gif encoded stream.
1312
/// </summary>
14-
public sealed class GifDecoder : IImageDecoder, IGifDecoderOptions, IImageInfoDetector
13+
public sealed class GifDecoder : IImageDecoder
1514
{
16-
/// <summary>
17-
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded.
18-
/// </summary>
19-
public bool IgnoreMetadata { get; set; } = false;
20-
21-
/// <summary>
22-
/// Gets or sets the decoding mode for multi-frame images
23-
/// </summary>
24-
public FrameDecodingMode DecodingMode { get; set; } = FrameDecodingMode.All;
25-
2615
/// <inheritdoc/>
27-
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream, CancellationToken cancellationToken)
28-
where TPixel : unmanaged, IPixel<TPixel>
16+
IImageInfo IImageInfoDetector.Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
2917
{
30-
var decoder = new GifDecoderCore(configuration, this);
31-
return decoder.Decode<TPixel>(configuration, stream, cancellationToken);
32-
}
18+
Guard.NotNull(options, nameof(options));
19+
Guard.NotNull(stream, nameof(stream));
3320

34-
/// <inheritdoc />
35-
public Image Decode(Configuration configuration, Stream stream, CancellationToken cancellationToken)
36-
=> this.Decode<Rgba32>(configuration, stream, cancellationToken);
21+
return new GifDecoderCore(options).Identify(options.Configuration, stream, cancellationToken);
22+
}
3723

3824
/// <inheritdoc/>
39-
public IImageInfo Identify(Configuration configuration, Stream stream, CancellationToken cancellationToken)
25+
Image<TPixel> IImageDecoder.Decode<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
4026
{
27+
Guard.NotNull(options, nameof(options));
4128
Guard.NotNull(stream, nameof(stream));
4229

43-
var decoder = new GifDecoderCore(configuration, this);
44-
return decoder.Identify(configuration, stream, cancellationToken);
30+
GifDecoderCore decoder = new(options);
31+
Image<TPixel> image = decoder.Decode<TPixel>(options.Configuration, stream, cancellationToken);
32+
33+
ImageDecoderUtilities.Resize(options, image);
34+
35+
return image;
4536
}
37+
38+
/// <inheritdoc/>
39+
Image IImageDecoder.Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
40+
=> ((IImageDecoder)this).Decode<Rgba32>(options, stream, cancellationToken);
4641
}
4742
}

0 commit comments

Comments
 (0)