diff --git a/src/ImageSharp/Formats/WebP/Vp8LBitReader.cs b/src/ImageSharp/Formats/WebP/Vp8LBitReader.cs index bcde6e74c..39ee78cd6 100644 --- a/src/ImageSharp/Formats/WebP/Vp8LBitReader.cs +++ b/src/ImageSharp/Formats/WebP/Vp8LBitReader.cs @@ -8,15 +8,15 @@ namespace SixLabors.ImageSharp.Formats.WebP /// /// A bit reader for VP8 streams. /// - public class Vp8LBitreader + public class Vp8LBitReader { private readonly Stream stream; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The stream to read from. - public Vp8LBitreader(Stream stream) + public Vp8LBitReader(Stream stream) { this.stream = new MemoryStream(); stream.CopyTo(this.stream); @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Formats.WebP private int Bit { get; set; } /// - /// Check if the offset is inside the stream length. + /// Gets a value indicating whether the offset is inside the stream length. /// private bool ValidPosition { @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Formats.WebP /// True, if the bit is one, otherwise false. public bool ReadBit() { - if (!ValidPosition) + if (!this.ValidPosition) { WebPThrowHelper.ThrowImageFormatException("The image stream does not contain enough data"); } diff --git a/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs b/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs index 72000b8e9..b8bbf7599 100644 --- a/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs +++ b/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs @@ -230,10 +230,70 @@ namespace SixLabors.ImageSharp.Formats.WebP } // The first 28 bits of the bitstream specify the width and height of the image. - var bitReader = new Vp8LBitreader(this.currentStream); + var bitReader = new Vp8LBitReader(this.currentStream); uint width = bitReader.Read(WebPConstants.Vp8LImageSizeBits) + 1; uint height = bitReader.Read(WebPConstants.Vp8LImageSizeBits) + 1; + // The alpha_is_used flag should be set to 0 when all alpha values are 255 in the picture, and 1 otherwise. + bool alphaIsUsed = bitReader.ReadBit(); + + // The next 3 bytes are the version. The version_number is a 3 bit code that must be set to 0. + // Any other value should be treated as an error. + uint version = bitReader.Read(3); + if (version != 0) + { + WebPThrowHelper.ThrowImageFormatException($"Unexpected webp version number: {version}"); + } + + // Next bit indicates, if a transformation is present. + bool transformPresent = bitReader.ReadBit(); + int numberOfTransformsPresent = 0; + while (transformPresent) + { + var transformType = (WebPTransformType)bitReader.Read(2); + switch (transformType) + { + case WebPTransformType.SubtractGreen: + // There is no data associated with this transform. + break; + case WebPTransformType.ColorIndexingTransform: + // The transform data contains color table size and the entries in the color table. + // 8 bit value for color table size. + uint colorTableSize = bitReader.Read(8) + 1; + // TODO: color table should follow here? + break; + + case WebPTransformType.PredictorTransform: + { + // The first 3 bits of prediction data define the block width and height in number of bits. + // The number of block columns, block_xsize, is used in indexing two-dimensionally. + uint sizeBits = bitReader.Read(3) + 2; + int blockWidth = 1 << (int)sizeBits; + int blockHeight = 1 << (int)sizeBits; + + break; + } + + case WebPTransformType.ColorTransform: + { + // The first 3 bits of the color transform data contain the width and height of the image block in number of bits, + // just like the predictor transform: + uint sizeBits = bitReader.Read(3) + 2; + int blockWidth = 1 << (int)sizeBits; + int blockHeight = 1 << (int)sizeBits; + break; + } + } + + numberOfTransformsPresent++; + if (numberOfTransformsPresent == 4) + { + break; + } + + transformPresent = bitReader.ReadBit(); + } + return new WebPImageInfo() { Width = (int)width, diff --git a/src/ImageSharp/Formats/WebP/WebPTransformType.cs b/src/ImageSharp/Formats/WebP/WebPTransformType.cs new file mode 100644 index 000000000..ed6e37e0a --- /dev/null +++ b/src/ImageSharp/Formats/WebP/WebPTransformType.cs @@ -0,0 +1,37 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Formats.WebP +{ + /// + /// Enum for the different transform types. Transformations are reversible manipulations of the image data + /// that can reduce the remaining symbolic entropy by modeling spatial and color correlations. + /// Transformations can make the final compression more dense. + /// + public enum WebPTransformType : uint + { + /// + /// The predictor transform can be used to reduce entropy by exploiting the fact that neighboring pixels are often correlated. + /// + PredictorTransform = 0, + + /// + /// The goal of the color transform is to decorrelate the R, G and B values of each pixel. + /// Color transform keeps the green (G) value as it is, transforms red (R) based on green and transforms blue (B) based on green and then based on red. + /// + ColorTransform = 1, + + /// + /// The subtract green transform subtracts green values from red and blue values of each pixel. + /// When this transform is present, the decoder needs to add the green value to both red and blue. + /// There is no data associated with this transform. + /// + SubtractGreen = 2, + + /// + /// If there are not many unique pixel values, it may be more efficient to create a color index array and replace the pixel values by the array's indices. + /// The color indexing transform achieves this. + /// + ColorIndexingTransform = 3, + } +}