Browse Source

Add webp decoder option BackgroundColorHandling to decide howto handle the background color in the ANIM chunk

pull/2547/head
Brian Popow 3 years ago
parent
commit
a80ae33e4c
  1. 2
      src/ImageSharp/Formats/Tiff/Compression/Decompressors/WebpTiffCompression.cs
  2. 1
      src/ImageSharp/Formats/Tiff/Compression/TiffDecompressorsFactory.cs
  3. 21
      src/ImageSharp/Formats/Webp/BackgroundColorHandling.cs
  4. 14
      src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs
  5. 18
      src/ImageSharp/Formats/Webp/WebpDecoder.cs
  6. 18
      src/ImageSharp/Formats/Webp/WebpDecoderCore.cs
  7. 21
      src/ImageSharp/Formats/Webp/WebpDecoderOptions.cs

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

@ -32,7 +32,7 @@ internal class WebpTiffCompression : TiffBaseDecompressor
/// <inheritdoc/> /// <inheritdoc/>
protected override void Decompress(BufferedReadStream stream, int byteCount, int stripHeight, Span<byte> buffer, CancellationToken cancellationToken) protected override void Decompress(BufferedReadStream stream, int byteCount, int stripHeight, Span<byte> buffer, CancellationToken cancellationToken)
{ {
using WebpDecoderCore decoder = new(this.options); using WebpDecoderCore decoder = new(new WebpDecoderOptions());
using Image<Rgb24> image = decoder.Decode<Rgb24>(stream, cancellationToken); using Image<Rgb24> image = decoder.Decode<Rgb24>(stream, cancellationToken);
CopyImageBytesToBuffer(buffer, image.Frames.RootFrame.PixelBuffer); CopyImageBytesToBuffer(buffer, image.Frames.RootFrame.PixelBuffer);
} }

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

@ -4,6 +4,7 @@
using SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors; using SixLabors.ImageSharp.Formats.Tiff.Compression.Decompressors;
using SixLabors.ImageSharp.Formats.Tiff.Constants; using SixLabors.ImageSharp.Formats.Tiff.Constants;
using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; using SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Tiff.Compression; namespace SixLabors.ImageSharp.Formats.Tiff.Compression;

21
src/ImageSharp/Formats/Webp/BackgroundColorHandling.cs

@ -0,0 +1,21 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Webp;
/// <summary>
/// Enum to decide how to handle the background color of the Animation chunk during decoding.
/// </summary>
public enum BackgroundColorHandling
{
/// <summary>
/// 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.
/// Also, if AnimationDisposalMethod.Dispose is used, this color will be used to restore the canvas background.
/// </summary>
Standard = 0,
/// <summary>
/// The background color of the ANIM chunk is ignored and instead the canvas is initialized with black, BGRA(0, 0, 0, 0).
/// </summary>
Ignore = 1
}

14
src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs

@ -52,17 +52,24 @@ internal class WebpAnimationDecoder : IDisposable
/// </summary> /// </summary>
private IMemoryOwner<byte>? alphaData; private IMemoryOwner<byte>? alphaData;
/// <summary>
/// The flag to decide how to handle the background color in the Animation Chunk.
/// </summary>
private readonly BackgroundColorHandling backgroundColorHandling;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WebpAnimationDecoder"/> class. /// Initializes a new instance of the <see cref="WebpAnimationDecoder"/> class.
/// </summary> /// </summary>
/// <param name="memoryAllocator">The memory allocator.</param> /// <param name="memoryAllocator">The memory allocator.</param>
/// <param name="configuration">The global configuration.</param> /// <param name="configuration">The global configuration.</param>
/// <param name="maxFrames">The maximum number of frames to decode. Inclusive.</param> /// <param name="maxFrames">The maximum number of frames to decode. Inclusive.</param>
public WebpAnimationDecoder(MemoryAllocator memoryAllocator, Configuration configuration, uint maxFrames) /// <param name="backgroundColorHandling">The flag to decide how to handle the background color in the Animation Chunk.</param>
public WebpAnimationDecoder(MemoryAllocator memoryAllocator, Configuration configuration, uint maxFrames, BackgroundColorHandling backgroundColorHandling)
{ {
this.memoryAllocator = memoryAllocator; this.memoryAllocator = memoryAllocator;
this.configuration = configuration; this.configuration = configuration;
this.maxFrames = maxFrames; this.maxFrames = maxFrames;
this.backgroundColorHandling = backgroundColorHandling;
} }
/// <summary> /// <summary>
@ -94,7 +101,10 @@ internal class WebpAnimationDecoder : IDisposable
switch (chunkType) switch (chunkType)
{ {
case WebpChunkType.Animation: case WebpChunkType.Animation:
uint dataSize = this.ReadFrame(stream, ref image, ref previousFrame, width, height, features.AnimationBackgroundColor!.Value); Color backgroundColor = this.backgroundColorHandling == BackgroundColorHandling.Ignore
? new Color(new Bgra32(0, 0, 0, 0))
: features.AnimationBackgroundColor!.Value;
uint dataSize = this.ReadFrame(stream, ref image, ref previousFrame, width, height, backgroundColor);
remainingBytes -= (int)dataSize; remainingBytes -= (int)dataSize;
break; break;
case WebpChunkType.Xmp: case WebpChunkType.Xmp:

18
src/ImageSharp/Formats/Webp/WebpDecoder.cs

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Formats.Webp;
/// <summary> /// <summary>
/// Image decoder for generating an image out of a webp stream. /// Image decoder for generating an image out of a webp stream.
/// </summary> /// </summary>
public sealed class WebpDecoder : ImageDecoder public sealed class WebpDecoder : SpecializedImageDecoder<WebpDecoderOptions>
{ {
private WebpDecoder() private WebpDecoder()
{ {
@ -25,25 +25,33 @@ public sealed class WebpDecoder : ImageDecoder
Guard.NotNull(options, nameof(options)); Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream)); Guard.NotNull(stream, nameof(stream));
using WebpDecoderCore decoder = new(options); using WebpDecoderCore decoder = new(new WebpDecoderOptions() { GeneralOptions = options });
return decoder.Identify(options.Configuration, stream, cancellationToken); return decoder.Identify(options.Configuration, stream, cancellationToken);
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override Image<TPixel> Decode<TPixel>(DecoderOptions options, Stream stream, CancellationToken cancellationToken) protected override Image<TPixel> Decode<TPixel>(WebpDecoderOptions options, Stream stream, CancellationToken cancellationToken)
{ {
Guard.NotNull(options, nameof(options)); Guard.NotNull(options, nameof(options));
Guard.NotNull(stream, nameof(stream)); Guard.NotNull(stream, nameof(stream));
using WebpDecoderCore decoder = new(options); using WebpDecoderCore decoder = new(options);
Image<TPixel> image = decoder.Decode<TPixel>(options.Configuration, stream, cancellationToken); Image<TPixel> image = decoder.Decode<TPixel>(options.GeneralOptions.Configuration, stream, cancellationToken);
ScaleToTargetSize(options, image); ScaleToTargetSize(options.GeneralOptions, image);
return image; return image;
} }
/// <inheritdoc/>
protected override Image Decode(WebpDecoderOptions options, Stream stream, CancellationToken cancellationToken)
=> this.Decode<Rgba32>(options, stream, cancellationToken);
/// <inheritdoc/> /// <inheritdoc/>
protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken) protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
=> this.Decode<Rgba32>(options, stream, cancellationToken); => this.Decode<Rgba32>(options, stream, cancellationToken);
/// <inheritdoc/>
protected override WebpDecoderOptions CreateDefaultSpecializedOptions(DecoderOptions options)
=> new() { GeneralOptions = options };
} }

18
src/ImageSharp/Formats/Webp/WebpDecoderCore.cs

@ -48,16 +48,22 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable
/// </summary> /// </summary>
private WebpImageInfo? webImageInfo; private WebpImageInfo? webImageInfo;
/// <summary>
/// The flag to decide how to handle the background color in the Animation Chunk.
/// </summary>
private BackgroundColorHandling backgroundColorHandling;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WebpDecoderCore"/> class. /// Initializes a new instance of the <see cref="WebpDecoderCore"/> class.
/// </summary> /// </summary>
/// <param name="options">The decoder options.</param> /// <param name="options">The decoder options.</param>
public WebpDecoderCore(DecoderOptions options) public WebpDecoderCore(WebpDecoderOptions options)
{ {
this.Options = options; this.Options = options.GeneralOptions;
this.configuration = options.Configuration; this.backgroundColorHandling = options.BackgroundColorHandling;
this.skipMetadata = options.SkipMetadata; this.configuration = options.GeneralOptions.Configuration;
this.maxFrames = options.MaxFrames; this.skipMetadata = options.GeneralOptions.SkipMetadata;
this.maxFrames = options.GeneralOptions.MaxFrames;
this.memoryAllocator = this.configuration.MemoryAllocator; this.memoryAllocator = this.configuration.MemoryAllocator;
} }
@ -83,7 +89,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable
{ {
if (this.webImageInfo.Features is { Animation: true }) if (this.webImageInfo.Features is { Animation: true })
{ {
using WebpAnimationDecoder animationDecoder = new(this.memoryAllocator, this.configuration, this.maxFrames); using WebpAnimationDecoder animationDecoder = new(this.memoryAllocator, this.configuration, this.maxFrames, this.backgroundColorHandling);
return animationDecoder.Decode<TPixel>(stream, this.webImageInfo.Features, this.webImageInfo.Width, this.webImageInfo.Height, fileSize); return animationDecoder.Decode<TPixel>(stream, this.webImageInfo.Features, this.webImageInfo.Width, this.webImageInfo.Height, fileSize);
} }

21
src/ImageSharp/Formats/Webp/WebpDecoderOptions.cs

@ -0,0 +1,21 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Webp;
/// <summary>
/// Configuration options for decoding webp images.
/// </summary>
public sealed class WebpDecoderOptions : ISpecializedDecoderOptions
{
/// <inheritdoc/>
public DecoderOptions GeneralOptions { get; init; } = new();
/// <summary>
/// Gets the flag to decide how to handle the background color Animation Chunk.
/// The specification is vague on how to handle the background color of the animation chunk.
/// This option let's the user choose how to deal with it.
/// </summary>
/// <see href="https://developers.google.com/speed/webp/docs/riff_container#animation"/>
public BackgroundColorHandling BackgroundColorHandling { get; init; } = BackgroundColorHandling.Standard;
}
Loading…
Cancel
Save