ImageIO无法处理在单个用户的Android手机上拍摄的照片

时间:2016-04-02 20:26:39

标签: java android png javax.imageio

我有一个Android应用程序拍摄照片,使用以下方法将它们转换为位图:

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将其转换为data []并发送以进行以下开头的其他处理:

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

该应用程序已投入生产并按预期工作,直到现在。我们上周激活了一个新用户(三星Galaxy Note Edge),当我调用ImageIO.read()时,他上传的每张照片都生成javax.imageio.IIOException: Error reading PNG image data,其中堆栈跟踪的根本原因是:

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

照片在浏览器中正常显示,但由于此异常,我无法完全处理它们。我也可以在编辑器中打开它们360度旋转,重新保存它们然后处理它们就好了。

任何人都可以帮助我理解这个问题可能会导致这个问题,或者建议我可以在服务器上解决这个问题并仍然生成我需要进一步处理的BufferedImage吗?手动编辑每张照片不是一种选择。

更新:正如所建议的那样,我在这台设备的14张照片上运行了pngcheck。它返回2个有效,12个无效,错误:zlib: inflate error = -3 (data error)。如上所述,所有14个都使用ImageIO失败。

可以在以下位置查看出现此问题的图片:https://tracweb-safecommunity.rhcloud.com/rest/monitoredProfile/106/testResult_8284.png

1 个答案:

答案 0 :(得分:2)

对我而言,似乎特定设备(特定于供应商的操作系统构建?)会产生损坏的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:您可以使用ImageBufferedImage转换为MediaTracker以完全加载它(或使用ImageIcon hack),然后将结果绘制到一个BufferedImage,如果你不介意失去一些精确度,比如原始的颜色模型等。

BufferedImageFactory类是我的TwelveMonkeys ImageIO库的一部分,可在BSD许可下使用,可以找到on GitHub