5

i have a tiff file 18000 * 18000 in Dimension and 1.20 GB in size. the tiff has 72 DPI.

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

I am using following code to do it

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 perfectly works for smaller images then the specified image for example tiff image less than 5000 * 5000 in Dimension can be easily converted to JPEG / PNG [though i need to change the PNG encoder] ,

but when i try to run the same code for above mentioned file it throws an 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 because of Out of memory error.

is there any Tiled Image Writer or Fragement Image Writer available using it we will just convert a portion of an image at a time , thus we can work with normal memory available i think it might be called convert using image segmentation.

EDIT

Directly write png file using pngJ.

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

if i use PNGTranscoder for that it throws an Out of memory exception for mentioned image size.

so i have used TiledImageTranscoder which uses following code to transcode SVG to 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();
        }
    }

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

so that's why i need to convert this generated file to PNG file.

my question here is specially for @leonbloy

can we use here PNGWriter from pngJ library to directly write the png file using 400 DPI without out of memory error , by this way we can save time as well and avoid unnecessary conversion.

or

can we Override PngImageWriter's writeImage method with pngJ library so we can achieve our goal ?

Thank You Mihir Parekh

Mihir
  • 2,480
  • 7
  • 38
  • 57
  • 1
    Have you tried the `-Xmx` VM parameter? Something like `-Xmx3G` to allow the maximum memory usage be 3 gigabyte. – jlordo Mar 15 '13 at 17:34
  • @jlordo please don't suggest me this parameter i want to run this code using only 64 - 512 mb of heap memory.suggest me image segmentation – Mihir Mar 15 '13 at 17:39
  • We have a similar problem. However we use native OS tool to handle that. Invoke tiff2png command and let OS handle the memory problem. See http://www.libpng.org/pub/png/apps/tiff2png.html . Tools available on Linux machines by default. – nobody Mar 17 '13 at 21:19
  • @nobody and what about other os like windows , Mac and all ? – Mihir Mar 18 '13 at 04:06
  • We have a client server app. So we know what server it runs on. May be that's not your case. – nobody Mar 18 '13 at 19:14
  • @nobody i downloaded tiff2png and installed in my window pc. can you give me an example of what command you give to convert ? is it possible to convert file with some dpi setting ? – Mihir Mar 19 '13 at 03:37
  • tiff2png [-verbose] [-force] [-destdir ] [-compression ] [-gamma ] [-interlace] [-invert] – nobody Mar 19 '13 at 18:11
  • @nobody i will check and let you know. – Mihir Mar 20 '13 at 04:16

1 Answers1

2

You might try to find some TIFF-decoder and JPEG/PNG encoder that support progressive (eg one row at a time) processing. This TIFF decoder seems to support it; PNGJ supports it.

Update: To try to plug PNGJ inside PNGTrasncoder seems the way to go, but it's not so easy: you (or I, or somebody) must code the bridge between the RenderedImage format and that that PNGJ expects. (PNGJ is intentionally decoupled from java.awt.*). It might give it a look when I have some time, it seems an interesting alternative to include in Batik, the only limitation I foresee is that I don't support interlaced writing, but I don't think that's relevant.

leonbloy
  • 73,180
  • 20
  • 142
  • 190
  • i read your recommended links , i think they are the one i am looking for , can i set DPI information while converting from TIFF to PNG ? – Mihir Mar 16 '13 at 05:28
  • Yes, see `PngWriter.getMetadata().setDpi()` – leonbloy Mar 16 '13 at 12:52
  • i will try tomorrow and let you know for PNG . do you know same about JPEG progressively writer ? – Mihir Mar 16 '13 at 16:46
  • No. BTW, I'm the author of the PngJ library – leonbloy Mar 17 '13 at 01:53
  • great to meet you i have updated the question. please look through it and if possible provide me some example this time , i have been reading for pngj since it suggested by you – Mihir Mar 17 '13 at 11:53
  • thanks for your update , now back to our previous solution how can i provide tiff image to PNGWriter ? can you give me an example with some demo code ? i tried but could not succeed ? – Mihir Mar 18 '13 at 04:10
  • you might help me for this question http://stackoverflow.com/questions/15452656/raster-bitmap-to-vector – Mihir Mar 18 '13 at 04:20
  • i have decided to use pngj for writing pngj can you give me an example how can i write png file using your mentioned tiffdecoder ? – Mihir Mar 18 '13 at 14:53
  • Sorry, I haven't used the TIFF decoder, to write using PngWriter is quite simple... once you have the row in the proper format (one integer per sample). The task can be simpler if you can restrict to some particular color model – leonbloy Mar 18 '13 at 20:59
  • please help me on this question http://stackoverflow.com/questions/15598872/write-png-file-with-less-disk-size-in-java – Mihir Mar 24 '13 at 13:11