How to convert a huge TIFF image to PNG / JPEG without a memory error?

I have a tiff file of 18000 * 18000 in dimension and 1.20 GB . tiff has 72 DPI.

I want to convert this TIFF to PNG / JPEG using 400 DPI.

I am using the following code for this

public static void ConvertTiffToJpg(String str_TiffUrl, String str_JpgFileDestinationUrl) throws Exception { try { FileSeekableStream obj_FileSeekableStream = new FileSeekableStream( new File(str_TiffUrl)); ImageDecoder obj_ImageDecoder = ImageCodec.createImageDecoder( "tiff", obj_FileSeekableStream, null); RenderedImage obj_RenderedImage = obj_ImageDecoder .decodeAsRenderedImage(); JAI.create("filestore", obj_RenderedImage, str_JpgFileDestinationUrl, "jpeg"); obj_RenderedImage = null; obj_ImageDecoder = null; obj_FileSeekableStream.close(); } catch (Exception ex) { throw ex; } 

the above code works fine for smaller images, then the specified image, for example, a tiff image of less than 5000 * 5000 in Dimension, can easily be converted to JPEG / PNG [although I need to change the PNG encoder],

but when I try to run the same code for the above file, it throws the following exception

 Error: One factory fails for the operation "encode" Occurs in: javax.media.jai.ThreadSafeOperationRegistry java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at javax.media.jai.FactoryCache.invoke(FactoryCache.java:122) at javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674) at javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473) at javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332) at com.sun.media.jai.opimage.FileStoreRIF.create(FileStoreRIF.java:138) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at javax.media.jai.FactoryCache.invoke(FactoryCache.java:122) at javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674) at javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473) at javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332) at javax.media.jai.RenderedOp.createInstance(RenderedOp.java:819) at javax.media.jai.RenderedOp.createRendering(RenderedOp.java:867) at javax.media.jai.RenderedOp.getRendering(RenderedOp.java:888) at javax.media.jai.JAI.createNS(JAI.java:1099) at javax.media.jai.JAI.create(JAI.java:973) at javax.media.jai.JAI.create(JAI.java:1621) at com.vs.graphics.concepts.TiffToJpeg.ConvertTiffToJpg(TiffToJpeg.java:30) at com.vs.graphics.svg.SvgRefresh$1.actionPerformed(SvgRefresh.java:106) at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995) at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318) at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387) at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242) at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236) at java.awt.Component.processMouseEvent(Component.java:6216) at javax.swing.JComponent.processMouseEvent(JComponent.java:3265) at java.awt.Component.processEvent(Component.java:5981) at java.awt.Container.processEvent(Container.java:2041) at java.awt.Component.dispatchEventImpl(Component.java:4583) at java.awt.Container.dispatchEventImpl(Container.java:2099) at java.awt.Component.dispatchEvent(Component.java:4413) at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4556) at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4220) at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4150) at java.awt.Container.dispatchEventImpl(Container.java:2085) at java.awt.Window.dispatchEventImpl(Window.java:2475) at java.awt.Component.dispatchEvent(Component.java:4413) at java.awt.EventQueue.dispatchEvent(EventQueue.java:599) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161) at java.awt.EventDispatchThread.run(EventDispatchThread.java:122) Caused by: java.lang.OutOfMemoryError: Java heap space at java.awt.image.DataBufferByte.<init>(DataBufferByte.java:42) at java.awt.image.Raster.createInterleavedRaster(Raster.java:253) at java.awt.image.Raster.createInterleavedRaster(Raster.java:194) at com.sun.media.jai.codecimpl.JPEGImageEncoder.encode(JPEGImageEncoder.java:182) at com.sun.media.jai.opimage.EncodeRIF.create(EncodeRIF.java:70) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at javax.media.jai.FactoryCache.invoke(FactoryCache.java:122) at javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674) at javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473) at javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332) at com.sun.media.jai.opimage.FileStoreRIF.create(FileStoreRIF.java:138) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at javax.media.jai.FactoryCache.invoke(FactoryCache.java:122) at javax.media.jai.OperationRegistry.invokeFactory(OperationRegistry.java:1674) at javax.media.jai.ThreadSafeOperationRegistry.invokeFactory(ThreadSafeOperationRegistry.java:473) at javax.media.jai.registry.RIFRegistry.create(RIFRegistry.java:332) at javax.media.jai.RenderedOp.createInstance(RenderedOp.java:819) at javax.media.jai.RenderedOp.createRendering(RenderedOp.java:867) at javax.media.jai.RenderedOp.getRendering(RenderedOp.java:888) at javax.media.jai.JAI.createNS(JAI.java:1099) at javax.media.jai.JAI.create(JAI.java:973) at javax.media.jai.JAI.create(JAI.java:1621) at com.vs.graphics.concepts.TiffToJpeg.ConvertTiffToJpg(TiffToJpeg.java:30) at com.vs.graphics.svg.SvgRefresh$1.actionPerformed(SvgRefresh.java:106) at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995) at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318) Error: One factory fails for the operation "filestore" Occurs in: javax.media.jai.ThreadSafeOperationRegistry 

this is due to a memory error.

whether it is available using Tiled Image Writer or Fragement Image Writer, we just convert a part of the image at a time, so we can work with ordinary memory, I think it could be called conversion using image segmentation.

EDIT

Directly write a png file using pngJ.

My goal is to transcode SVG canvas to PNG with 400 DPI

if I use PNGTranscoder for throwing an exception in memory for the specified image size.

so I used TiledImageTranscoder , which uses the following code to transcode SVG into an image.

 protected void transcode(Document document, String uri, TranscoderOutput output) throws TranscoderException { // Sets up root, curTxf & curAoi super.transcode(document, uri, output); Filter f = this.root.getGraphicsNodeRable(true); RenderContext rc = new RenderContext(curTxf, null, null); RenderedImage img = f.createRendering(rc); // prepare the image to be painted int w = img.getWidth(); int h = img.getHeight(); try { int bands = img.getSampleModel().getNumBands(); int[] off = new int[bands]; for (int i = 0; i < bands; i++) off[i] = i; SampleModel sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_BYTE, w, (100000 + w - 1) / w, bands, w * bands, off); RenderedImage rimg = new FormatRed(GraphicsUtil.wrap(img), sm); TIFFImageEncoder enc = new TIFFImageEncoder(output .getOutputStream(), null); enc.encode(rimg); } catch (IOException ioe) { ioe.printStackTrace(); } } 

, as you can see here, the above code finally uses TIFFImageEncoder to write to disk gradually and generates 1.30 GB of TIFF file in my case.

so I need to convert this generated file to a PNG file.

My question is here specifically for @leonbloy

you can use PNGWriter from the pngJ library here to directly write the png file using 400 DPI without memory errors, thereby we can also save time and avoid unnecessary conversion.

or

can we override the PngImageWriter writeImage method with the pngJ library so that we can achieve our goal?

Thanks Mihir Pareh

+5
source share
1 answer

You can try to find some TIFF decoder and JPEG / PNG encoder that support progressive (like one line at a time). This TIFF decoder seems to support it; PNGJ supports it.

Update. To try to connect PNGJ inside PNGTrasncoder, you don't care, but it's not that simple: you (or I or someone) must encode a bridge between the RenderedImage format and what PNGJ expects. (PNGJ is intentionally separated from java.awt.* ). It may seem interesting to me if I have the time, it seems like an interesting alternative to inclusion in Batik, the only limitation that I assume is that I do not support interlaced recording, but I do not think it is important.

+2
source