diff --git a/src/ImageSharp/Formats/WebP/Readme.md b/src/ImageSharp/Formats/WebP/Readme.md
index 41409f1369..664df5043e 100644
--- a/src/ImageSharp/Formats/WebP/Readme.md
+++ b/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/)
diff --git a/src/ImageSharp/Formats/WebP/Vp8HeaderType.cs b/src/ImageSharp/Formats/WebP/Vp8HeaderType.cs
new file mode 100644
index 0000000000..18e311da3b
--- /dev/null
+++ b/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
+{
+ ///
+ /// Enum for the different VP8 chunk header types.
+ ///
+ public enum Vp8HeaderType
+ {
+ ///
+ /// Invalid VP8 header.
+ ///
+ Invalid = 0,
+
+ ///
+ /// A VP8 header.
+ ///
+ Vp8 = 1,
+
+ ///
+ /// VP8 header, signaling the use of VP8L lossless format.
+ ///
+ Vp8L = 2,
+
+ ///
+ /// Header for a extended-VP8 chunk.
+ ///
+ Vp8X = 3,
+ }
+}
diff --git a/src/ImageSharp/Formats/WebP/WebPConstants.cs b/src/ImageSharp/Formats/WebP/WebPConstants.cs
index e1f0fd23d3..bdc026937b 100644
--- a/src/ImageSharp/Formats/WebP/WebPConstants.cs
+++ b/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
diff --git a/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs b/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs
index d4d7503c59..5c5c5d3aca 100644
--- a/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs
+++ b/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(Buffer2D pixels, int width, int height)
diff --git a/src/ImageSharp/Formats/WebP/WebPImageInfo.cs b/src/ImageSharp/Formats/WebP/WebPImageInfo.cs
index 1cf98865c0..065e5dd7e3 100644
--- a/src/ImageSharp/Formats/WebP/WebPImageInfo.cs
+++ b/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.
///
public bool IsLossLess { get; set; }
-
- public int Version { get; set; }
-
- public uint DataSize { get; set; }
}
}