Skip to content
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

Image.Load() throws InvalidImageContentException: CRC Error. PNG IDAT chunk is corrupt! #2570

Closed
4 tasks done
oskarlindman opened this issue Oct 24, 2023 · 14 comments · Fixed by #2589
Closed
4 tasks done

Comments

@oskarlindman
Copy link

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.0.2

Other ImageSharp packages and versions

None

Environment (Operating system, version and so on)

Windows 11 Version 22H2

.NET Framework version

.net 7

Description

I have two png images that opens fine with System.Drawing.Common, but that fails to open with ImageSharp, and instead throw an InvalidImageContentException: CRC Error. PNG IDAT chunk is corrupt! Both files can be viewed in windows.

Steps to Reproduce

Just point to the filePath with Image.Open(filePath) and it should throw the exception when running the code.

 at SixLabors.ImageSharp.Formats.Png.PngThrowHelper.ThrowInvalidChunkCrc(String chunkTypeName)
   at SixLabors.ImageSharp.Formats.Png.PngDecoderCore.ValidateChunk(PngChunk& chunk)
   at SixLabors.ImageSharp.Formats.Png.PngDecoderCore.TryReadChunk(PngChunk& chunk)
   at SixLabors.ImageSharp.Formats.Png.PngDecoderCore.Decode[TPixel](BufferedReadStream stream, CancellationToken cancellationToken)
   at SixLabors.ImageSharp.Formats.ImageDecoderUtilities.Decode[TPixel](IImageDecoderInternals decoder, Configuration configuration, Stream stream, Func`3 largeImageExceptionFactory, CancellationToken cancellationToken)
   at SixLabors.ImageSharp.Formats.ImageDecoderUtilities.Decode[TPixel](IImageDecoderInternals decoder, Configuration configuration, Stream stream, CancellationToken cancellationToken)
   at SixLabors.ImageSharp.Formats.Png.PngDecoder.Decode[TPixel](DecoderOptions options, Stream stream, CancellationToken cancellationToken)
   at SixLabors.ImageSharp.Formats.Png.PngDecoder.Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken)
   at SixLabors.ImageSharp.Formats.ImageDecoder.<>c__DisplayClass1_0.<Decode>b__0(Stream s)
   at SixLabors.ImageSharp.Formats.ImageDecoder.<WithSeekableStream>g__PeformActionAndResetPosition|11_0[T](Stream s, Int64 position, <>c__DisplayClass11_0`1& )
   at SixLabors.ImageSharp.Formats.ImageDecoder.WithSeekableStream[T](DecoderOptions options, Stream stream, Func`2 action)
   at SixLabors.ImageSharp.Formats.ImageDecoder.Decode(DecoderOptions options, Stream stream)
   at SixLabors.ImageSharp.Image.Decode(DecoderOptions options, Stream stream)
   at SixLabors.ImageSharp.Image.<>c__DisplayClass80_0.<Load>b__0(Stream s)
   at SixLabors.ImageSharp.Image.WithSeekableStream[T](DecoderOptions options, Stream stream, Func`2 action)
   at SixLabors.ImageSharp.Image.Load(DecoderOptions options, Stream stream)
   at SixLabors.ImageSharp.Image.Load(DecoderOptions options, String path)
   at SixLabors.ImageSharp.Image.Load(String path)

Images

transparent_png_without_extension_2
transparent_png_without_extension_1

@JimBobSquarePants
Copy link
Member

The IDAT is indeed corrupt.

image

We'll need to have a look at libpng to see if they have some special handling of this.

https://www.nayuki.io/page/png-file-chunk-inspector

@dlemstra
Copy link
Member

Libpng also "throws an exceptions":

C:\Users\Dirk\Desktop>magick 277674454-e24cc769-3dbd-420b-977f-7f7b6dbec05c.png info:
magick: Expected 4 bytes; found 0 bytes `277674454-e24cc769-3dbd-420b-977f-7f7b6dbec05c.png' @ warning/png.c/MagickPNGWarningHandler/1526.
magick: Read Exception `277674454-e24cc769-3dbd-420b-977f-7f7b6dbec05c.png' @ error/png.c/MagickPNGErrorHandler/1492.

@svenclaesson
Copy link
Contributor

corrupt
This file, and the two above can be partially displayed by chrome, that uses libpng

@JimBobSquarePants
Copy link
Member

Can they be opened by other imaging libraries? Chrome looks to have turned of the safety checks. (There’s a compiler option in libpng)

@svenclaesson
Copy link
Contributor

svenclaesson commented Nov 7, 2023

MagicScalar uses libpng and can handle the last image that i posted

MagicScalar uses vcpkg precompiled version of libpng. What is the compiler option called can't seam to find it here?

@JimBobSquarePants
Copy link
Member

Ah not a compiler option it seems. Look for png_set_crc_action

http://www.libpng.org/pub/png/libpng-manual.txt

@svenclaesson
Copy link
Contributor

So this explains why it works in MagicScalar then.

Would it be possible to consider this for ImageSharp?

@svenclaesson
Copy link
Contributor

svenclaesson commented Nov 8, 2023

After further investigation into MagicScaler, it turns out that using default settings on windows will result in native WIC codecs being used. This png codec is forgiving.
Instead when libpng is used with "codecs.UseLibpng()" no CRC error is thrown but the resulting image is all black.
nevermind. this works as expected.

Any input?

@JimBobSquarePants
Copy link
Member

This is precisely the kind of thing I designed ISpecializedDecoderOptions for. There's no reason we cannot define rules for handling Crc and Adler validation on decode.

Would you be interested in creating a PR?

@svenclaesson
Copy link
Contributor

Tried it a bit but got stuck by the fact that IDAT and IEND is considered critical chunks and found no way of ignoring that fact if the file is truncated, IDAT is cut off and IEND is missing.

Maybe you have some pointers for me here
PR not yet posted to here because it is work in progress still.

@JimBobSquarePants
Copy link
Member

Sorry for the slow reply @svenclaesson I've been off the boil for the last few weeks with sickness.

If you actually open a PR I can commit directly to your fork to help finish it off.

@Erik-White
Copy link

@JimBobSquarePants What is the easiest way to make use of the new options? Ideally I would like to be able to pass something through via Image.Identify or Image.Load, but they only take a basic DecoderOptions.

Would it be reasonable to add overloads that take ISpecializedDecoderOptions since that already contains a DecoderOptions property? Or maybe some other concept of aggregated specialized decoder options?

@JimBobSquarePants
Copy link
Member

@JimBobSquarePants What is the easiest way to make use of the new options? Ideally I would like to be able to pass something through via Image.Identify or Image.Load, but they only take a basic DecoderOptions.

Would it be reasonable to add overloads that take ISpecializedDecoderOptions since that already contains a DecoderOptions property? Or maybe some other concept of aggregated specialized decoder options?

Ideally, we'd add a general equivalent to DecoderOptions but we're stuck with the problem of what to choose... The specialized, or general version of the enum. Implementing it would require a breaking change to either remove or make nullable the specialized enum.

@Erik-White
Copy link

Just so I understand, you would like to add a new property to DecoderOptions, a new enum e.g. CrcChunkHandling.
This could then be used in place of PngCrcChunkHandling, and maybe also in other decoders?

Maybe the new one could be added and mapped to the specialized enum to save a breaking change? If I get time I could make an attempt at that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants