diff --git a/src/ImageSharp/Formats/WebP/Vp8LBitReader.cs b/src/ImageSharp/Formats/WebP/Vp8LBitReader.cs new file mode 100644 index 000000000..bcde6e74c --- /dev/null +++ b/src/ImageSharp/Formats/WebP/Vp8LBitReader.cs @@ -0,0 +1,93 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.IO; + +namespace SixLabors.ImageSharp.Formats.WebP +{ + /// + /// A bit reader for VP8 streams. + /// + public class Vp8LBitreader + { + private readonly Stream stream; + + /// + /// Initializes a new instance of the class. + /// + /// The stream to read from. + public Vp8LBitreader(Stream stream) + { + this.stream = new MemoryStream(); + stream.CopyTo(this.stream); + this.Offset = 0; + this.Bit = 0; + } + + private long Offset { get; set; } + + private int Bit { get; set; } + + /// + /// Check if the offset is inside the stream length. + /// + private bool ValidPosition + { + get + { + return this.Offset < this.stream.Length; + } + } + + /// + /// Reads a unsigned short value from the stream. The bits of each byte are read in least-significant-bit-first order. + /// + /// The number of bits to read (should not exceed 16). + /// A ushort value. + public uint Read(int count) + { + uint readValue = 0; + for (int bitPos = 0; bitPos < count; bitPos++) + { + bool bitRead = this.ReadBit(); + if (bitRead) + { + readValue = (uint)(readValue | (1 << bitPos)); + } + } + + return readValue; + } + + /// + /// Reads one bit. + /// + /// True, if the bit is one, otherwise false. + public bool ReadBit() + { + if (!ValidPosition) + { + WebPThrowHelper.ThrowImageFormatException("The image stream does not contain enough data"); + } + + this.stream.Seek(this.Offset, SeekOrigin.Begin); + byte value = (byte)((this.stream.ReadByte() >> this.Bit) & 1); + this.AdvanceBit(); + this.stream.Seek(this.Offset, SeekOrigin.Begin); + + return value == 1; + } + + /// + /// Advances the stream by one Bit. + /// + public void AdvanceBit() + { + this.Bit = (this.Bit + 1) % 8; + if (this.Bit == 0) + { + this.Offset++; + } + } + } +} diff --git a/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs b/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs index 49871d005..769c1a1ca 100644 --- a/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs +++ b/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs @@ -230,15 +230,14 @@ namespace SixLabors.ImageSharp.Formats.WebP } // The first 28 bits of the bitstream specify the width and height of the image. - this.currentStream.Read(this.buffer, 0, 4); - // TODO: A bitreader should be used from here on which reads least-significant-bit-first - int height = 0; - int width = 0; + var bitReader = new Vp8LBitreader(this.currentStream); + uint height = bitReader.Read(WebPConstants.Vp8LImageSizeBits) + 1; + uint width = bitReader.Read(WebPConstants.Vp8LImageSizeBits) + 1; return new WebPImageInfo() { - Width = width, - Height = height, + Width = (int)width, + Height = (int)height, IsLossLess = true, DataSize = dataSize };