Browse Source

Refactor determining chunk types

pull/1552/head
Brian Popow 6 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>
/// Initializes a new instance of the <see cref="Vp8LBitReader"/> class.
/// </summary>
/// <param name="stream">The stream to read from.</param>
public Vp8LBitReader(Stream stream)
/// <param name="inputStream">The input stream to read from.</param>
public Vp8LBitReader(Stream inputStream)
{
this.stream = new MemoryStream();
stream.CopyTo(this.stream);
long inputStreamPos = inputStream.Position;
inputStream.CopyTo(this.stream);
inputStream.Position = inputStreamPos;
this.Offset = 0;
this.Bit = 0;
}
@ -29,7 +31,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
private int Bit { get; set; }
/// <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>
private bool ValidPosition
{
@ -40,7 +42,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
/// <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>
/// <param name="count">The number of bits to read (should not exceed 16).</param>
/// <returns>A ushort value.</returns>
@ -67,7 +69,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
{
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);
@ -79,7 +81,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
/// <summary>
/// Advances the stream by one Bit.
/// Advances the inputStream by one Bit.
/// </summary>
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
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.Buffers.Binary;
using System.IO;
using System.Linq;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
@ -74,14 +73,15 @@ namespace SixLabors.ImageSharp.Formats.WebP
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
if (imageInfo.IsLossLess)
{
ReadSimpleLossless(pixels, image.Width, image.Height);
ReadSimpleLossless(pixels, image.Width, image.Height, (int)imageInfo.DataSize);
}
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.
this.ParseOptionalChunks();
return image;
}
@ -123,22 +123,16 @@ namespace SixLabors.ImageSharp.Formats.WebP
private WebPImageInfo ReadVp8Info(int vpxWidth = 0, int vpxHeight = 0)
{
// Read VP8 chunk header.
this.currentStream.Read(this.buffer, 0, 4);
if (this.buffer.AsSpan().SequenceEqual(WebPConstants.Vp8Header))
{
return this.ReadVp8Header(vpxWidth, vpxHeight);
}
WebPChunkType type = this.ReadChunkType();
if (this.buffer.AsSpan().SequenceEqual(WebPConstants.Vp8LHeader))
switch (type)
{
return this.ReadVp8LHeader(vpxWidth, vpxHeight);
}
if (this.buffer.SequenceEqual(WebPConstants.Vp8XHeader))
{
return this.ReadVp8XHeader();
case WebPChunkType.Vp8:
return this.ReadVp8Header(vpxWidth, vpxHeight);
case WebPChunkType.Vp8L:
return this.ReadVp8LHeader(vpxWidth, vpxHeight);
case WebPChunkType.Vp8X:
return this.ReadVp8XHeader();
}
WebPThrowHelper.ThrowImageFormatException("Unrecognized VP8 header");
@ -185,6 +179,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
int height = BinaryPrimitives.ReadInt32LittleEndian(this.buffer) + 1;
// TODO: optional chunks ICCP and ANIM can follow here. Ignoring them for now.
this.ParseOptionalChunks();
// A VP8 or VP8L chunk will follow here.
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>
{
// 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>
{
// 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)
@ -341,5 +344,18 @@ namespace SixLabors.ImageSharp.Formats.WebP
{
// 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