diff --git a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/ext/awt/image/codec/png/PNGImage.java b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/ext/awt/image/codec/png/PNGImage.java index 05f7500f6..b3aca9598 100644 --- a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/ext/awt/image/codec/png/PNGImage.java +++ b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/ext/awt/image/codec/png/PNGImage.java @@ -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); } @@ -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); } @@ -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: @@ -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 @@ -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); } @@ -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) { @@ -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); } } @@ -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; @@ -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); } @@ -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); } } @@ -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]; @@ -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); diff --git a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/ext/awt/image/codec/png/PNGImageEncoder.java b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/ext/awt/image/codec/png/PNGImageEncoder.java index 4d8da38c4..41f9d8211 100644 --- a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/ext/awt/image/codec/png/PNGImageEncoder.java +++ b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/ext/awt/image/codec/png/PNGImageEncoder.java @@ -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 { @@ -152,13 +153,12 @@ public void writeInt(int v) throws IOException { *

* * @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]); } } @@ -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); } } } @@ -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(); @@ -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) { @@ -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; diff --git a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/ext/awt/image/codec/png/PNGRed.java b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/ext/awt/image/codec/png/PNGRed.java index 2b8e22131..0b87ec557 100644 --- a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/ext/awt/image/codec/png/PNGRed.java +++ b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/ext/awt/image/codec/png/PNGRed.java @@ -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); } diff --git a/echosvg-transcoder/src/main/resources/io/sf/carte/echosvg/ext/awt/image/codec/Messages.properties b/echosvg-transcoder/src/main/resources/io/sf/carte/echosvg/ext/awt/image/codec/Messages.properties index 776c84a9b..7dcecf1ea 100644 --- a/echosvg-transcoder/src/main/resources/io/sf/carte/echosvg/ext/awt/image/codec/Messages.properties +++ b/echosvg-transcoder/src/main/resources/io/sf/carte/echosvg/ext/awt/image/codec/Messages.properties @@ -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}.