Browse Source

Add reading of VP8X header

pull/1552/head
Brian Popow 7 years ago
parent
commit
0392d0ea87
  1. 2
      src/ImageSharp/Formats/WebP/Readme.md
  2. 31
      src/ImageSharp/Formats/WebP/Vp8HeaderType.cs
  3. 2
      src/ImageSharp/Formats/WebP/WebPConstants.cs
  4. 65
      src/ImageSharp/Formats/WebP/WebPDecoderCore.cs
  5. 4
      src/ImageSharp/Formats/WebP/WebPImageInfo.cs

2
src/ImageSharp/Formats/WebP/Readme.md

@ -3,6 +3,6 @@
Reference implementation, specification and stuff like that:
- [google webp introduction](https://developers.google.com/speed/webp)
- [WebP Spec 0.2](https://chromium.googlesource.com/webm/libwebp/+/v0.2.0/doc/webp-container-spec.txt)
- [WebP Spec 1.0.3](https://chromium.googlesource.com/webm/libwebp/+/v1.0.3/doc/webp-container-spec.txt)
- [WebP VP8 chunk Spec](http://tools.ietf.org/html/rfc6386)
- [WebP filefront](https://wiki.fileformat.com/image/webp/)

31
src/ImageSharp/Formats/WebP/Vp8HeaderType.cs

@ -0,0 +1,31 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.WebP
{
/// <summary>
/// Enum for the different VP8 chunk header types.
/// </summary>
public enum Vp8HeaderType
{
/// <summary>
/// Invalid VP8 header.
/// </summary>
Invalid = 0,
/// <summary>
/// A VP8 header.
/// </summary>
Vp8 = 1,
/// <summary>
/// VP8 header, signaling the use of VP8L lossless format.
/// </summary>
Vp8L = 2,
/// <summary>
/// Header for a extended-VP8 chunk.
/// </summary>
Vp8X = 3,
}
}

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

@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
0x56, // V
0x50, // P
0x38, // 8
0x88, // X
0x58, // X
};
public static readonly byte LossLessFlag = 0x4C; // L

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

@ -4,6 +4,7 @@
using System;
using System.Buffers.Binary;
using System.IO;
using System.Linq;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
@ -108,6 +109,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
this.currentStream.Skip(4);
// Read Chunk size.
// The size of the file in bytes starting at offset 8.
// The file size in the header is the total size of the chunks that follow plus 4 bytes for the ‘WEBP’ FourCC.
this.currentStream.Read(this.buffer, 0, 4);
uint chunkSize = BinaryPrimitives.ReadUInt32LittleEndian(this.buffer);
@ -126,19 +129,57 @@ namespace SixLabors.ImageSharp.Formats.WebP
WebPThrowHelper.ThrowImageFormatException("Alpha channel is not yet supported");
}
if (this.buffer.AsSpan().SequenceEqual(WebPConstants.Vp8XHeader))
var vp8HeaderType = Vp8HeaderType.Invalid;
if (this.buffer.AsSpan().SequenceEqual(WebPConstants.Vp8Header))
{
WebPThrowHelper.ThrowImageFormatException("Vp8X is not yet supported");
vp8HeaderType = Vp8HeaderType.Vp8;
}
if (!(this.buffer.AsSpan().SequenceEqual(WebPConstants.Vp8Header)
|| this.buffer.AsSpan().SequenceEqual(WebPConstants.Vp8LHeader)))
else if (this.buffer.AsSpan().SequenceEqual(WebPConstants.Vp8LHeader))
{
vp8HeaderType = Vp8HeaderType.Vp8L;
}
else if (this.buffer.SequenceEqual(WebPConstants.Vp8XHeader))
{
vp8HeaderType = Vp8HeaderType.Vp8X;
}
else
{
WebPThrowHelper.ThrowImageFormatException("Unrecognized VP8 header");
}
bool isLossLess = this.buffer[3] == WebPConstants.LossLessFlag;
return vp8HeaderType == Vp8HeaderType.Vp8X ? this.ReadVp8XHeader() : this.ReadVp8Header(vp8HeaderType);
}
private WebPImageInfo ReadVp8XHeader()
{
this.currentStream.Read(this.buffer, 0, 4);
uint chunkSize = BinaryPrimitives.ReadUInt32LittleEndian(this.buffer);
byte imageFeatures = (byte)this.currentStream.ReadByte();
// 3 reserved bytes should follow which are supposed to be zero.
this.currentStream.Read(this.buffer, 0, 3);
// 3 bytes for the width.
this.currentStream.Read(this.buffer, 0, 3);
this.buffer[3] = 0;
int width = BinaryPrimitives.ReadInt32LittleEndian(this.buffer) + 1;
// 3 bytes for the height.
this.currentStream.Read(this.buffer, 0, 3);
this.buffer[3] = 0;
int height = BinaryPrimitives.ReadInt32LittleEndian(this.buffer) + 1;
return new WebPImageInfo()
{
Width = width,
Height = height,
IsLossLess = false, // note: this is maybe incorrect here
};
}
private WebPImageInfo ReadVp8Header(Vp8HeaderType vp8HeaderType)
{
// VP8 data size.
this.currentStream.Read(this.buffer, 0, 3);
this.buffer[3] = 0;
@ -157,13 +198,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
int height = BinaryPrimitives.ReadInt16LittleEndian(imageInfo.AsSpan(9)) & 0x3fff;
return new WebPImageInfo()
{
Width = width,
Height = height,
IsLossLess = isLossLess,
Version = version,
DataSize = dataSize
};
{
Width = width,
Height = height,
IsLossLess = vp8HeaderType == Vp8HeaderType.Vp8L,
};
}
private void ReadSimpleLossy<TPixel>(Buffer2D<TPixel> pixels, int width, int height)

4
src/ImageSharp/Formats/WebP/WebPImageInfo.cs

@ -19,9 +19,5 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// Gets or sets whether this image uses a lossless compression.
/// </summary>
public bool IsLossLess { get; set; }
public int Version { get; set; }
public uint DataSize { get; set; }
}
}

Loading…
Cancel
Save