Browse Source

Review changes

pull/1985/head
Brian Popow 4 years ago
parent
commit
2a8418f986
  1. 13
      src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs
  2. 58
      src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs
  3. 2
      src/ImageSharp/Formats/Webp/WebpDecoderCore.cs

13
src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs

@ -192,7 +192,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
this.RestoreToBackground(imageFrame, backgroundColor); this.RestoreToBackground(imageFrame, backgroundColor);
} }
using Image<TPixel> decodedImage = this.DecodeImageData<TPixel>(frameData, webpInfo); using Buffer2D<TPixel> decodedImage = this.DecodeImageData<TPixel>(frameData, webpInfo);
this.DrawDecodedImageOnCanvas(decodedImage, imageFrame, frameX, frameY, frameWidth, frameHeight); this.DrawDecodedImageOnCanvas(decodedImage, imageFrame, frameX, frameY, frameWidth, frameHeight);
if (previousFrame != null && frameData.BlendingMethod is AnimationBlendingMethod.AlphaBlending) if (previousFrame != null && frameData.BlendingMethod is AnimationBlendingMethod.AlphaBlending)
@ -244,7 +244,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
/// <param name="frameData">The frame data.</param> /// <param name="frameData">The frame data.</param>
/// <param name="webpInfo">The webp information.</param> /// <param name="webpInfo">The webp information.</param>
/// <returns>A decoded image.</returns> /// <returns>A decoded image.</returns>
private Image<TPixel> DecodeImageData<TPixel>(AnimationFrameData frameData, WebpImageInfo webpInfo) private Buffer2D<TPixel> DecodeImageData<TPixel>(AnimationFrameData frameData, WebpImageInfo webpInfo)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
var decodedImage = new Image<TPixel>((int)frameData.Width, (int)frameData.Height); var decodedImage = new Image<TPixel>((int)frameData.Width, (int)frameData.Height);
@ -262,6 +262,8 @@ namespace SixLabors.ImageSharp.Formats.Webp
var lossyDecoder = new WebpLossyDecoder(webpInfo.Vp8BitReader, this.memoryAllocator, this.configuration); var lossyDecoder = new WebpLossyDecoder(webpInfo.Vp8BitReader, this.memoryAllocator, this.configuration);
lossyDecoder.Decode(pixelBufferDecoded, (int)webpInfo.Width, (int)webpInfo.Height, webpInfo, this.AlphaData); lossyDecoder.Decode(pixelBufferDecoded, (int)webpInfo.Width, (int)webpInfo.Height, webpInfo, this.AlphaData);
} }
return pixelBufferDecoded;
} }
catch catch
{ {
@ -272,8 +274,6 @@ namespace SixLabors.ImageSharp.Formats.Webp
{ {
webpInfo.Dispose(); webpInfo.Dispose();
} }
return decodedImage;
} }
/// <summary> /// <summary>
@ -286,16 +286,15 @@ namespace SixLabors.ImageSharp.Formats.Webp
/// <param name="frameY">The frame y coordinate.</param> /// <param name="frameY">The frame y coordinate.</param>
/// <param name="frameWidth">The width of the frame.</param> /// <param name="frameWidth">The width of the frame.</param>
/// <param name="frameHeight">The height of the frame.</param> /// <param name="frameHeight">The height of the frame.</param>
private void DrawDecodedImageOnCanvas<TPixel>(Image<TPixel> decodedImage, ImageFrame<TPixel> imageFrame, int frameX, int frameY, int frameWidth, int frameHeight) private void DrawDecodedImageOnCanvas<TPixel>(Buffer2D<TPixel> decodedImage, ImageFrame<TPixel> imageFrame, int frameX, int frameY, int frameWidth, int frameHeight)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
Buffer2D<TPixel> decodedImagePixels = decodedImage.Frames.RootFrame.PixelBuffer;
Buffer2D<TPixel> imageFramePixels = imageFrame.PixelBuffer; Buffer2D<TPixel> imageFramePixels = imageFrame.PixelBuffer;
int decodedRowIdx = 0; int decodedRowIdx = 0;
for (int y = frameY; y < frameY + frameHeight; y++) for (int y = frameY; y < frameY + frameHeight; y++)
{ {
Span<TPixel> framePixelRow = imageFramePixels.DangerousGetRowSpan(y); Span<TPixel> framePixelRow = imageFramePixels.DangerousGetRowSpan(y);
Span<TPixel> decodedPixelRow = decodedImagePixels.DangerousGetRowSpan(decodedRowIdx++).Slice(0, frameWidth); Span<TPixel> decodedPixelRow = decodedImage.DangerousGetRowSpan(decodedRowIdx++).Slice(0, frameWidth);
decodedPixelRow.TryCopyTo(framePixelRow.Slice(frameX)); decodedPixelRow.TryCopyTo(framePixelRow.Slice(frameX));
} }
} }

58
src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs

@ -3,9 +3,9 @@
using System; using System;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.IO;
using SixLabors.ImageSharp.Formats.Webp.BitReader; using SixLabors.ImageSharp.Formats.Webp.BitReader;
using SixLabors.ImageSharp.Formats.Webp.Lossy; using SixLabors.ImageSharp.Formats.Webp.Lossy;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Exif;
@ -19,10 +19,15 @@ namespace SixLabors.ImageSharp.Formats.Webp
/// Reads the header of a lossy webp image. /// Reads the header of a lossy webp image.
/// </summary> /// </summary>
/// <returns>Information about this webp image.</returns> /// <returns>Information about this webp image.</returns>
public static WebpImageInfo ReadVp8Header(MemoryAllocator memoryAllocator, Stream stream, byte[] buffer, WebpFeatures features) public static WebpImageInfo ReadVp8Header(MemoryAllocator memoryAllocator, BufferedReadStream stream, byte[] buffer, WebpFeatures features)
{ {
// VP8 data size (not including this 4 bytes). // VP8 data size (not including this 4 bytes).
stream.Read(buffer, 0, 4); int bytesRead = stream.Read(buffer, 0, 4);
if (bytesRead != 4)
{
WebpThrowHelper.ThrowInvalidImageContentException("Not enough data to read the VP8 header");
}
uint dataSize = BinaryPrimitives.ReadUInt32LittleEndian(buffer); uint dataSize = BinaryPrimitives.ReadUInt32LittleEndian(buffer);
// Remaining counts the available image data payload. // Remaining counts the available image data payload.
@ -34,7 +39,12 @@ namespace SixLabors.ImageSharp.Formats.Webp
// - A 3-bit version number. // - A 3-bit version number.
// - A 1-bit show_frame flag. // - A 1-bit show_frame flag.
// - A 19-bit field containing the size of the first data partition in bytes. // - A 19-bit field containing the size of the first data partition in bytes.
stream.Read(buffer, 0, 3); bytesRead = stream.Read(buffer, 0, 3);
if (bytesRead != 3)
{
WebpThrowHelper.ThrowInvalidImageContentException("Not enough data to read the VP8 header");
}
uint frameTag = (uint)(buffer[0] | (buffer[1] << 8) | (buffer[2] << 16)); uint frameTag = (uint)(buffer[0] | (buffer[1] << 8) | (buffer[2] << 16));
remaining -= 3; remaining -= 3;
bool isNoKeyFrame = (frameTag & 0x1) == 1; bool isNoKeyFrame = (frameTag & 0x1) == 1;
@ -62,17 +72,27 @@ namespace SixLabors.ImageSharp.Formats.Webp
} }
// Check for VP8 magic bytes. // Check for VP8 magic bytes.
stream.Read(buffer, 0, 3); bytesRead = stream.Read(buffer, 0, 3);
if (bytesRead != 3)
{
WebpThrowHelper.ThrowInvalidImageContentException("Not enough data to read the VP8 magic bytes");
}
if (!buffer.AsSpan(0, 3).SequenceEqual(WebpConstants.Vp8HeaderMagicBytes)) if (!buffer.AsSpan(0, 3).SequenceEqual(WebpConstants.Vp8HeaderMagicBytes))
{ {
WebpThrowHelper.ThrowImageFormatException("VP8 magic bytes not found"); WebpThrowHelper.ThrowImageFormatException("VP8 magic bytes not found");
} }
stream.Read(buffer, 0, 4); bytesRead = stream.Read(buffer, 0, 4);
uint tmp = (uint)BinaryPrimitives.ReadInt16LittleEndian(buffer); if (bytesRead != 4)
{
WebpThrowHelper.ThrowInvalidImageContentException("Not enough data to read the VP8 header, could not read width and height");
}
uint tmp = BinaryPrimitives.ReadUInt16LittleEndian(buffer);
uint width = tmp & 0x3fff; uint width = tmp & 0x3fff;
sbyte xScale = (sbyte)(tmp >> 6); sbyte xScale = (sbyte)(tmp >> 6);
tmp = (uint)BinaryPrimitives.ReadInt16LittleEndian(buffer.AsSpan(2)); tmp = BinaryPrimitives.ReadUInt16LittleEndian(buffer.AsSpan(2));
uint height = tmp & 0x3fff; uint height = tmp & 0x3fff;
sbyte yScale = (sbyte)(tmp >> 6); sbyte yScale = (sbyte)(tmp >> 6);
remaining -= 7; remaining -= 7;
@ -121,7 +141,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
/// Reads the header of a lossless webp image. /// Reads the header of a lossless webp image.
/// </summary> /// </summary>
/// <returns>Information about this image.</returns> /// <returns>Information about this image.</returns>
public static WebpImageInfo ReadVp8LHeader(MemoryAllocator memoryAllocator, Stream stream, byte[] buffer, WebpFeatures features) public static WebpImageInfo ReadVp8LHeader(MemoryAllocator memoryAllocator, BufferedReadStream stream, byte[] buffer, WebpFeatures features)
{ {
// VP8 data size. // VP8 data size.
uint imageDataSize = ReadChunkSize(stream, buffer); uint imageDataSize = ReadChunkSize(stream, buffer);
@ -176,7 +196,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
/// After the image header, image data will follow. After that optional image metadata chunks (EXIF and XMP) can follow. /// After the image header, image data will follow. After that optional image metadata chunks (EXIF and XMP) can follow.
/// </summary> /// </summary>
/// <returns>Information about this webp image.</returns> /// <returns>Information about this webp image.</returns>
public static WebpImageInfo ReadVp8XHeader(Stream stream, byte[] buffer, WebpFeatures features) public static WebpImageInfo ReadVp8XHeader(BufferedReadStream stream, byte[] buffer, WebpFeatures features)
{ {
uint fileSize = ReadChunkSize(stream, buffer); uint fileSize = ReadChunkSize(stream, buffer);
@ -234,11 +254,15 @@ namespace SixLabors.ImageSharp.Formats.Webp
/// <param name="stream">The stream to read from.</param> /// <param name="stream">The stream to read from.</param>
/// <param name="buffer">The buffer to store the read data into.</param> /// <param name="buffer">The buffer to store the read data into.</param>
/// <returns>A unsigned 24 bit integer.</returns> /// <returns>A unsigned 24 bit integer.</returns>
public static uint ReadUnsignedInt24Bit(Stream stream, byte[] buffer) public static uint ReadUnsignedInt24Bit(BufferedReadStream stream, byte[] buffer)
{ {
stream.Read(buffer, 0, 3); if (stream.Read(buffer, 0, 3) == 3)
buffer[3] = 0; {
return (uint)BinaryPrimitives.ReadInt32LittleEndian(buffer); buffer[3] = 0;
return BinaryPrimitives.ReadUInt32LittleEndian(buffer);
}
throw new ImageFormatException("Invalid Webp data, could not read unsigned integer.");
} }
/// <summary> /// <summary>
@ -248,7 +272,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
/// <param name="stream">The stream to read the data from.</param> /// <param name="stream">The stream to read the data from.</param>
/// <param name="buffer">Buffer to store the data read from the stream.</param> /// <param name="buffer">Buffer to store the data read from the stream.</param>
/// <returns>The chunk size in bytes.</returns> /// <returns>The chunk size in bytes.</returns>
public static uint ReadChunkSize(Stream stream, byte[] buffer) public static uint ReadChunkSize(BufferedReadStream stream, byte[] buffer)
{ {
if (stream.Read(buffer, 0, 4) == 4) if (stream.Read(buffer, 0, 4) == 4)
{ {
@ -267,7 +291,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
/// <exception cref="ImageFormatException"> /// <exception cref="ImageFormatException">
/// Thrown if the input stream is not valid. /// Thrown if the input stream is not valid.
/// </exception> /// </exception>
public static WebpChunkType ReadChunkType(Stream stream, byte[] buffer) public static WebpChunkType ReadChunkType(BufferedReadStream stream, byte[] buffer)
{ {
if (stream.Read(buffer, 0, 4) == 4) if (stream.Read(buffer, 0, 4) == 4)
{ {
@ -283,7 +307,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
/// If there are more such chunks, readers MAY ignore all except the first one. /// If there are more such chunks, readers MAY ignore all except the first one.
/// Also, a file may possibly contain both 'EXIF' and 'XMP ' chunks. /// Also, a file may possibly contain both 'EXIF' and 'XMP ' chunks.
/// </summary> /// </summary>
public static void ParseOptionalChunks(Stream stream, WebpChunkType chunkType, ImageMetadata metadata, bool ignoreMetaData, byte[] buffer) public static void ParseOptionalChunks(BufferedReadStream stream, WebpChunkType chunkType, ImageMetadata metadata, bool ignoreMetaData, byte[] buffer)
{ {
long streamLength = stream.Length; long streamLength = stream.Length;
while (stream.Position < streamLength) while (stream.Position < streamLength)

2
src/ImageSharp/Formats/Webp/WebpDecoderCore.cs

@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
/// <summary> /// <summary>
/// The stream to decode from. /// The stream to decode from.
/// </summary> /// </summary>
private Stream currentStream; private BufferedReadStream currentStream;
/// <summary> /// <summary>
/// The webp specific metadata. /// The webp specific metadata.

Loading…
Cancel
Save