【问题标题】:Is there a equivalent of Android's BitmapFactory.Options isDecodeBounds for TIFF in Java/JAI?Java/JAI 中的 TIFF 是否有相当于 Android 的 BitmapFactory.Options isDecodeBounds?
【发布时间】:2013-03-26 18:55:27
【问题描述】:

我正在尝试提高我们系统的性能(一个运行在Tomcat中的Java应用程序),现在瓶颈在于一次操作,我们需要读取并返回tiff图像的维度,所以我们使用JAI的ImageDecoder并使用

ImageDecoder decoder = ImageCodec.createImageDecoder("TIFF", input, param);
RenderedImage r = decoder.decodeAsRenderedImage();
int width = r.getWidth();
int height = r.getHeight();

从采样数据来看,createImageDecoder 花费了很多时间。我的假设(不去 ImageCodec 的源代码)是它可能试图解码输入流。

来自 Android 领域,我希望有一个类似的解决方案来解码边界,例如设置 BitmapFactory.Options.inJustDecodeBounds = true,但到目前为止还没有找到任何其他类似的库。 (我知道 AOSP 中缺少对 Android 的 tiff 支持,但这是另一天的话题。)

有人知道有这样的图书馆吗?或者有没有办法使用 JAI/ImageIO 实现类似的目标?

【问题讨论】:

  • 专门针对 TIFF 文件,还是针对 Java 支持的所有图像格式?
  • @RussellZahniser 专门针对 Tiff,如果可能的话。 (由于尺寸限制,我们无法切换到其他格式)
  • 我会试试你上面的帖子,谢谢!
  • 不幸的是,即使在我将 jai_imageio lib jar 放入我的类路径之后,我也无法让它与 Tif 一起使用 :-(

标签: java image jai


【解决方案1】:

看起来tiff file format 将这些信息组合在一个标头中,因此您可以自己从文件中读取数据:

private static Dimension getTiffDimensions(InputStream tiffFile) throws IOException {
    ReadableByteChannel channel = Channels.newChannel(tiffFile);

    ByteBuffer buffer = ByteBuffer.allocate(12);

    forceRead(channel, buffer, 8);
    byte endian = buffer.get();
    if(endian != buffer.get() || (endian != 'I' && endian != 'M')) {
        throw new IOException("Not a tiff file.");
    }

    buffer.order(endian == 'I' ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
    if(buffer.getShort() != 42) {
        throw new IOException("Not a tiff file.");
    }

    // Jump to the first image directory. Note that we've already read 8 bytes.
    tiffFile.skip(buffer.getInt() - 8);

    int width = -1;
    int height = -1;
    // The first two bytes of the IFD are the number of fields.
    forceRead(channel, buffer, 2);
    for(int fieldCount = buffer.getShort(); fieldCount > 0 && (width < 0 || height < 0); --fieldCount) {
        forceRead(channel, buffer, 12);
        switch(buffer.getShort()) {
        case 0x0100: // Image width
            width = readField(buffer);
            break;
        case 0x0101: // Image "length", i.e. height
            height = readField(buffer);
            break;
        }
    }
    return new Dimension(width, height);
}

private static void forceRead(ReadableByteChannel channel, ByteBuffer buffer, int n) throws IOException {
    buffer.position(0);
    buffer.limit(n);

    while(buffer.hasRemaining()) {
        channel.read(buffer);
    }
    buffer.flip();
}

private static int readField(ByteBuffer buffer) {
    int type = buffer.getShort();
    int count = buffer.getInt();

    if(count != 1) {
        throw new RuntimeException("Expected a count of 1 for the given field.");
    }

    switch(type) {
    case 3: // word
        return buffer.getShort();
    case 4: // int
        return buffer.getInt();
    default: // char (not used here)
        return buffer.get() & 0xFF;
    }
}

我已经用几个不同的 tiff 文件(运行长度编码的黑白、带透明度的颜色)对此进行了测试,它似乎工作正常。根据您的 tiff 文件的布局,它可能必须在找到大小之前读取大量流(我测试的文件之一,由 Apple 的 Preview 保存,文件末尾有此数据)。

【讨论】:

  • 哇,非常感谢,一旦我验证它也适用于我的文件,我将对此进行测试并标记为答案!
  • 适用于我们的 TIFF 文件!标记为答案!
  • 在我的慢机器上进行快速比较,原始方法在 1600 个 tiff 上花费了 10139 毫秒,而您的方法在相同的 tiff 上只花费了 244 毫秒!哇!
猜你喜欢
  • 2019-04-24
  • 2014-01-08
  • 1970-01-01
  • 1970-01-01
  • 2020-11-26
  • 2014-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多