-
-
Notifications
You must be signed in to change notification settings - Fork 851
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
Png - Preserve Pixel Format for Non-generic decode. #1861
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1861 +/- ##
======================================
- Coverage 87% 87% -1%
======================================
Files 957 957
Lines 50391 50474 +83
Branches 6264 6291 +27
======================================
+ Hits 44180 44252 +72
- Misses 5180 5185 +5
- Partials 1031 1037 +6
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
Co-authored-by: Günther Foidl <gue@korporal.at>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but Identify is so quick anyway it seemed like the simplest approach.
I'm not sure if it's always true. There is some unnecessary IO cost reading the stream twice when the file is large and/or there are *Text
chunks not being skipped on ignoreMetadata
. This may hurt scalability, and it doesn't seem to be very hard to fix:
We can introduce a field in PngDecoderCore
that asks to skip everything except the absolute minimum needed to determine the pixel type (Header + Transparency?), and stop when the essential chunks are processed or when a Data chunk is detected.
Later we can improve the IImageDecoderInternals
infrastructure to support these scenarios, but that's far beyond the essential feature work we need for Png.
I've changed the behavior of the chunk reader to avoid reading data from anything other than the header and transparency chunks when required. This also allows skipping the entire chunk. It also now stops as soon as we have the info we require. It's a little hacky but should be fast enough for now. |
this.SkipChunkDataAndCrc(chunk); | ||
break; | ||
} | ||
|
||
this.ReadGammaChunk(pngMetadata, chunk.Data.GetSpan()); | ||
break; | ||
case PngChunkType.Data: | ||
this.SkipChunkDataAndCrc(chunk); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When present, the tRNS chunk must precede the first IDAT chunk, and must follow the PLTE chunk, if any.
It means that if we reach Data, we are free to quit the loop. Forwarding the file position beyond the data chunk may have IO overhead we can easily avoid here.
this.paletteAlpha = alpha; | ||
this.AssignTransparentMarkers(alpha, pngMetadata); | ||
|
||
if (this.colorMetadataOnly && this.isHeaderChunkReached) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the spec, IDAT IHDR is always the first, so - in theory - we don't need to track if we reached it. I wonder if there are malformed PNG-s in the wild which do not follow this rule.
@brianpopow any thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean IHDR
is always first I guess? I will go through my collection of "weird and broken images" to check if i can find any which has not IHDR
first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean IHDR is always first I guess?
Yes, sorry for the typo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could not find any png which do not start with IHDR
. Nonetheless I am still in favor of keeping it as it is, just to be sure, because in theory such png can be created.
if (this.colorMetadataOnly && this.isHeaderChunkReached) | ||
{ | ||
// Quick exit | ||
this.isEndChunkReached = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we should just break
out of the loop instead of abusing this flag?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
goto
baby; goto
.
@antonfirsov @brianpopow I'll just follow the strict specification here and optimize accordingly. The worst that can happen is that they decode to the incorrect pixel format. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. I think it's possible to achieve the same without goto
will do it in a separate cleanup PR.
Whole thing needs a cleanup. We should be skipping all chunks we don't currently read on decode but are instead reading the data. |
Prerequisites
Description
Fixes #1813 by determining the most appropriate pixel format to decode to based upon the detected color type and bit depth.
I could have avoided the identify/reset/decode route and gained a little more performance but
Identify
is so quick anyway it seemed like the simplest approach.