Browse Source

Refactor determining chunk types

pull/1552/head
Brian Popow 7 years ago
parent
commit
3c419fcfdc
  1. 16
      src/ImageSharp/Formats/WebP/Vp8LBitReader.cs
  2. 56
      src/ImageSharp/Formats/WebP/WebPChunkType.cs
  3. 101
      src/ImageSharp/Formats/WebP/WebPConstants.cs
  4. 58
      src/ImageSharp/Formats/WebP/WebPDecoderCore.cs

16
src/ImageSharp/Formats/WebP/Vp8LBitReader.cs

@ -15,11 +15,13 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Vp8LBitReader"/> class. /// Initializes a new instance of the <see cref="Vp8LBitReader"/> class.
/// </summary> /// </summary>
/// <param name="stream">The stream to read from.</param> /// <param name="inputStream">The input stream to read from.</param>
public Vp8LBitReader(Stream stream) public Vp8LBitReader(Stream inputStream)
{ {
this.stream = new MemoryStream(); this.stream = new MemoryStream();
stream.CopyTo(this.stream); long inputStreamPos = inputStream.Position;
inputStream.CopyTo(this.stream);
inputStream.Position = inputStreamPos;
this.Offset = 0; this.Offset = 0;
this.Bit = 0; this.Bit = 0;
} }
@ -29,7 +31,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
private int Bit { get; set; } private int Bit { get; set; }
/// <summary> /// <summary>
/// Gets a value indicating whether the offset is inside the stream length. /// Gets a value indicating whether the offset is inside the inputStream length.
/// </summary> /// </summary>
private bool ValidPosition private bool ValidPosition
{ {
@ -40,7 +42,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
} }
/// <summary> /// <summary>
/// Reads a unsigned short value from the stream. The bits of each byte are read in least-significant-bit-first order. /// Reads a unsigned short value from the inputStream. The bits of each byte are read in least-significant-bit-first order.
/// </summary> /// </summary>
/// <param name="count">The number of bits to read (should not exceed 16).</param> /// <param name="count">The number of bits to read (should not exceed 16).</param>
/// <returns>A ushort value.</returns> /// <returns>A ushort value.</returns>
@ -67,7 +69,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
{ {
if (!this.ValidPosition) if (!this.ValidPosition)
{ {
WebPThrowHelper.ThrowImageFormatException("The image stream does not contain enough data"); WebPThrowHelper.ThrowImageFormatException("The image inputStream does not contain enough data");
} }
this.stream.Seek(this.Offset, SeekOrigin.Begin); this.stream.Seek(this.Offset, SeekOrigin.Begin);
@ -79,7 +81,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
} }
/// <summary> /// <summary>
/// Advances the stream by one Bit. /// Advances the inputStream by one Bit.
/// </summary> /// </summary>
public void AdvanceBit() public void AdvanceBit()
{ {

56
src/ImageSharp/Formats/WebP/WebPChunkType.cs

@ -0,0 +1,56 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.WebP
{
/// <summary>
/// Contains a list of different webp chunk types.
/// </summary>
internal enum WebPChunkType : uint
{
/// <summary>
/// Header signaling the use of VP8 video format.
/// </summary>
Vp8 = 0x56503820U,
/// <summary>
/// Header for a extended-VP8 chunk.
/// </summary>
Vp8L = 0x5650384CU,
/// <summary>
/// Header for a extended-VP8 chunk.
/// </summary>
Vp8X = 0x56503858U,
/// <summary>
/// Chunk contains information about the alpha channel.
/// </summary>
Alpha = 0x414C5048U,
/// <summary>
/// Chunk which contains a color profile.
/// </summary>
Iccp = 0x49434350U,
/// <summary>
/// Chunk which contains EXIF metadata about the image.
/// </summary>
Exif = 0x45584946U,
/// <summary>
/// Chunk contains XMP metadata about the image.
/// </summary>
Xmp = 0x584D5020U,
/// <summary>
/// For an animated image, this chunk contains the global parameters of the animation.
/// </summary>
AnimationParameter = 0x414E494D,
/// <summary>
/// For animated images, this chunk contains information about a single frame. If the Animation flag is not set, then this chunk SHOULD NOT be present.
/// </summary>
Animation = 0x414E4D46,
}
}

101
src/ImageSharp/Formats/WebP/WebPConstants.cs

@ -58,106 +58,5 @@ namespace SixLabors.ImageSharp.Formats.WebP
0x42, // B 0x42, // B
0x50 // P 0x50 // P
}; };
/// <summary>
/// Header signaling the use of VP8 video format.
/// </summary>
public static readonly byte[] Vp8Header =
{
0x56, // V
0x50, // P
0x38, // 8
0x20, // Space
};
/// <summary>
/// Header for a extended-VP8 chunk.
/// </summary>
public static readonly byte[] Vp8XHeader =
{
0x56, // V
0x50, // P
0x38, // 8
0x58, // X
};
public static readonly byte LossLessFlag = 0x4C; // L
/// <summary>
/// VP8 header, signaling the use of VP8L lossless format.
/// </summary>
public static readonly byte[] Vp8LHeader =
{
0x56, // V
0x50, // P
0x38, // 8
LossLessFlag // L
};
/// <summary>
/// Chunk contains information about the alpha channel.
/// </summary>
public static readonly byte[] AlphaHeader =
{
0x41, // A
0x4C, // L
0x50, // P
0x48, // H
};
/// <summary>
/// Chunk which contains a color profile.
/// </summary>
public static readonly byte[] IccpHeader =
{
0x49, // I
0x43, // C
0x43, // C
0x50, // P
};
/// <summary>
/// Chunk which contains EXIF metadata about the image.
/// </summary>
public static readonly byte[] ExifHeader =
{
0x45, // E
0x58, // X
0x49, // I
0x46, // F
};
/// <summary>
/// Chunk contains XMP metadata about the image.
/// </summary>
public static readonly byte[] XmpHeader =
{
0x58, // X
0x4D, // M
0x50, // P
0x20, // Space
};
/// <summary>
/// For an animated image, this chunk contains the global parameters of the animation.
/// </summary>
public static readonly byte[] AnimationParameterHeader =
{
0x41, // A
0x4E, // N
0x49, // I
0x4D, // M
};
/// <summary>
/// For animated images, this chunk contains information about a single frame. If the Animation flag is not set, then this chunk SHOULD NOT be present.
/// </summary>
public static readonly byte[] AnimationHeader =
{
0x41, // A
0x4E, // N
0x4D, // M
0x46, // F
};
} }
} }

58
src/ImageSharp/Formats/WebP/WebPDecoderCore.cs

@ -4,7 +4,6 @@
using System; using System;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.IO; using System.IO;
using System.Linq;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata;
@ -74,14 +73,15 @@ namespace SixLabors.ImageSharp.Formats.WebP
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer(); Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
if (imageInfo.IsLossLess) if (imageInfo.IsLossLess)
{ {
ReadSimpleLossless(pixels, image.Width, image.Height); ReadSimpleLossless(pixels, image.Width, image.Height, (int)imageInfo.DataSize);
} }
else else
{ {
ReadSimpleLossy(pixels, image.Width, image.Height); ReadSimpleLossy(pixels, image.Width, image.Height, (int)imageInfo.DataSize);
} }
// TODO: there can be optional chunks after the image data, like EXIF, XMP etc. // TODO: there can be optional chunks after the image data, like EXIF, XMP etc.
this.ParseOptionalChunks();
return image; return image;
} }
@ -123,22 +123,16 @@ namespace SixLabors.ImageSharp.Formats.WebP
private WebPImageInfo ReadVp8Info(int vpxWidth = 0, int vpxHeight = 0) private WebPImageInfo ReadVp8Info(int vpxWidth = 0, int vpxHeight = 0)
{ {
// Read VP8 chunk header. WebPChunkType type = this.ReadChunkType();
this.currentStream.Read(this.buffer, 0, 4);
if (this.buffer.AsSpan().SequenceEqual(WebPConstants.Vp8Header))
{
return this.ReadVp8Header(vpxWidth, vpxHeight);
}
if (this.buffer.AsSpan().SequenceEqual(WebPConstants.Vp8LHeader)) switch (type)
{ {
return this.ReadVp8LHeader(vpxWidth, vpxHeight); case WebPChunkType.Vp8:
} return this.ReadVp8Header(vpxWidth, vpxHeight);
case WebPChunkType.Vp8L:
if (this.buffer.SequenceEqual(WebPConstants.Vp8XHeader)) return this.ReadVp8LHeader(vpxWidth, vpxHeight);
{ case WebPChunkType.Vp8X:
return this.ReadVp8XHeader(); return this.ReadVp8XHeader();
} }
WebPThrowHelper.ThrowImageFormatException("Unrecognized VP8 header"); WebPThrowHelper.ThrowImageFormatException("Unrecognized VP8 header");
@ -185,6 +179,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
int height = BinaryPrimitives.ReadInt32LittleEndian(this.buffer) + 1; int height = BinaryPrimitives.ReadInt32LittleEndian(this.buffer) + 1;
// TODO: optional chunks ICCP and ANIM can follow here. Ignoring them for now. // TODO: optional chunks ICCP and ANIM can follow here. Ignoring them for now.
this.ParseOptionalChunks();
// A VP8 or VP8L chunk will follow here. // A VP8 or VP8L chunk will follow here.
return this.ReadVp8Info(width, height); return this.ReadVp8Info(width, height);
@ -324,16 +319,24 @@ namespace SixLabors.ImageSharp.Formats.WebP
}; };
} }
private void ReadSimpleLossy<TPixel>(Buffer2D<TPixel> pixels, int width, int height) private void ParseOptionalChunks()
{
// Read VP8 chunk header.
this.currentStream.Read(this.buffer, 0, 4);
}
private void ReadSimpleLossy<TPixel>(Buffer2D<TPixel> pixels, int width, int height, int chunkSize)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
// TODO: implement decoding // TODO: implement decoding, for simulating the decoding, skipping the chunk size bytes.
this.currentStream.Skip(chunkSize);
} }
private void ReadSimpleLossless<TPixel>(Buffer2D<TPixel> pixels, int width, int height) private void ReadSimpleLossless<TPixel>(Buffer2D<TPixel> pixels, int width, int height, int chunkSize)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
// TODO: implement decoding // TODO: implement decoding, for simulating the decoding, skipping the chunk size bytes.
this.currentStream.Skip(chunkSize);
} }
private void ReadExtended<TPixel>(Buffer2D<TPixel> pixels, int width, int height) private void ReadExtended<TPixel>(Buffer2D<TPixel> pixels, int width, int height)
@ -341,5 +344,18 @@ namespace SixLabors.ImageSharp.Formats.WebP
{ {
// TODO: implement decoding // TODO: implement decoding
} }
/// <summary>
/// Identifies the chunk type from the chunk.
/// </summary>
/// <exception cref="ImageFormatException">
/// Thrown if the input stream is not valid.
/// </exception>
private WebPChunkType ReadChunkType()
{
return this.currentStream.Read(this.buffer, 0, 4) == 4
? (WebPChunkType)BinaryPrimitives.ReadUInt32BigEndian(this.buffer)
: throw new ImageFormatException("Invalid WebP data.");
}
} }
} }

Loading…
Cancel
Save