2013-03-15 18 views
5

Mam plik tiff 18000 * 18000 w wymiarze i 1,20 GB w rozmiarze. tiff ma 72 DPI.Jak przekonwertować ogromny obraz TIFF do PNG/JPEG bez błędu braku pamięci?

Chcę przekonwertować ten TIFF na PNG/JPEG używając 400 DPI.

Używam poniższy kod, żeby to zrobić

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

powyższy kod działa idealnie do mniejszych obrazów wtedy określony obraz na przykład TIFF mniej niż 5000 * 5000 na wymiar może być łatwo przekształcone w formacie JPEG/PNG [choć muszę zmienić kodera PNG]

ale gdy próbuję uruchomić tego samego kodu dla wyżej wymienionego pliku zgłasza następujący wyjątek

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 

jest to spowodowane błędem braku pamięci.

jest jakiś marmurowa Writer Obraz lub Fragement Obraz Writer dostępny go używać będziemy tylko przekształcić część obrazu w czasie, więc możemy pracować z normalnej pamięci dostępnej myślę, że można by nazwać konwersji za pomocą segmentacji obrazu .

EDIT

Bezpośrednio napisać png plik używając pngJ.

Moim celem jest transkodowanie kanwę SVG do PNG 400 DPI

przypadku korzystania PNGTranscoder na to, że rzuca Out of wyjątkiem pamięci dla wspomnianej wielkości obrazu.

więc użyłem TiledImageTranscoder, który używa następującego kodu do transkodowania SVG do obrazu.

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

tak jak widać tutaj powyższy kod wykorzystuje wreszcie TIFFImageEncoder stopniowe napisać na dysku i generuje 1,30 GB plik TIFF w moim przypadku.

dlatego potrzebuję przekonwertować wygenerowany plik na plik PNG.

moje pytanie o to specjalnie dla @leonbloy

możemy użyć tutaj PNGWriter z biblioteki pngJ napisać bezpośrednio do pliku PNG, używając 400 dpi bez out błędu pamięci, w ten sposób możemy zaoszczędzić czas, jak również i unikaj niepotrzebnej konwersji.

lub

możemy Zastąp metodę writeImage PngImageWriter jest z biblioteką pngJ więc możemy osiągnąć nasz cel?

Dziękuję Mihir PAREKH

+1

Czy wypróbowałeś parametr VM '-Xmx'? Coś jak "-Xmx3G", aby maksymalne wykorzystanie pamięci było 3 gigabajtowe. – jlordo

+0

@jlordo proszę nie sugerować mi tego parametru chcę uruchomić ten kod przy użyciu tylko 64 - 512 mb pamięci. Perug mnie mnie segmentacja obrazu – Mihir

+0

Mamy podobny problem. Jednak używamy rodzimego narzędzia systemu operacyjnego do obsługi tego. Wywołaj polecenie tiff2png i pozwól systemowi obsługiwać problem z pamięcią. Zobacz http://www.libpng.org/pub/png/apps/tiff2png.html. Narzędzia domyślnie dostępne na komputerach z systemem Linux. – nobody

Odpowiedz

2

Można spróbować znaleźć jakieś TIFF-dekoder i JPEG/PNG koder obsługuje progresywnego (np jeden wiersz na raz) przetwarzania. Ten TIFF decoder wydaje się go wspierać; PNGJ obsługuje to.

Aktualizacja: Aby spróbować podłączyć wtyczkę PNGJ do PNGTrasncodera, wydaje się, że do zrobienia, ale nie jest to takie proste: Ty (lub ja, lub ktoś) musimy zakodować most między formatem RenderedImage a tym, czego oczekuje PNGJ. (PNGJ jest celowo odłączony od java.awt.*). Mogę rzucić okiem, kiedy mam trochę czasu, wydaje się interesującą alternatywą do włączenia do Batik, jedynym ograniczeniem, które przewiduję, jest to, że nie popieram pisania z przeplotem, ale nie sądzę, że jest to istotne.

+0

Czytam polecane przez ciebie linki, myślę, że są tymi, których szukam, czy mogę ustawić informacje o DPI podczas konwersji z TIFF do PNG? – Mihir

+0

Tak, zobacz 'PngWriter.getMetadata(). SetDpi()' – leonbloy

+0

Spróbuję jutro i powiadomię Cię o PNG. Czy wiesz o progresywnym pisaniu JPEG? – Mihir