Open ErazerBrecht opened 1 week ago
Hello @ErazerBrecht, thank you for this.
Upon reviewing the issues, I was unable to open the folder containing a copy of your repository on my Windows 11 machine, as File Explorer would instantly crash. It's unclear how you were able to view the output there.
However, I was able to conduct an investigation on an older MacBook.
Regarding the GIF issue, I have opened a pull request which has been successfully tested against your image. It's important to note that your test code has a memory leak due to not disposing of images after allocation.
For the JPEG issue, the DividebyZeroException
you mentioned is unclear to me. The encoder in your sample code seems to replicate the default encoder options, and since the encoder only encodes the decoded pixel buffer, the input appears to be irrelevant. Further clarification is needed on this matter.
The increase in JPEG encoded output size is to be expected. The images provided have been modified to specify large dimensions, such as 59787x511 pixels. These dimensions are taken from the jpeg header, and we attempt to decode to a buffer that matches these dimensions. Consequently, when encoding, we are working with a pixel buffer that reflects the full manipulated dimensions, resulting in the encoding of a significantly larger amount of data.
Hey @JimBobSquarePants Already thanks for taking a look at this.
Yeah I can just use the file explorer on Windows 11. Here are the payloads in a ZIP so hopefully that works.
funnyanim.gif.zip funnyjpegs.zip
What I mean is that if I swap this part of the code:
using var output = new MemoryStream();
var encoder = new JpegEncoder { Quality = 75 };
image.Save(output, encoder);
Console.WriteLine($"Input: {input.Length} vs Output: {output.Length}");
To this:
using var output = new MemoryStream();
var encoder = new JpegEncoder();
image.Save(output, encoder);
Console.WriteLine($"Input: {input.Length} vs Output: {output.Length}");
Than it throws the exception:
Unhandled exception. System.DivideByZeroException: Attempted to divide by zero.
at SixLabors.ImageSharp.Formats.Jpeg.JpegEncoderCore.WriteDefineQuantizationTables(JpegQuantizationTableConfig[] configs, Nullable`1 optionsQuality, JpegMetadata metadata, Span`1 tmpBuffer)
at SixLabors.ImageSharp.Formats.Jpeg.JpegEncoderCore.Encode[TPixel](Image`1 image, Stream stream, CancellationToken cancellationToken)
at SixLabors.ImageSharp.Formats.Jpeg.JpegEncoder.Encode[TPixel](Image`1 image, Stream stream, CancellationToken cancellationToken)
at SixLabors.ImageSharp.Formats.ImageEncoder.EncodeWithSeekableStream[TPixel](Image`1 image, Stream stream, CancellationToken cancellationToken)
at SixLabors.ImageSharp.Formats.ImageEncoder.Encode[TPixel](Image`1 image, Stream stream)
at SixLabors.ImageSharp.Image.EncodeVisitor.Visit[TPixel](Image`1 image)
at SixLabors.ImageSharp.Image`1.Accept(IImageVisitor visitor)
at SixLabors.ImageSharp.Advanced.AdvancedImageExtensions.AcceptVisitor(Image source, IImageVisitor visitor)
at SixLabors.ImageSharp.Image.Save(Stream stream, IImageEncoder encoder)
at Program.<<Main>$>g__SaveLoadImage|0_0(String fileName) in I:\POC\ImageSharp.Payloads\ImageSharp.Payloads.Jpeg\Program.cs:line 32
at Program.<Main>$(String[] args) in I:\POC\ImageSharp.Payloads\ImageSharp.Payloads.Jpeg\Program.cs:line 14
For me the exception is better since it prevents a malicious actor of uploading the file. We fixed it in our own code by checking if the output ImageSharp is 10x bigger than the input, if this is the case we don't allow the image (only if the result is bigger than x amount of Mb).
Thanks for the update @ErazerBrecht I think understand what must be happening with the jpeg encoder now.
You can see the progress of the PR here https://github.com/SixLabors/ImageSharp/pull/2759
I've solved the GIF problem by refactoring the LZW decoder to work line by line. This limits allocations for the index buffer to 64K preventing the massive allocation you were seeing.
I'll have a look at the JPEG issue in the morning. I believe my inability to view the images in your repository has something to do with my usage of the new dev drive. I can see them in my standard drive.
P.S you can use the Image.Identify(...)
methods to determine the decoded dimensions of an image and also configure memory allocation limitations which will throw exceptions when exceeded.
@ErazerBrecht I've added a fix for the DividebyZeroException
to the PR. There are no fixes for the output file size since that is simply how large a true encoded JPEG for those dimensions would be. This is how any library that can open the images would behave.
Prerequisites
DEBUG
andRELEASE
modeImageSharp version
3.1.4
Other ImageSharp packages and versions
-
Environment (Operating system, version and so on)
Windows 11 Alpine 3.19
.NET Framework version
.NET 8
Description
Hello,
GIF
When using a certain GIF we are seeing OOM's. When debugging this locally I allocate +- 20Gb when handling that specific payload 5 times in parallel.
Payload: https://github.com/ErazerBrecht/ImageSharp.Payloads/blob/master/ImageSharp.Payloads.Gif/funnyanim.gif Source code: https://github.com/ErazerBrecht/ImageSharp.Payloads/blob/master/ImageSharp.Payloads.Gif/Program.cs
When changing the source code to use the 'earth.gif' it works as intended and there is no spike in memory allocation.
JPEG
We have some payloads that cause resource amplification. There are very small <1460 bytes but when using Imagesharp they result into a very big result (biggest one goes to >40Mb). This only happens when specifying a quality level in the JPG encoder. When not using one the payloads throw on a DividebyZeroException.
Payloads https://github.com/ErazerBrecht/ImageSharp.Payloads/blob/master/ImageSharp.Payloads.Jpeg/83.jpg https://github.com/ErazerBrecht/ImageSharp.Payloads/blob/master/ImageSharp.Payloads.Jpeg/92.jpg https://github.com/ErazerBrecht/ImageSharp.Payloads/blob/master/ImageSharp.Payloads.Jpeg/93.jpg Source code: https://github.com/ErazerBrecht/ImageSharp.Payloads/blob/master/ImageSharp.Payloads.Jpeg/Program.cs
Payloads were created by: https://app.intigriti.com/profile/whatevicanhaz
Sincerely, Brecht
Steps to Reproduce
See: https://github.com/ErazerBrecht/ImageSharp.Payloads
Images
No response