diff --git a/modules/library/coverage/src/main/java/org/geotools/image/ImageWorker.java b/modules/library/coverage/src/main/java/org/geotools/image/ImageWorker.java index 2f2d16cc670..5e3059dab84 100644 --- a/modules/library/coverage/src/main/java/org/geotools/image/ImageWorker.java +++ b/modules/library/coverage/src/main/java/org/geotools/image/ImageWorker.java @@ -54,6 +54,7 @@ import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.plugins.jpeg.JPEGImageWriteParam; +import javax.imageio.spi.IIORegistry; import javax.imageio.spi.ImageOutputStreamSpi; import javax.imageio.spi.ImageWriterSpi; import javax.imageio.stream.ImageOutputStream; @@ -2717,23 +2718,36 @@ public final void writePNG(final Object destination, final String compression, } // let me check if the native writer can encode this image (paranoiac checks this was already performed by the ImageIO search - if(!originatingProvider.canEncodeImage(new ImageTypeSpecifier(image))){ - LOGGER.fine("The following encoder cannot encode this image: "+originatingProvider.getClass().getCanonicalName()); - - // kk, last resort reformat the image - forceComponentColorModel(true, true); - rescaleToBytes(); - if(!originatingProvider.canEncodeImage(image)){ - LOGGER.severe("Unable to find a valid PNG Encoder!"); - } - } + if(originatingProvider.canEncodeImage(new ImageTypeSpecifier(image))){ + break; // leave loop + } + + // clean + writer=null; + originatingProvider=null; } } - // do we have a writer? + // ok, last resort use the JDK one and reformat the image if(writer==null){ - throw new IllegalStateException("Unable to find a valid PNG Encoder!"); - } + List providers = com.sun.media.imageioimpl.common.ImageUtil.getJDKImageReaderWriterSPI( + IIORegistry.getDefaultInstance(), + "PNG", + false); + if(providers==null||providers.isEmpty()){ + throw new IllegalStateException("Unable to find JDK Png encoder!"); + } + originatingProvider=(ImageWriterSpi) providers.get(0); + writer=originatingProvider.createWriterInstance(); + + // kk, last resort reformat the image + forceComponentColorModel(true, true); + rescaleToBytes(); + if(!originatingProvider.canEncodeImage(image)){ + throw new IllegalArgumentException("Unable to find a valid PNG Encoder! And believe me, we tried hard!"); + } + } + LOGGER.fine("Using ImageIO Writer with SPI: "+originatingProvider.getClass().getCanonicalName()); // Getting a stream. @@ -2768,22 +2782,22 @@ public final void writePNG(final Object destination, final String compression, } LOGGER.fine("About to write png image"); try{ - writer.setOutput(memOutStream); - writer.write(null, new IIOImage(image, null, null), iwp); + writer.setOutput(memOutStream); + writer.write(null, new IIOImage(image, null, null), iwp); } finally{ - try{ - writer.dispose(); - }catch (Throwable e) { - if(LOGGER.isLoggable(Level.FINEST)) - LOGGER.log(Level.FINEST,e.getLocalizedMessage(),e); - } - try{ - memOutStream.close(); - }catch (Throwable e) { - if(LOGGER.isLoggable(Level.FINEST)) - LOGGER.log(Level.FINEST,e.getLocalizedMessage(),e); - } + try{ + writer.dispose(); + }catch (Throwable e) { + if(LOGGER.isLoggable(Level.FINEST)) + LOGGER.log(Level.FINEST,e.getLocalizedMessage(),e); + } + try{ + memOutStream.close(); + }catch (Throwable e) { + if(LOGGER.isLoggable(Level.FINEST)) + LOGGER.log(Level.FINEST,e.getLocalizedMessage(),e); + } } diff --git a/modules/library/coverage/src/test/java/org/geotools/image/ImageWorkerTest.java b/modules/library/coverage/src/test/java/org/geotools/image/ImageWorkerTest.java index 5d9ef8a7687..4bacc0ee002 100644 --- a/modules/library/coverage/src/test/java/org/geotools/image/ImageWorkerTest.java +++ b/modules/library/coverage/src/test/java/org/geotools/image/ImageWorkerTest.java @@ -439,39 +439,69 @@ public void testPNGWrite() throws IOException { assertTrue(readWorker.getRenderedImage().getColorModel() instanceof IndexColorModel); } + @Test + public void test16BitPNG() throws Exception { + // the resource has been compressed since the palette is way larger than the image itself, + // and the palette does not get compressed + InputStream gzippedStream = ImageWorkerTest.class.getResource("test-data/sf-sfdem.tif.gz").openStream(); + GZIPInputStream is = new GZIPInputStream(gzippedStream); + try { + ImageInputStream iis = ImageIO.createImageInputStream(is); + ImageReader reader = new TIFFImageReaderSpi().createReaderInstance(iis); + reader.setInput(iis); + BufferedImage bi = reader.read(0); + IndexColorModel icm = (IndexColorModel) bi.getColorModel(); + assertEquals(65536, icm.getMapSize()); + + final File outFile = TestData.temp(this, "temp.png"); + ImageWorker worker = new ImageWorker(bi); + worker.writePNG(outFile, "FILTERED", 0.75f, true, false); + worker.dispose(); + + // make sure we can read it + BufferedImage back = ImageIO.read(outFile); + + // we expect a RGB one + ComponentColorModel ccm = (ComponentColorModel) back.getColorModel(); + assertEquals(3, ccm.getNumColorComponents()); + } finally { + is.close(); + } + } + @Test public void test4BitPNG() throws Exception { // create test image IndexColorModel icm =new IndexColorModel( - 4, - 16, - new byte[]{(byte)255,0, 0, 0,16,32,64,(byte)128,1,2,3,4,5,6,7,8}, - new byte[]{0, (byte)255,0, 0,16,32,64,(byte)128,1,2,3,4,5,6,7,8}, - new byte[]{0, 0, (byte)255,0,16,32,64,(byte)128,1,2,3,4,5,6,7,8}); + 4, + 16, + new byte[]{(byte)255,0, 0, 0,16,32,64,(byte)128,1,2,3,4,5,6,7,8}, + new byte[]{0, (byte)255,0, 0,16,32,64,(byte)128,1,2,3,4,5,6,7,8}, + new byte[]{0, 0, (byte)255,0,16,32,64,(byte)128,1,2,3,4,5,6,7,8}); assertEquals(16, icm.getMapSize()); // create random data WritableRaster data = com.sun.media.jai.codecimpl.util.RasterFactory.createWritableRaster( - icm.createCompatibleSampleModel(32,32), - new Point(0,0)); + icm.createCompatibleSampleModel(32,32), + new Point(0,0)); for(int x=data.getMinX();x