Skip to content

Commit

Permalink
Follow-up to 649ec6d: remove the testing tweaks for larger bit depths
Browse files Browse the repository at this point in the history
And improve the error messages.
  • Loading branch information
carlosame committed Jul 10, 2024
1 parent 83ff03e commit f2cbc45
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -427,41 +427,47 @@ private void parse_IHDR_chunk(PNGChunk chunk) {

bitDepth = chunk.getInt1(8);

int validMask = (1 << 1) | (1 << 2) | (1 << 4) | (1 << 8) | (1 << 16) | (1 << 32);
int validMask = (1 << 1) | (1 << 2) | (1 << 4) | (1 << 8) | (1 << 16);
if (((1 << bitDepth) & validMask) == 0) {
// bitDepth is not one of { 1, 2, 4, 8, 16, 32 }: Error -- bad bit depth
String msg = PropertyUtil.getString("PNGImage.bad.bit.depth");
// bitDepth is not one of { 1, 2, 4, 8, 16 }: Error -- bad bit depth
String msg = PropertyUtil.getString("PNGImage.unsupported.bit.depth");
throw new RuntimeException(msg);
}
maxOpacity = (1 << bitDepth) - 1;

colorType = chunk.getInt1(9);
if ((colorType != PNG_COLOR_GRAY) && (colorType != PNG_COLOR_RGB) && (colorType != PNG_COLOR_PALETTE)
&& (colorType != PNG_COLOR_GRAY_ALPHA) && (colorType != PNG_COLOR_RGB_ALPHA)) {
System.out.println(PropertyUtil.getString("PNGImageDecoder4"));
if ((colorType != PNG_COLOR_GRAY) && (colorType != PNG_COLOR_RGB)
&& (colorType != PNG_COLOR_PALETTE) && (colorType != PNG_COLOR_GRAY_ALPHA)
&& (colorType != PNG_COLOR_RGB_ALPHA)) {
System.out.println(PropertyUtil.formatMessage("PNGImage.unknown.color.type",
new Object[] { colorType }));
}

if ((colorType == PNG_COLOR_RGB) && (bitDepth < 8)) {
// Error -- RGB images must have 8 or 16 bits
String msg = PropertyUtil.getString("PNGImageDecoder5");
String msg = PropertyUtil.formatMessage("PNGImage.unsupported.rgb.bit.depth",
new Object[] { bitDepth });
throw new RuntimeException(msg);
}

if ((colorType == PNG_COLOR_PALETTE) && (bitDepth == 16)) {
// Error -- palette images must have < 16 bits
String msg = PropertyUtil.getString("PNGImageDecoder6");
String msg = PropertyUtil.formatMessage("PNGImage.wrong.palette.bit.depth",
new Object[] { bitDepth });
throw new RuntimeException(msg);
}

if ((colorType == PNG_COLOR_GRAY_ALPHA) && (bitDepth < 8)) {
// Error -- gray/alpha images must have >= 8 bits
String msg = PropertyUtil.getString("PNGImageDecoder7");
String msg = PropertyUtil.formatMessage("PNGImage.wrong.gray.alpha.bit.depth",
new Object[] { bitDepth });
throw new RuntimeException(msg);
}

if ((colorType == PNG_COLOR_RGB_ALPHA) && (bitDepth < 8)) {
// Error -- RGB/alpha images must have >= 8 bits
String msg = PropertyUtil.getString("PNGImageDecoder8");
String msg = PropertyUtil.formatMessage("PNGImage.wrong.rgb.alpha.bit.depth",
new Object[] { bitDepth });
throw new RuntimeException(msg);
}

Expand Down Expand Up @@ -501,14 +507,14 @@ private void parse_IHDR_chunk(PNGChunk chunk) {
compressionMethod = chunk.getInt1(10);
if (compressionMethod != 0) {
// Error -- only know about compression method 0
String msg = PropertyUtil.getString("PNGImageDecoder9");
String msg = PropertyUtil.getString("PNGImage.unknown.compression.method");
throw new RuntimeException(msg);
}

filterMethod = chunk.getInt1(11);
if (filterMethod != 0) {
// Error -- only know about filter method 0
String msg = PropertyUtil.getString("PNGImageDecoder10");
String msg = PropertyUtil.getString("PNGImage.unknown.filter");
throw new RuntimeException(msg);
}

Expand All @@ -529,19 +535,11 @@ private void parse_IHDR_chunk(PNGChunk chunk) {
}
} else {
// Error -- only know about Adam7 interlacing
String msg = PropertyUtil.getString("PNGImageDecoder11");
String msg = PropertyUtil.getString("PNGImage.unknown.interlacing");
throw new RuntimeException(msg);
}

if (bitDepth == 16) {
bytesPerPixel = 2;
} else if (bitDepth < 16) {
bytesPerPixel = 1;
} else if (bitDepth == 24) {
bytesPerPixel = 3;
} else {
bytesPerPixel = 4;
}
bytesPerPixel = (bitDepth == 16) ? 2 : 1;

switch (colorType) {
case PNG_COLOR_GRAY:
Expand Down Expand Up @@ -705,10 +703,10 @@ private void parse_IEND_chunk(PNGChunk chunk) throws Exception {
colorModel = createComponentColorModel(sampleModel);
}

onEnd();
onIEnd();
}

protected void onEnd() {
protected void onIEnd() {
}

// RenderedImage stuff
Expand Down Expand Up @@ -1060,7 +1058,7 @@ private void parse_gAMA_chunk(PNGChunk chunk) {

private void parse_hIST_chunk(PNGChunk chunk) {
if (redPalette == null) {
String msg = PropertyUtil.getString("PNGImageDecoder18");
String msg = PropertyUtil.getString("PNGImage.palette.not.set");
throw new RuntimeException(msg);
}

Expand Down Expand Up @@ -1099,14 +1097,13 @@ private void parse_iCCP_chunk(PNGChunk chunk) {
pdataLen + 64)) {
iccArray = infStream.readAllBytes();
} catch (IOException e) {
throw new RuntimeException("Error decompressing the ICC profile.", e);
throw new RuntimeException(PropertyUtil.getString("PNGImage.error.decomp.icc.profile."), e);
}
decodeParam.setICCProfileData(profileName.toString(), iccArray);
} else {
// Batik won't crash if there is no profile data, neither we.
iccArray = null;
}

decodeParam.setICCProfileData(profileName.toString(), iccArray);
}

private void parse_pHYs_chunk(PNGChunk chunk) {
Expand All @@ -1125,7 +1122,7 @@ private void parse_pHYs_chunk(PNGChunk chunk) {
properties.put("pixel_units", "Meters");
} else if (unitSpecifier != 0) {
// Error -- unit specifier must be 0 or 1
String msg = PropertyUtil.getString("PNGImageDecoder12");
String msg = PropertyUtil.getString("PNGImage.wrong.unit.specifier");
throw new RuntimeException(msg);
}
}
Expand All @@ -1143,7 +1140,7 @@ private void parse_sBIT_chunk(PNGChunk chunk) {
if (bits <= 0 || bits > depth) {
// Error -- significant bits must be between 0 and
// image bit depth.
String msg = PropertyUtil.getString("PNGImageDecoder13");
String msg = PropertyUtil.getString("PNGImage.wrong.significant.bits");
throw new RuntimeException(msg);
}
significantBits[i] = bits;
Expand Down Expand Up @@ -1239,7 +1236,7 @@ private void parse_tRNS_chunk(PNGChunk chunk) {
int entries = chunk.getLength();
if (entries > paletteEntries) {
// Error -- mustn't have more alpha than RGB palette entries
String msg = PropertyUtil.getString("PNGImageDecoder14");
String msg = PropertyUtil.getString("PNGImage.too.many.alphas");
throw new RuntimeException(msg);
}

Expand Down Expand Up @@ -1304,7 +1301,7 @@ private void parse_tRNS_chunk(PNGChunk chunk) {
}
} else if (colorType == PNG_COLOR_GRAY_ALPHA || colorType == PNG_COLOR_RGB_ALPHA) {
// Error -- GA or RGBA image can't have a tRNS chunk.
String msg = PropertyUtil.getString("PNGImageDecoder15");
String msg = PropertyUtil.getString("PNGImage.unexpected.trns");
throw new RuntimeException(msg);
}
}
Expand Down Expand Up @@ -1692,12 +1689,7 @@ private void decodePass(WritableRaster imRas, int xOffset, int yOffset, int xSte
}

int bytesPerRow = (inputBands * passWidth * bitDepth + 7) / 8;
int eltsPerRow;
if (bitDepth < 16) {
eltsPerRow = bytesPerRow;
} else {
eltsPerRow = bytesPerRow * 8 / bitDepth;
}
int eltsPerRow = bitDepth == 16 ? bytesPerRow / 2 : bytesPerRow;

byte[] curr = new byte[bytesPerRow];
byte[] prior = new byte[bytesPerRow];
Expand Down Expand Up @@ -1745,32 +1737,19 @@ private void decodePass(WritableRaster imRas, int xOffset, int yOffset, int xSte
break;
default:
// Error -- unknown filter type
String msg = PropertyUtil.getString("PNGImageDecoder16");
String msg = PropertyUtil.getString("PNGImage.unknown.filter");
throw new RuntimeException(msg);
}

// Copy data into passRow byte by byte
if (bitDepth < 16) {
System.arraycopy(curr, 0, byteData, 0, bytesPerRow);
} else if (bitDepth == 16) {
} else {
int idx = 0;
for (int j = 0; j < eltsPerRow; j++) {
shortData[j] = (short) ((curr[idx] << 8) | (curr[idx + 1] & 0xff));
idx += 2;
}
} else if (bitDepth == 24) {
int idx = 0;
for (int j = 0; j < eltsPerRow; j++) {
shortData[j] = (short) ((curr[idx + 1] << 16) | ((curr[idx + 2] & 0xff) << 8) | (curr[idx + 3] & 0xff));
idx += 3;
}
} else {
int idx = 0;
for (int j = 0; j < eltsPerRow; j++) {
shortData[j] = (short) ((curr[idx] << 24) | ((curr[idx + 1] & 0xff) << 16) | ((curr[idx + 2] & 0xff) << 8)
| (curr[idx + 3] & 0xff));
idx += 4;
}
}

processPixels(postProcess, passRow, imRas, xOffset, xStep, dstY, passWidth);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import java.util.zip.DeflaterOutputStream;

import io.sf.carte.echosvg.ext.awt.image.codec.util.ImageEncoderImpl;
import io.sf.carte.echosvg.ext.awt.image.codec.util.PropertyUtil;

class CRC {

Expand Down Expand Up @@ -152,13 +153,12 @@ public void writeInt(int v) throws IOException {
* </p>
*
* @param s the string to write.
* @throws IOException
* @throws IOException if an I/O error occurs.
*/
void writeLatin1(String s) throws IOException {
int len = s.length();
for (int i = 0; i < len; i++) {
char c = s.charAt(i);
dos.write(c);
final byte[] b = s.getBytes(StandardCharsets.ISO_8859_1);
for (int i = 0; i < b.length; i++) {
dos.writeByte(b[i]);
}
}

Expand Down Expand Up @@ -612,8 +612,6 @@ private void writeICCP() throws IOException {
cs.write(out.toByteArray());

cs.writeToStream(dataOutput);
} catch (IOException e) {
throw new RuntimeException("Error writing the ICC profile.", e);
}
}
}
Expand Down Expand Up @@ -932,38 +930,35 @@ public void encode(RenderedImage im) throws IOException {
// Ensure all channels have the same bit depth
for (int i = 1; i < sampleSize.length; i++) {
if (sampleSize[i] != bitDepth) {
throw new RuntimeException("Channel " + i + " has a different bit depth.");
String msg = PropertyUtil.formatMessage("PNGImageEncoder.bitdepth.mismatch",
new Object[] { i, bitDepth });
throw new RuntimeException(msg);
}
}

// Round bit depth up to a power of 2, unless > 16
// Round bit depth up to a power of 2
if (bitDepth > 2 && bitDepth < 4) {
bitDepth = 4;
} else if (bitDepth > 4 && bitDepth < 8) {
bitDepth = 8;
} else if (bitDepth > 8 && bitDepth < 16) {
bitDepth = 16;
} else if (bitDepth > 16 && bitDepth < 24) {
bitDepth = 24;
} else if (bitDepth > 24 && bitDepth < 32) {
bitDepth = 32;
} else if (bitDepth > 32) {
throw new RuntimeException("Bit depth too large: " + bitDepth);
} else if (bitDepth > 16) {
String msg = PropertyUtil.formatMessage("PNGImage.unsupported.bit.depth",
new Object[] { bitDepth });
throw new RuntimeException(msg);
}
}

this.numBands = sampleModel.getNumBands();

if (bitDepth < 16) {
this.bpp = numBands;
} else {
this.bpp = numBands * bitDepth / 8;
}
this.bpp = numBands * ((bitDepth == 16) ? 2 : 1);

ColorModel colorModel = image.getColorModel();
if (colorModel instanceof IndexColorModel) {
if (bitDepth < 1 || bitDepth > 8) {
throw new RuntimeException("Bit depth cannot be " + bitDepth);
String msg = PropertyUtil.formatMessage("PNGImage.wrong.indexed.bit.depth",
new Object[] { bitDepth });
throw new RuntimeException(msg);
}
if (sampleModel.getNumBands() != 1) {
throw new RuntimeException();
Expand Down Expand Up @@ -1013,7 +1008,7 @@ public void encode(RenderedImage im) throws IOException {
redPalette = greenPalette = bluePalette = alphaPalette = null;
this.colorType = PNG_COLOR_GRAY;
} else {
throw new RuntimeException();
throw new RuntimeException("Unknown palette.");
}
} else if (numBands == 1) {
if (param == null) {
Expand Down Expand Up @@ -1051,13 +1046,7 @@ public void encode(RenderedImage im) throws IOException {
if (param.isTransparencySet()) {
skipAlpha = true;
numBands = 3;
if (bitDepth == 16) {
bpp = 6;
} else if (bitDepth < 16) {
bpp = 3;
} else {
bpp = numBands * bitDepth / 8;
}
bpp = (bitDepth == 16) ? 6 : 3;
this.colorType = PNG_COLOR_RGB;
} else {
this.colorType = PNG_COLOR_RGB_ALPHA;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public MyPNGImage(InputStream input, PNGDecodeParam param) throws IOException {
}

@Override
protected void onEnd() {
protected void onIEnd() {
Rectangle bounds = new Rectangle(0, 0, width, height);
init((CachableRed) null, bounds, colorModel, sampleModel, 0, 0, properties);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,56 @@ Unknown magic number.
PNGImage.decode.error = \
Error decoding the file.

PNGImage.unknown.color.type = \
Unknown color type: {0}.

PNGImage.unknown.compression.method = \
Unknown ICC profile compression method.
Unknown compression method.

PNGImage.unknown.filter = \
Unknown filter.

PNGImage.unknown.interlacing = \
Unknown interlacing.

PNGImage.palette.not.set = \
Palette not set.

PNGImage.error.decomp.icc.profile = \
Error decompressing the ICC profile.

PNGImage.unsupported.rgb.bit.depth = \
RGB images must have a bit depth of 8 or 16, not: {0}.

PNGImage.wrong.palette.bit.depth = \
Palette images must have a depth lesser than 16, not {0}.

PNGImage.wrong.gray.alpha.bit.depth = \
Gray/alpha images must have a depth>= 8 bits, not {0}.

PNGImage.bad.bit.depth = \
PNGImage.wrong.rgb.alpha.bit.depth = \
RGB/alpha images must have a depth>= 8 bits, not {0}.

PNGImage.wrong.indexed.bit.depth = \
Color-mapped images can have a bit depth between 1 and 8, not {0}.

PNGImage.unsupported.bit.depth = \
Unsupported bit depth.

PNGImage.wrong.unit.specifier = \
Unit specifier must be 0 or 1.

PNGImage.wrong.significant.bits = \
Significant bits must be between 0 and image bit depth.

PNGImage.too.many.alphas = \
Error: cannot have more alpha than RGB palette entries.

PNGImage.unexpected.trns = \
Error: GA or RGBA image can't have a tRNS chunk.

PNGImageDecoder.unknown.page = \
Unknown page: {0}.

PNGImageEncoder.bitdepth.mismatch = \
Channel {0} has a bit depth different to specified {1}.

0 comments on commit f2cbc45

Please sign in to comment.