Skip to content

Commit b0c827b

Browse files
Merge branch 'main' into js/webp-allocations
2 parents 31aabcc + c5eed0e commit b0c827b

File tree

10 files changed

+103
-15
lines changed

10 files changed

+103
-15
lines changed

src/ImageSharp/Formats/Tiff/Compression/Decompressors/WebpTiffCompression.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public WebpTiffCompression(DecoderOptions options, MemoryAllocator memoryAllocat
3232
/// <inheritdoc/>
3333
protected override void Decompress(BufferedReadStream stream, int byteCount, int stripHeight, Span<byte> buffer, CancellationToken cancellationToken)
3434
{
35-
using WebpDecoderCore decoder = new(this.options);
35+
using WebpDecoderCore decoder = new(new WebpDecoderOptions());
3636
using Image<Rgb24> image = decoder.Decode<Rgb24>(stream, cancellationToken);
3737
CopyImageBytesToBuffer(buffer, image.Frames.RootFrame.PixelBuffer);
3838
}

src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors;
55
using SixLabors.ImageSharp.Formats.Tiff.Constants;
66
using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
7+
using SixLabors.ImageSharp.Formats.Webp;
78
using SixLabors.ImageSharp.Memory;
89

910
namespace SixLabors.ImageSharp.Formats.Tiff.Compression;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
namespace SixLabors.ImageSharp.Formats.Webp;
5+
6+
/// <summary>
7+
/// Enum to decide how to handle the background color of the Animation chunk during decoding.
8+
/// </summary>
9+
public enum BackgroundColorHandling
10+
{
11+
/// <summary>
12+
/// The background color of the ANIM chunk will be used to initialize the canvas to fill the unused space on the canvas around the frame.
13+
/// Also, if AnimationDisposalMethod.Dispose is used, this color will be used to restore the canvas background.
14+
/// </summary>
15+
Standard = 0,
16+
17+
/// <summary>
18+
/// The background color of the ANIM chunk is ignored and instead the canvas is initialized with transparent, BGRA(0, 0, 0, 0).
19+
/// </summary>
20+
Ignore = 1
21+
}

src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,24 @@ internal class WebpAnimationDecoder : IDisposable
5252
/// </summary>
5353
private IMemoryOwner<byte>? alphaData;
5454

55+
/// <summary>
56+
/// The flag to decide how to handle the background color in the Animation Chunk.
57+
/// </summary>
58+
private readonly BackgroundColorHandling backgroundColorHandling;
59+
5560
/// <summary>
5661
/// Initializes a new instance of the <see cref="WebpAnimationDecoder"/> class.
5762
/// </summary>
5863
/// <param name="memoryAllocator">The memory allocator.</param>
5964
/// <param name="configuration">The global configuration.</param>
6065
/// <param name="maxFrames">The maximum number of frames to decode. Inclusive.</param>
61-
public WebpAnimationDecoder(MemoryAllocator memoryAllocator, Configuration configuration, uint maxFrames)
66+
/// <param name="backgroundColorHandling">The flag to decide how to handle the background color in the Animation Chunk.</param>
67+
public WebpAnimationDecoder(MemoryAllocator memoryAllocator, Configuration configuration, uint maxFrames, BackgroundColorHandling backgroundColorHandling)
6268
{
6369
this.memoryAllocator = memoryAllocator;
6470
this.configuration = configuration;
6571
this.maxFrames = maxFrames;
72+
this.backgroundColorHandling = backgroundColorHandling;
6673
}
6774

6875
/// <summary>
@@ -94,7 +101,10 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, WebpFeatures feat
94101
switch (chunkType)
95102
{
96103
case WebpChunkType.Animation:
97-
uint dataSize = this.ReadFrame(stream, ref image, ref previousFrame, width, height, features.AnimationBackgroundColor!.Value);
104+
Color backgroundColor = this.backgroundColorHandling == BackgroundColorHandling.Ignore
105+
? new Color(new Bgra32(0, 0, 0, 0))
106+
: features.AnimationBackgroundColor!.Value;
107+
uint dataSize = this.ReadFrame(stream, ref image, ref previousFrame, width, height, backgroundColor);
98108
remainingBytes -= (int)dataSize;
99109
break;
100110
case WebpChunkType.Xmp:

src/ImageSharp/Formats/Webp/WebpDecoder.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Formats.Webp;
88
/// <summary>
99
/// Image decoder for generating an image out of a webp stream.
1010
/// </summary>
11-
public sealed class WebpDecoder : ImageDecoder
11+
public sealed class WebpDecoder : SpecializedImageDecoder<WebpDecoderOptions>
1212
{
1313
private WebpDecoder()
1414
{
@@ -25,25 +25,33 @@ protected override ImageInfo Identify(DecoderOptions options, Stream stream, Can
2525
Guard.NotNull(options, nameof(options));
2626
Guard.NotNull(stream, nameof(stream));
2727

28-
using WebpDecoderCore decoder = new(options);
28+
using WebpDecoderCore decoder = new(new WebpDecoderOptions() { GeneralOptions = options });
2929
return decoder.Identify(options.Configuration, stream, cancellationToken);
3030
}
3131

3232
/// <inheritdoc/>
33-
protected override Image<TPixel> Decode<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
33+
protected override Image<TPixel> Decode<TPixel>(WebpDecoderOptions options, Stream stream, CancellationToken cancellationToken)
3434
{
3535
Guard.NotNull(options, nameof(options));
3636
Guard.NotNull(stream, nameof(stream));
3737

3838
using WebpDecoderCore decoder = new(options);
39-
Image<TPixel> image = decoder.Decode<TPixel>(options.Configuration, stream, cancellationToken);
39+
Image<TPixel> image = decoder.Decode<TPixel>(options.GeneralOptions.Configuration, stream, cancellationToken);
4040

41-
ScaleToTargetSize(options, image);
41+
ScaleToTargetSize(options.GeneralOptions, image);
4242

4343
return image;
4444
}
4545

46+
/// <inheritdoc/>
47+
protected override Image Decode(WebpDecoderOptions options, Stream stream, CancellationToken cancellationToken)
48+
=> this.Decode<Rgba32>(options, stream, cancellationToken);
49+
4650
/// <inheritdoc/>
4751
protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
4852
=> this.Decode<Rgba32>(options, stream, cancellationToken);
53+
54+
/// <inheritdoc/>
55+
protected override WebpDecoderOptions CreateDefaultSpecializedOptions(DecoderOptions options)
56+
=> new() { GeneralOptions = options };
4957
}

src/ImageSharp/Formats/Webp/WebpDecoderCore.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,22 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable
4848
/// </summary>
4949
private WebpImageInfo? webImageInfo;
5050

51+
/// <summary>
52+
/// The flag to decide how to handle the background color in the Animation Chunk.
53+
/// </summary>
54+
private BackgroundColorHandling backgroundColorHandling;
55+
5156
/// <summary>
5257
/// Initializes a new instance of the <see cref="WebpDecoderCore"/> class.
5358
/// </summary>
5459
/// <param name="options">The decoder options.</param>
55-
public WebpDecoderCore(DecoderOptions options)
60+
public WebpDecoderCore(WebpDecoderOptions options)
5661
{
57-
this.Options = options;
58-
this.configuration = options.Configuration;
59-
this.skipMetadata = options.SkipMetadata;
60-
this.maxFrames = options.MaxFrames;
62+
this.Options = options.GeneralOptions;
63+
this.backgroundColorHandling = options.BackgroundColorHandling;
64+
this.configuration = options.GeneralOptions.Configuration;
65+
this.skipMetadata = options.GeneralOptions.SkipMetadata;
66+
this.maxFrames = options.GeneralOptions.MaxFrames;
6167
this.memoryAllocator = this.configuration.MemoryAllocator;
6268
}
6369

@@ -83,7 +89,7 @@ public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken
8389
{
8490
if (this.webImageInfo.Features is { Animation: true })
8591
{
86-
using WebpAnimationDecoder animationDecoder = new(this.memoryAllocator, this.configuration, this.maxFrames);
92+
using WebpAnimationDecoder animationDecoder = new(this.memoryAllocator, this.configuration, this.maxFrames, this.backgroundColorHandling);
8793
return animationDecoder.Decode<TPixel>(stream, this.webImageInfo.Features, this.webImageInfo.Width, this.webImageInfo.Height, fileSize);
8894
}
8995

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
namespace SixLabors.ImageSharp.Formats.Webp;
5+
6+
/// <summary>
7+
/// Configuration options for decoding webp images.
8+
/// </summary>
9+
public sealed class WebpDecoderOptions : ISpecializedDecoderOptions
10+
{
11+
/// <inheritdoc/>
12+
public DecoderOptions GeneralOptions { get; init; } = new();
13+
14+
/// <summary>
15+
/// Gets the flag to decide how to handle the background color Animation Chunk.
16+
/// The specification is vague on how to handle the background color of the animation chunk.
17+
/// This option let's the user choose how to deal with it.
18+
/// </summary>
19+
/// <see href="https://developers.google.com/speed/webp/docs/riff_container#animation"/>
20+
public BackgroundColorHandling BackgroundColorHandling { get; init; } = BackgroundColorHandling.Standard;
21+
}

tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Copyright (c) Six Labors.
22
// Licensed under the Six Labors Split License.
33

4-
using System.Runtime.InteropServices;
54
using System.Runtime.Intrinsics.X86;
65
using SixLabors.ImageSharp.Formats;
76
using SixLabors.ImageSharp.Formats.Webp;
@@ -340,6 +339,24 @@ public void Decode_AnimatedLossless_WithFrameDecodingModeFirst_OnlyDecodesOneFra
340339
Assert.Equal(1, image.Frames.Count);
341340
}
342341

342+
[Theory]
343+
[WithFile(Lossy.AnimatedIssue2528, PixelTypes.Rgba32)]
344+
public void Decode_AnimatedLossy_IgnoreBackgroundColor_Works<TPixel>(TestImageProvider<TPixel> provider)
345+
where TPixel : unmanaged, IPixel<TPixel>
346+
{
347+
WebpDecoderOptions options = new()
348+
{
349+
BackgroundColorHandling = BackgroundColorHandling.Ignore,
350+
GeneralOptions = new DecoderOptions()
351+
{
352+
MaxFrames = 1
353+
}
354+
};
355+
using Image<TPixel> image = provider.GetImage(WebpDecoder.Instance, options);
356+
image.DebugSave(provider);
357+
image.CompareToOriginal(provider, ReferenceDecoder);
358+
}
359+
343360
[Theory]
344361
[WithFile(Lossless.LossLessCorruptImage1, PixelTypes.Rgba32)]
345362
[WithFile(Lossless.LossLessCorruptImage2, PixelTypes.Rgba32)]

tests/ImageSharp.Tests/TestImages.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,7 @@ public static class Lossy
677677
public const string WithXmp = "Webp/xmp_lossy.webp";
678678
public const string BikeSmall = "Webp/bike_lossy_small.webp";
679679
public const string Animated = "Webp/leo_animated_lossy.webp";
680+
public const string AnimatedIssue2528 = "Webp/issues/Issue2528.webp";
680681

681682
// Lossy images without macroblock filtering.
682683
public const string BikeWithExif = "Webp/bike_lossy_with_exif.webp";
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:b4aa2ba2e6ef0263b5b657e4d15241d497721a0461250b1d942751812b96de71
3+
size 60214

0 commit comments

Comments
 (0)