Skip to content

Image.Load cannot load webp with extra meta bytes #2925

Closed
@xqiu

Description

@xqiu

Prerequisites

  • I have written a descriptive issue title
  • I have verified that I am running the latest version of ImageSharp
  • I have verified if the problem exist in both DEBUG and RELEASE mode
  • I have searched open and closed issues to ensure it has not already been reported

ImageSharp version

3.1.8

Other ImageSharp packages and versions

latest

Environment (Operating system, version and so on)

win

.NET Framework version

core 8.0

Description

My client gives me a webp file (might be saved from adobe programs) that image sharp cannot read. Turns it out it have extra meta bytes after the valid webp chunks. Google's webpinfo gives warning instead of error. Browser can display the webp properly.
webpinfo returned result:

RIFF HEADER:
File size: 180690
Warning: RIFF size is smaller than the file size.
Chunk VP8X at offset 12, length 18
ICCP: 1
Alpha: 0
EXIF: 0
XMP: 0
Animation: 0
Canvas size 1200 x 1200
Chunk ICCP at offset 30, length 464
Chunk VP8 at offset 494, length 180196
Width: 1200
Height: 1200
Alpha: 0
Animation: 0
Format: Lossy (1)
No error detected.
There were 1 warning(s).

I've attached the webp file.

The current workaround is to truncate the extra bytes before passing to webp, as suggested by AI:

    /// <summary>
    /// Truncates a WebP byte array to the size specified in its RIFF header to remove extra bytes.
    /// </summary>
    /// <param name="inputBytes">Input WebP file as a byte array.</param>
    /// <returns>Truncated WebP data as a byte array, or null if an error occurs.</returns>
    /// <exception cref="ArgumentException">Thrown if the input is invalid or too small.</exception>
    public static byte[] TruncateWebP(byte[] inputBytes)
    {
        try
        {
            // Verify minimum size (RIFF header is at least 12 bytes)
            if (inputBytes == null || inputBytes.Length < 12)
            {
                throw new ArgumentException("Input byte array is null or too small to be a valid WebP file.");
            }

            // Check RIFF header (bytes 0-3 should be "RIFF")
            if (inputBytes[0] != 'R' || inputBytes[1] != 'I' || inputBytes[2] != 'F' || inputBytes[3] != 'F')
            {
                throw new ArgumentException("Input does not have a valid RIFF header.");
            }

            // Read RIFF size (bytes 4-7, little-endian)
            uint riffSize = BitConverter.ToUInt32(inputBytes, 4) + 8; // Add 8 bytes for "RIFF" and size field

            // Verify RIFF size against input size
            if (riffSize > inputBytes.Length)
            {
                throw new ArgumentException($"RIFF size ({riffSize}) is larger than input size ({inputBytes.Length}).");
            }

            // Use provided size (180,690 bytes) or RIFF size for dynamic truncation
            int bytesToKeep = (int)Math.Min(riffSize, 180690); // Hardcode to 180,690 for this specific file

            // Create truncated byte array
            byte[] outputBytes = new byte[bytesToKeep];
            Array.Copy(inputBytes, 0, outputBytes, 0, bytesToKeep);

            return outputBytes;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error truncating WebP byte array: {ex.Message}");
            return inputBytes;
        }
    }

Steps to Reproduce

  1. Decode the attached zip file, and try to use program to load the extra-meta.webp.
  2. e.g.
    [Theory]
    [WithFile(ExtraMeta, PixelTypes.Rgba32)]
    public void WebpDecoder_CanDecode_ExtraMeta<TPixel>(TestImageProvider<TPixel> provider)
        where TPixel : unmanaged, IPixel<TPixel>
    {
        using Image<TPixel> image = provider.GetImage(WebpDecoder.Instance);
        image.DebugSave(provider);
        image.CompareToOriginal(provider, ReferenceDecoder);
    } 
  1. run test will get:
System.AggregateException : One or more errors occurred. (Invalid Webp data.) (Expected 0 undisposed buffers but found 1)
---- SixLabors.ImageSharp.ImageFormatException : Invalid Webp data.
---- Expected 0 undisposed buffers but found 1

  Stack Trace: 
----- Inner Stack Trace #1 (SixLabors.ImageSharp.ImageFormatException) -----
WebpDecoderCore.ReadChunkSize(BufferedReadStream stream, Span`1 buffer) line 511
WebpDecoderCore.ReadVp8Info(BufferedReadStream stream, ImageMetadata metadata, Boolean ignoreAlpha) line 223
WebpDecoderCore.Decode[TPixel](BufferedReadStream stream, CancellationToken cancellationToken) line 84
ImageDecoderCore.Decode[TPixel](Configuration configuration, Stream stream, CancellationToken cancellationToken) line 82
WebpDecoder.Decode[TPixel](WebpDecoderOptions options, Stream stream, CancellationToken cancellationToken) line 39
SpecializedImageDecoder`1.Decode[TPixel](DecoderOptions options, Stream stream, CancellationToken cancellationToken) line 103
<>c__DisplayClass0_0`1.<Decode>b__0(Stream s) line 24
ImageDecoder.<WithSeekableStream>g__PerformActionAndResetPosition|11_0[T](Stream s, Int64 position, <>c__DisplayClass11_0`1&) line 195
ImageDecoder.WithSeekableStream[T](DecoderOptions options, Stream stream, Func`2 action) line 210
ImageDecoder.Decode[TPixel](DecoderOptions options, Stream stream) line 21
FileProvider.DecodeImage(IImageDecoder decoder, DecoderOptions options) line 275
FileProvider.GetImage(IImageDecoder decoder, DecoderOptions options) line 196
TestImageProvider`1.GetImage(IImageDecoder decoder) line 91
WebpDecoderTests.WebpDecoder_CanDecode_ExtraMeta[TPixel](TestImageProvider`1 provider) line 559
RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
----- Inner Stack Trace #2 (Xunit.Sdk.TrueException) -----
TestMemoryDiagnostics.Validate(Int32 expectedAllocationCount) line 61
MemoryAllocatorValidator.ValidateAllocations(Int32 expectedAllocationCount) line 49
ValidateDisposedMemoryAllocationsAttribute.After(MethodInfo methodUnderTest) line 27

Images

extra_meta.zip

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions