JDK-6348744 : PNGImageReader should skip metadata if ignoreMetadata=true
The Version table provides details related to the release that this issue/RFE will be addressed.
Unresolved : Release in which this issue/RFE will be addressed. Resolved: Release in which this issue/RFE has been resolved. Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.
PNGImageReader currently reads all image metadata, even if the ignoreMetadata flag
is set. We can reduce overhead and improve performance of reading small PNG images
if we skip those metadata blocks when ignoreMetadata=true.
The main fix is pretty simple. If ignoreMetadata is set, then we can skip over all
metadata chunks until we reach the first IDAT chunk. We need to be careful to only
apply this optimization for non-palette images, since we need the tRNS chunk in order
to read palette images properly.
There are some other minor performance tweaks we can make at this time as well:
- Use StringBuilder instead of StringBuffer (not likely to have much impact, but
it's an easy change to make).
- Use a switch block instead of if/else in the loop that reads metadata chunks. In
order to do so, we first need to make the *_TYPE constants truly constant
(currently they are calculated at runtime, which in itself is unnecessary work at
class load time, and prevents us from using a switch statement). The improvement
from this change is likely very small, but it's a good change to make so that in
theory we are taking advantage of some recent VM optimizations for jump tables.
- In PNGImageReader.readHeader(), there is one place where we call
stream.readUnsignedByte() 5x in a row. As discovered in 6347575, this can lead to
many system calls, so it would be better to do a bulk read of these 5 unsigned byte
values. This accounts for a modest reduction in overhead.
- In PNGImageReader.skipPass(), we allocate a temporary scanline byte and call
readFully() in order to skip one scanline at a time. This represents unnecessary
work; it would be preferable to call skipBytes(), as we do in other parts of the
With these changes in place, J2DBench tests show a modest (2-4%) improvement in
reading small PNG images. The test images being loaded by J2DBench have a very
small number of metadata chunks; I've tested some real world PNG files outside of
J2DBench that have more metadata, and I've found that performance is improved by
up to 10% for these images when ignoreMetadata is set. Here are the J2DBench
results for solaris-sparc, SB2000, 900 MHz USIII, 1GB RAM, -client, source is an
on-disk (blank) PNG file (base is 1.6.0-b60, test is similar with the changes
base: 1.595049105 (var=2.37%) (100.0%)
test: 1.625115298 (var=2.91%) (101.88%)
base: 579.6923076 (var=0.15%) (100.0%)
test: 592.8594130 (var=1.71%) (102.27%)
base: 1.607404860 (var=0.95%) (100.0%)
test: 1.648932603 (var=1.69%) (102.58%)
base: 565.3443811 (var=2.89%) (100.0%)
test: 589.0425645 (var=3.29%) (104.19%)