-
-
Notifications
You must be signed in to change notification settings - Fork 859
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Error block in image result after saving after loading some files #2866
Comments
What do you mean by compressed gifs? The encoder only encodes the difference because otherwise you end up with massive gifs. There’s no way to turn that off. |
Sorry for the long delay in replying.
I'm referring to gifs that only keep a record of the changed pixels. After I ran a lot of tests, I figured out why I was asking the question. Using CloneFrame itself gives me the results I want, and the reason I'm asking is because I usually save as a png or gif, so it's getting the wrong results, and leading me to think that what this method gets would be the difference pixel map (instead of the full frame image) This gif if I export it using CloneFrame and save it as a png, it will all show up as a pure empty image. using var image = await Image.LoadAsync<Rgba32>("1.gif");
for (var i = 0; i < image.Frames.Count; i++)
{
using var frameImage = image.Frames.CloneFrame(i);
frameImage.Save($"frame-{i}.png");
} And if I store it in jpg format, it's correct, this image is the result I want. using var image = await Image.LoadAsync<Rgba32>("1.gif");
for (var i = 0; i < image.Frames.Count; i++)
{
using var frameImage = image.Frames.CloneFrame(i);
frameImage.Save($"frame-{i}.jpg");
} |
A similar phenomenon occurs in webp. For example, these two images. using var image = await Image.LoadAsync<Rgba32>("1.webp");
await image.SaveAsync("2.webp"); I changed the title of the issue because of this. |
@BAKAOLC I think your issue is this. From the spec:
https://developers.google.com/speed/webp/docs/riff_container#animation ImageSharp has a dedicated decoder option when dealing with this ambiguity but requires explicit usage of the decoder to use it. using FileStream stream = File.OpenRead("1.webp");
WebpDecoderOptions decoderOptions = new() { GeneralOptions = this.options, BackgroundColorHandling = BackgroundColorHandling.Ignore };
using WebpDecoderCore decoder = new(decoderOptions);
using Image<Rgb32> image = decoder.Decode<Rgb32>(decoderOptions.GeneralOptions.Configuration, stream, cancellationToken);
image.Save("2.webp"); This gives you your output without the blocks. I'm almost tempted to use However, I have found something odd in the output. There's some ghosting on frame 16 where there are remnants of an ear that shouldn't be there. If I compare that frame to one extracted using EazyGif you will see that the BGR components are the same however the alpha component has a value. That value is coming straight out of the Is it a bug.... I don't know, is there some unspecified magic that is performed by other decoders.... I don't know. The |
Thank you very much for your answer, it solves part of my problem.
After additional experimentation, I confirmed that the gif will export the png image correctly using the following code. This issue is still one of the more confusing points for me at the moment. var image = await Image.LoadAsync<Rgba32>("1.gif").ConfigureAwait(false);
for (var i = 0; i < image.Frames.Count; i++)
{
using var frameImage = image.Frames.CloneFrame(i);
frameImage.Metadata.GetGifMetadata().GlobalColorTable = null;
await frameImage.SaveAsync($"frame-{i}.png").ConfigureAwait(false);
} This doesn't happen with all gif files extracting png frames. And by outputting a version of the empty file, does that mean it tries to store it as APNG? Also I don't think extracted frames should have this particular discrepancy when stored directly as a single frame image, should this behavior be handled away by default? |
var image = await Image.LoadAsync<Rgba32>("1.gif").ConfigureAwait(false);
image.Metadata.GetGifMetadata().GlobalColorTable = null;
await image.SaveAsync("2.gif").ConfigureAwait(false); Again, no unusual black blocks will appear when using this method when saving immediately after a direct read. But this should mean that there is something wrong with the GlobalColorTable data, because as I thought, without any editing of the image, the generated result should not be noticeably different from the original. |
OK... So I had a good look at the GIF. It's an odd one. It has a global color table but only two entries within that table. None of the frames actually use that table. ImageSharp assumes that the table use both valid so when converting between formats will attempt to use it. It also attempts to use it for the first frame when reencoding the GIF. I'm going to have to revisit the logic to handle such oddities. |
Figured out the WebP ghosting issue! We were disposing of the background restore area based on the current frame's disposal mode not the previous one! (@brianpopow crisis averted). Saved output attached (GitHub does not allow WebP) @BAKAOLC I'll open a PR tomorrow. |
@JimBobSquarePants I am glad you found this issue, this was hard to spot! |
Prerequisites
DEBUG
andRELEASE
modeImageSharp version
3.1.6
Other ImageSharp packages and versions
SixLabors.ImageSharp.Drawing 2.1.5
Environment (Operating system, version and so on)
macOS Sequoia 15.2
.NET Framework version
.net 9.0
Description
There are some specific compressed Gif files that are saved after being loaded that lose their differential rendering properties, resulting in black blocks in the image. But the original image renders fine without ImageSharp. However the image works fine in ImageSharp after it has been re-encoded by other software.
The result of the error looks like this:
As well, how do I get the full frame image of the compressed Gif correctly in the code instead of the difference?
Steps to Reproduce
just load and save it.
Images
The text was updated successfully, but these errors were encountered: