Open Dylan-Jinx opened 1 week ago
Can you please supply a sample image? It’s critical to allow me to debug anything.
Please provide an image when you are asked for one. If we find an image that works and it still doesn't work with yours than you are wasting our time.
@JimBobSquarePants @dlemstra I apologize for my earlier oversight. Since the images we're using have copyright considerations, could you please share your email address? I would like to send the problematic images directly to you. Thank you!
help @ sixlabors.com
Thank you very much! I will send the organized data to the specified email address shortly.
@JimBobSquarePants I've sent the relevant data to your email. Please take a look when you have a moment. I really appreciate all your hard work. Thank you!
I got your image and had a look. Thanks for sending it through.
The good news is that I've tested it against both webpinfo and ezgif splitter and cannot find an issue with it.
https://developers.google.com/speed/webp/docs/webpinfo https://ezgif.com/split
I'm also able to play the WEBP successfully using vwebp, Edge and Firefox on my Windows development machine. https://developers.google.com/speed/webp/docs/vwebp
So, we know the format of the image is fine. 👍
Let's look deeper at the image though...
The provided input GIF file has a background color set at index 63 in the color palette. This color is equivalent to RGBA 255, 255, 255, 255 which is white.
ImageSharp will use that information when translating the GIF to a WEBP file to set the background color on the ANIM chunk in the RIFF container. Here's what the specification says about that property.
Background Color: 32 bits (uint32) The default background color of the canvas in [Blue, Green, Red, Alpha] byte order. This color MAY be used to fill the unused space on the canvas around the frames, as well as the transparent pixels of the first frame. The background color is also used when the Disposal method is 1.
Note:
- The background color MAY contain a nonopaque alpha value, even if the Alpha flag in the 'VP8X' Chunk (Figure 7) is unset.
- Viewer applications SHOULD treat the background color value as a hint and are not required to use it.
- The canvas is cleared at the start of each loop. The background color MAY be used to achieve this.
https://developers.google.com/speed/webp/docs/riff_container#animation
It looks to me like the specific decoder which displays the thumbnails is using that background color property to fill outside frames which is different behavior to the decoders on my Windows machine. (ImageSharp optimizes the encoded frames on encode to remove unused areas)
Fortunately, it's possible to update that property.
using Image gifImage = Image.Load(image);
// Manually copy the properties across.
GifMetadata gMeta = gifImage .Metadata.GetGifMetadata();
WebpMetadata wMeta = gifImage .Metadata.GetWebpMetadata();
wMeta.FileFormat = WebpFileFormatType.Lossless;
wMeta.RepeatCount = gMeta.RepeatCount;
wMeta.BackgroundColor = Color.Transparent;
gifImage.SaveAsWebp(Path.Combine(AppContext.BaseDirectory, "testImageSharp.webp"));
Note: The RepeatCount
and BackgroundColor
properties are current missing on the WebPEncoder
type. I'll add them in an update which will make this easier to set.
P.S. Your code sample showed you are not disposing of your images. You must do that to prevent memory leaks.
Thank you very much! After using this code to generate a webp file, I found that there are no flickering issues when previewing it on my Mac. Everything seems to be normal so far. 👍
However, when I try to import it as a sticker in WhatsApp, it gets filtered out (I suspect WhatsApp considers it invalid and excludes it?).
For this image, when I directly convert the gif to webp using the Magick.NET library, it displays correctly. I wonder if there might be some subtle issue causing this.
I can provide an example of the code I used with Magick.NET.
using (var collection = new MagickImageCollection())
{
collection.Read(image);
var webpSettings = new WebPWriteDefines
{
Lossless = true,
};
using (var ms = new MemoryStream())
{
collection.Write(ms, webpSettings);
return ms.ToArray();
}
}
The image below shows the actual results in WhatsApp. I originally had four stickers, but only three are displayed. The missing one is the test image that I emailed to you.
The webp output is 100% valid according to every test I can apply including official tools from Google themselves. I would use webpinfo to compare blend/disposal properties to see if updating those to match the Magick version changes anything.
I checked the information on macOS, and the previews in Firefox, Safari, and Chrome all displayed correctly.
However, since Magick.NET can convert the file successfully and it passes verification in WhatsApp, I wonder if there might be some differences in the information.
I attached the webp file that works after conversion with Magick.NET (named "test.webp") from the help system you provided yesterday; it may be necessary to compare it with the webp generated by ImageSharp to identify any discrepancies.
That’s what I was asking you to do via webpinfo.
I followed your suggestion and used webpinfo to analyze the two WEBP files. test.webp is working fine, while testImageSharp.webp has issues when imported into WhatsApp. The webinfo results are as follows.
RIFF HEADER:
File:test.webp
File size: 162746
Chunk VP8X at offset 12, length 18
ICCP: 0
Alpha: 1
EXIF: 0
XMP: 0
Animation: 1
Canvas size 512 x 512
Chunk ANIM at offset 30, length 14
Background color:(ARGB) ff ff ff ff
Loop count : 0
Chunk ANMF at offset 44, length 36100
Offset_X: 0
Offset_Y: 0
Width: 512
Height: 512
Duration: 100
Dispose: 0
Blend: 1
Chunk VP8L at offset 68, length 36076
Width: 512
Height: 512
Alpha: 1
Animation: 0
Format: Lossless (2)
Chunk ANMF at offset 36144, length 31776
Offset_X: 60
Offset_Y: 40
Width: 428
Height: 418
Duration: 100
Dispose: 0
Blend: 1
Chunk VP8L at offset 36168, length 31752
Width: 428
Height: 418
Alpha: 1
Animation: 0
Format: Lossless (2)
Chunk ANMF at offset 67920, length 32718
Offset_X: 60
Offset_Y: 28
Width: 427
Height: 431
Duration: 100
Dispose: 0
Blend: 1
Chunk VP8L at offset 67944, length 32694
Width: 427
Height: 431
Alpha: 1
Animation: 0
Format: Lossless (2)
Chunk ANMF at offset 100638, length 29190
Offset_X: 62
Offset_Y: 28
Width: 425
Height: 431
Duration: 100
Dispose: 0
Blend: 1
Chunk VP8L at offset 100662, length 29166
Width: 425
Height: 431
Alpha: 1
Animation: 0
Format: Lossless (2)
Chunk ANMF at offset 129828, length 32918
Offset_X: 64
Offset_Y: 68
Width: 431
Height: 392
Duration: 100
Dispose: 0
Blend: 1
Chunk VP8L at offset 129852, length 32894
Width: 431
Height: 392
Alpha: 1
Animation: 0
Format: Lossless (2)
No error detected.
File: testImageSharp.webp
RIFF HEADER:
File size: 168496
Chunk VP8X at offset 12, length 18
ICCP: 0
Alpha: 1
EXIF: 0
XMP: 1
Animation: 1
Canvas size 512 x 512
Chunk ANIM at offset 30, length 14
Background color:(ARGB) 00 00 00 00
Loop count : 0
Chunk ANMF at offset 44, length 36100
Offset_X: 0
Offset_Y: 0
Width: 512
Height: 512
Duration: 100
Dispose: 1
Blend: 1
Chunk VP8L at offset 68, length 36076
Width: 512
Height: 512
Alpha: 1
Animation: 0
Format: Lossless (2)
Chunk ANMF at offset 36144, length 32922
Offset_X: 28
Offset_Y: 24
Width: 457
Height: 461
Duration: 0
Dispose: 1
Blend: 1
Chunk VP8L at offset 36168, length 32898
Width: 457
Height: 461
Alpha: 1
Animation: 0
Format: Lossless (2)
Chunk ANMF at offset 69066, length 33782
Offset_X: 28
Offset_Y: 24
Width: 459
Height: 461
Duration: 0
Dispose: 1
Blend: 1
Chunk VP8L at offset 69090, length 33758
Width: 459
Height: 461
Alpha: 1
Animation: 0
Format: Lossless (2)
Chunk ANMF at offset 102848, length 30156
Offset_X: 28
Offset_Y: 24
Width: 458
Height: 461
Duration: 0
Dispose: 1
Blend: 1
Chunk VP8L at offset 102872, length 30132
Width: 458
Height: 461
Alpha: 1
Animation: 0
Format: Lossless (2)
Chunk ANMF at offset 133004, length 34604
Offset_X: 28
Offset_Y: 24
Width: 467
Height: 461
Duration: 0
Dispose: 0
Blend: 0
Chunk VP8L at offset 133028, length 34580
Width: 467
Height: 461
Alpha: 1
Animation: 0
Format: Lossless (2)
Chunk XMP at offset 167608, length 888
No error detected.
Conclusion: Based on the webpinfo output for these two files, here are the key differences:
1. XMP Data:
test.webp: No XMP data.
testImageSharp.webp: Contains XMP data. This data may affect how some applications parse and display the image, but it usually doesn't lead to compatibility issues.
2. Animation:
Both files support animation, but in testImageSharp.webp, some frames have a Dispose value of 1 (which means clear the previous frame), while test.webp has a Dispose value of 0. This could affect how the animation performs.
3. Dimensions:
Both files have similar width and height data, but in testImageSharp.webp, certain frames' Offset_X and Offset_Y values might cause display issues in WhatsApp.
4. Background Color:
test.webp uses a white background (ARGB: ff ff ff ff), while testImageSharp.webp has a transparent background (ARGB: 00 00 00 00). A transparent background may cause display problems in certain environments.
I would suggest stripping out the XMP data.
I would avoid conjecture when describing the differences. Things like offset and background color are perfectly valid.
using Image gifImage = Image.Load(image);
// Manually copy the properties across.
GifMetadata gMeta = gifImage.Metadata.GetGifMetadata();
WebpMetadata wMeta = gifImage.Metadata.GetWebpMetadata();
Console.WriteLine(wMeta);
wMeta.FileFormat = WebpFileFormatType.Lossless;
wMeta.RepeatCount = gMeta.RepeatCount;
wMeta.BackgroundColor = Color.White;
gifImage.Metadata.XmpProfile = null;
foreach (var frame in gifImage.Frames)
{
var webpFrame = frame.Metadata.GetWebpMetadata();
webpFrame.BlendMethod = WebpBlendMethod.Source;
webpFrame.DisposalMethod = WebpDisposalMethod.DoNotDispose;
webpFrame.FrameDelay = 100;
}
gifImage.SaveAsWebp(Path.Combine(AppContext.BaseDirectory, "202410231720.webp"));
After repeated comparisons, I followed your instructions this time and removed the XMP data, but it still didn't work. So, I gradually adjusted the properties to match the webpinfo results of the working image, but it still didn’t help.
It wasn't until I added the following statement that it was finally recognized correctly, and I was really excited by the result.😯
webpFrame.FrameDelay = 100;
After comparison, I found that the images generated by Magick.Net have a Duration of 100 for each ANMF in the webpinfo, while ImageSharp's Duration is set to 0.
WhatsApp may use the Duration for its judgment, which could lead to the images generated by ImageSharp being filtered out. I think that ImageSharp should correctly set the Duration property for each ANMF in the WebP metadata when using SaveAsWebp.
Should ImageSharp handle similar special cases? If possible, I would like to assist in completing this great work.
NICE DETECTIVE WORK!! 🕵️
I think that ImageSharp should correctly set the Duration property for each ANMF in the WebP metadata when using SaveAsWebp.
ImageSharp is actually doing the correct thing here by performing an exact translation.
If you look at the GIF metadata your will see that only the first frame actually has a frame delay set - All the others are zero. (Verified via 3rd party)
There's no rule for the minimum frame delay in either specification (nor also APNG) but browsers and other tools tend to use a minimum value for display purposes.
I've done some research in the past though for various browsers and here are my findings:
Format | Chrome | Firefox | Safari | Edge | Opera |
---|---|---|---|---|---|
GIF | 10 ms (enforced) | 20 ms (enforced) | 20 ms (enforced) | 10 ms (enforced) | 10 ms (enforced) |
APNG | 10 ms (enforced) | 10 ms (native) | 10 ms (native) | 10 ms (native) | 10 ms (native) |
WEBP | 16.67 ms (60 FPS) | 16.67 ms | 16.67 ms | 16.67 ms | 16.67 ms |
GIF:
APNG (Animated PNG):
WEBP:
As you can see the minimum display value is inconsistent for GIF files and does not match the default set by Magick.Net.
While their approach is a sensible one, I disagree that it is the correct direction for ImageSharp. We should not change metadata without explicit instruction to do so.
NICE JOB! 👍 A very detailed explanation!
I share the same attitude as you, believing that metadata should not be changed arbitrarily. I think this issue can help colleagues in the future address similar situations more elegantly.
Prerequisites
DEBUG
andRELEASE
modeImageSharp version
3.1.5
Other ImageSharp packages and versions
3.1.5
Environment (Operating system, version and so on)
MacOS
.NET Framework version
.NET8
Description
I am using a GIF image to convert it into an animated WebP, but the resulting WebP image cannot be imported into WhatsApp. It seems to be filtered or rejected by WhatsApp. However, when I use the Magick library to perform the same conversion, the WebP file is successfully imported into WhatsApp.
Here is the code I am using to convert the GIF to WebP:
I would like to know if there is a specific issue with my code or any known differences between the encoding methods that could be causing this problem.
Steps to Reproduce
Images
No response