2013-03-15 12 views
5

Ho un file tiff 18000 * 18000 in Dimensione e dimensioni 1,20 GB. il tiff ha 72 DPI.Come posso convertire un'enorme immagine TIFF in PNG/JPEG senza errori di memoria esauriti?

Voglio convertire questo TIFF in PNG/JPEG usando 400 DPI.

Sto usando seguente codice per farlo

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; 
      } 

il codice precedente funziona perfettamente per le immagini più piccole, allora l'immagine specificata immagine esempio tiff meno di 5000 * 5000 in Dimension può essere facilmente convertito in JPEG/PNG per [anche se ho bisogno di cambiare l'encoder PNG],

ma quando si tenta di eseguire lo stesso codice per il file di cui sopra viene generata seguente eccezione

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 

questo a causa dell'errore di memoria insufficiente.

c'è qualche piastrella Image Writer o Fragement Image Writer disponibile ad usarlo ci limiteremo a convertire una porzione di un'immagine alla volta, così possiamo lavorare con la memoria normale disponibili penso che potrebbe essere chiamato convertito utilizzando la segmentazione di immagini .

EDIT

scrivere direttamente file PNG utilizzando pngJ.

Il mio scopo è quello di transcodifica tela SVG in PNG con 400 DPI

se io uso PNGTranscoder per ciò che getta un'eccezione di memoria per dimensioni dell'immagine menzionato.

così ho usato TiledImageTranscoder che usa il seguente codice per transcodificare SVG in Immagine.

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(); 
     } 
    } 

così come si può vedere qui il codice sopra usa finalmente TIFFImageEncoder scrivere progressivamente su disco e genera 1,30 GB di file TIFF nel mio caso.

ecco perché ho bisogno di convertire questo file generato in file PNG.

la mia domanda qui è specialmente per @leonbloy

possiamo usare qui PNGWriter dalla libreria pngJ di scrivere direttamente il file PNG con 400 DPI senza errore di memoria, in questo modo siamo in grado di risparmiare tempo come bene e evitare conversioni inutili.

o

possiamo override metodo writeImage PngImageWriter s' con biblioteca pngJ così possiamo raggiungere il nostro obiettivo?

Thank You Mihir Parekh

+1

Hai provato il parametro VM '-Xmx'? Qualcosa come '-Xmx3G' per consentire un utilizzo massimo della memoria di 3 gigabyte. – jlordo

+0

@jlordo per favore non suggerirmi questo parametro voglio eseguire questo codice usando solo 64 - 512 mb di memoria heap.seguimi segmentazione dell'immagine – Mihir

+0

Abbiamo un problema simile. Tuttavia usiamo uno strumento nativo per gestirlo. Richiama il comando tiff2png e lascia che il SO gestisca il problema di memoria. Vedi http://www.libpng.org/pub/png/apps/tiff2png.html. Strumenti disponibili su macchine Linux per impostazione predefinita. – nobody

risposta

2

Si potrebbe cercare di trovare qualche TIFF-decoder ed encoder/PNG JPEG che supportano progressiva (ad esempio, una riga alla volta) di elaborazione. Questo TIFF decoder sembra supportarlo; PNGJ lo supporta.

Aggiornamento: Per provare a collegare PNGJ all'interno di PNGTrasncoder sembra la strada da percorrere, ma non è così semplice: tu (o io, o qualcuno) dobbiamo codificare il bridge tra il formato RenderedImage e quello che PNGJ si aspetta. (PNGJ è intenzionalmente disaccoppiato da java.awt.*). Potrebbe dargli un'occhiata quando ho un po 'di tempo, sembra un'alternativa interessante da includere in Batik, l'unica limitazione che prevedo è che non sostengo la scrittura interlacciata, ma non penso che sia rilevante.

+0

ho letto i link consigliati, penso che siano quelli che sto cercando, posso impostare le informazioni DPI durante la conversione da TIFF a PNG? – Mihir

+0

Sì, vedi 'PngWriter.getMetadata(). SetDpi()' – leonbloy

+0

proverò domani e ti farò sapere per PNG. conosci lo stesso di JPEG progressivamente? – Mihir

Problemi correlati