2016-04-02 29 views
2

處理我有一個Android應用程序需要的照片,將它們轉換利用爲位圖:照片無法通過的ImageIO

private Bitmap generateBitmap(byte[] data) { 
    Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length); 
    Matrix mat = new Matrix(); 
    mat.postRotate(-90); 
    return Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), 
      bmp.getHeight(), mat, true); 
} 

然後PNG使用:

bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream); 

然後將outputStream發佈(multipart/form-data)到我的web服務器(jboss)。在服務器上,JAX-RS和MultipartForm它轉換成一個數據[],併發送爲開頭的額外處理:

BufferedImage image = ImageIO.read(new ByteArrayInputStream(form.getImageFileData())); 

應用程序是在生產,工作正常,一直到現在。我們激活上週(三星Galaxy Note EDGE)和每一張照片他上傳生成javax.imageio.IIOException: Error reading PNG image data當調用ImageIO.read()在堆棧跟蹤的根本原因是新用戶:

Caused by: java.util.zip.ZipException: incorrect data check 

的照片顯示正常在瀏覽器中,但由於此例外,我無法完全處理它們。我也可以在編輯器中打開它們,將它們旋轉360度,重新保存它們,然後處理它們就好了。

任何人都可以幫助我理解什麼可能會導致此問題在這一臺設備上,或建議我可以在服務器上做些什麼來解決它,仍然生成我需要進一步處理的BufferedImage?手動編輯每張照片不是一種選擇。

更新:如建議,我跑了pngcheck從這個設備的14張照片。它返回了2個有效的和12個無效的錯誤:zlib: inflate error = -3 (data error)。如上所述,所有14個使用ImageIO失敗。

這個問題的圖像可以看出:https://tracweb-safecommunity.rhcloud.com/rest/monitoredProfile/106/testResult_8284.png

+0

'引起︰java.util.zip.ZipException:不正確的數據檢查' - PNG文件不是ZIP文件。 – CommonsWare

+0

a)圖像有各種不同的類型 - 也許這個圖像不被imageio識別 - 你必須開始閱讀像素字節並重建圖像b)這個png是否可以作爲圖像顯示?那麼它可能是字節的傳輸bitmap.compress(Bitmap.CompressFormat.PNG,100,outputStream); – gpasch

+0

因此,bitmap.compress在這款手機上的功能不同,或者ImageIO不喜歡這款手機中所有照片的獨特之處?兩者似乎都不太可能,但這也是我想出的。除非任何人有更好的主意,否則我可以爲這個使用jpg代替png的人創建一個測試應用程序。 – Jonathon

回答

2

對我來說,這真的好像是特定設備(供應商特定的OS建立?)生成破PNG格式。但是,似乎唯一缺少的是Zip/zlib數據完整性檢查值,如果忽略數據完整性檢查,則可以正確重構映像。

出於某種原因,我的原始答案(下)不適用於OP。因此,這裏是只使用ImageIO的替代(更詳細)做法:

InputStream input = new ByteArrayInputStream(form.getImageFileData()); 
Iterator<ImageReader> readers = ImageIO.getImageReaders(input); 

if (!readers.hasNext()) { 
    // TODO: Handle, return null or throw exception, whatever is more appropriate 
} 

ImageReader reader = readers.next(); 
reader.setInput(input); 

try { 
    ImageReadParam param = reader.getDefaultReadParam(); 
    int imageNo = 0; 

    int width = reader.getWidth(imageNo); 
    int height = reader.getHeight(imageNo); 

    // If possible, create a destination image up front 
    ImageTypeSpecifier type = reader.getRawImageType(imageNo); 
    if (type != null) { 
     param.setDestination(type.createBufferedImage(width, height)); 
    } 

    // Decode into the destination 
    BufferedImage image; 
    try { 
     image = reader.read(imageNo, param); 
    } 
    catch (IOException e) { 
     if (e.getCause() instanceof ZipException && param.getDestination() != null) { 
      // If we got here, the destination will contain a partial image 
      // We'll use that. 
      image = param.getDestination(); 
     } 
     else { 
      throw e; 
     } 
    } 
} 
finally { 
    input.close(); 
} 

圖像的最後一行將缺少因ZipException,否則,成像效果很不錯。


下面是使用Java的一種可能的解決方法。我已經在OS X上測試過了,它適用於我,使用提供的測試文件同時使用Java 1.7.0_71和1.8.0_51(都是Oracle JRE)。堆棧跟蹤打印到控制檯,以及圖像的最後一行缺少,否則,它看起來不錯:

byte[] data = form.getImageFileData(); 
Image tmp = Toolkit.getDefaultToolkit().createImage(data); 
BufferedImage image = new BufferedImageFactory(tmp).getBufferedImage(); 

這將是比使用ImageIO慢一點,所以我建議你先用ImageIO嘗試和以前一樣,那麼只有在java.util.zip.ZipException根本原因失敗時才使用此代碼作爲回退。

PS:你可以使用MediaTracker完全加載(或使用ImageIcon黑客),然後畫結果爲BufferedImage也一樣,如果你不介意失去一些精度,如可能轉換ImageBufferedImage原來的顏色模式等


BufferedImageFactory類是我TwelveMonkeys的ImageIO庫的一部分,是在BSD許可證可用,可以發現on GitHub

+0

本週晚些時候我會檢查一下(昨天有些緊急事件),並讓你知道它是如何發生的。 – Jonathon

+0

我把它插入,現在接收com.twelvemonkeys.image.ImageConversionException:圖像轉換失敗:ImageConsumer.IMAGEERROR'在com.twelvemonkeys.image.BufferedImageFactory $ Consumer.imageComplete(BufferedImageFactory.java:478)''拋出''。而不是破壞客戶,我正在測試已經上傳的圖像文件,所以而不是'byte [] data = form.getImageFileData();'我正在使用'byte [] data = IOUtils.toByteArray(fileInputStream);'in情況有所不同。 – Jonathon

+0

堆棧跟蹤: '在com.twelvemonkeys.image.BufferedImageFactory $ Consumer.imageComplete(BufferedImageFactory.java:478) 在sun.awt.image.InputStreamImageSource.errorConsumer(InputStreamImageSource.java:147) 在sun.awt.image .InputStreamImageSource.errorAllConsumers(InputStreamImageSource.java:140) 在sun.awt.image.InputStreamImageSource.badDecoder(InputStreamImageSource.java:294) 在sun.awt.image.InputStreamImageSource.doFetch(InputStreamImageSource.java:265) 在太陽.awt.image.ImageFetcher.fetchloop(ImageFetcher.java:205) at sun.awt.image.ImageFetcher.run(ImageFetcher.java:169)' – Jonathon