2013-03-15 30 views
5

我有一個tiff文件,尺寸爲18000 * 18000,尺寸爲1.20 GB。 tiff有72 DPI。如何將巨大的TIFF圖像轉換爲PNG/JPEG而不會出現內存不足錯誤?

我想使用400 DPI將此TIFF轉換爲PNG/JPEG。

我使用以下代碼來做到這一點

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

上面的代碼完全適用於更小的圖像,然後例如TIFF圖像小於5000在尺寸* 5000可以很容易地轉換爲JPEG/PNG指定的圖像[雖然我需要改變的PNG編碼器],

但是當我嘗試運行相同的代碼上面提到的文件時,它拋出以下異常

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 

這是因爲內存不足錯誤。

有任何平鋪圖像Writer或Fragement的形象,作家使用它,我們只是在一個時間轉換的圖像的一部分,因此,我們可以用正常的存儲工作提供 我想可能使用的圖像分割被稱爲轉換可用。

編輯

使用pngJ直接寫入PNG文件。

我的目的是,如果我使用PNGTranscoder的,它會因提到的圖像大小的內存溢出異常轉碼SVG畫布PNG與400 DPI

所以我用TiledImageTranscoder它使用下面的代碼將SVG轉碼爲圖像。

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

所以你可以在這裏看到上面的代碼使用最後TIFFImageEncoder逐步寫入到磁盤,並在我的情況產生1.30 GB的TIFF文件的。

所以這就是爲什麼我需要將此生成的文件轉換爲PNG文件。

我這裏的問題是專門爲@leonbloy

我們可以在這裏使用PNGWriter從pngJ庫直接寫入使用400 DPI沒有內存不足錯誤的PNG文件,通過這種方式,我們可以節省時間,以及和避免不必要的轉換

我們可以覆蓋PngImageWriter的writeImage法pngJ庫,以便我們能夠實現我們的目標?

謝謝 米希爾Parekh的

+1

您是否嘗試過'-Xmx' VM參數?像'-Xmx3G'這樣的最大內存使用量是3千兆字節。 – jlordo 2013-03-15 17:34:05

+0

@jlordo請不要建議我這個參數我想運行這個代碼只使用64 - 512 MB的堆內存。建議我圖像分割 – Mihir 2013-03-15 17:39:10

+0

我們有類似的問題。但是,我們使用本機操作系統工具來處理。調用tiff2png命令並讓操作系統處理內存問題。請參閱http://www.libpng.org/pub/png/apps/tiff2png.html。 Linux機器上默認提供的工具。 – nobody 2013-03-17 21:19:06

回答

2

你可以嘗試找一些TIFF解碼器以及JPEG/PNG編碼器,支持逐行掃描(例如,一個排在一個時間)處理。這TIFF decoder似乎支持它; PNGJ支持它。

更新:嘗試插入PNGJ內部PNGTrasncoder似乎要走的路,但它不是那麼容易:你(或我,或某人)必須編碼RenderedImage格式和PNGJ期望之間的橋樑。 (PNGJ有意從java.awt.*解耦)。當我有一段時間時,它可能會讓它看起來,這似乎是一個有趣的選擇,包括在蠟染,我預見的唯一限制是,我不支持隔行文字,但我認爲這不相關。

+0

我閱讀了您的推薦鏈接,我認爲他們是我正在尋找的人,我可以在從TIFF轉換爲PNG時設置DPI信息嗎? – Mihir 2013-03-16 05:28:49

+0

是的,請參閱'PngWriter.getMetadata()。setDpi()' – leonbloy 2013-03-16 12:52:21

+0

我會明天嘗試,讓你知道PNG。你知道JPEG漸進式作家一樣嗎? – Mihir 2013-03-16 16:46:55

相關問題