【问题标题】:Determine DPI of Image in Java在Java中确定图像的DPI
【发布时间】:2017-11-09 01:22:08
【问题描述】:

我有一个 TIFF 图像已读入我的应用程序并存储在 BufferedImage 对象中。如何使用 Java 高级成像 (JAI) API 确定图像的水平和垂直 DPI?我一直在环顾四周,但找不到直接的方法来实现这一点。

【问题讨论】:

  • 如果你只有一个BufferedImage,那你就不走运了。如果你有一个文件、流或类似的引用,我建议查看ImageIO API,尤其是ImageReader.getImageMetadata() ,从那里获取 DPI 应该相当简单。
  • 数据以来自 Web 服务调用的字节数组形式提供给我。我想我可以回到最初从字节数组中读取它的点来尝试ImageReader。然后将 DPI 信息传递到我需要它的位置。我的下一个绊脚石似乎是,当我尝试使用ImageIO.getImageReadersByFormatName("tiff") 加载阅读器时,它说它找不到该类型的阅读器。还在想办法解决这个问题。
  • 我不断发现 Java 成像 API 有多么复杂,而我对它们知之甚少......
  • 很难不同意复杂性.. :-/ TIFF 问题:有几个用于 ImageIO 的 TIFF 插件。您可以使用 jai-imageio,它支持标准和原生格式的元数据。我也想推荐我自己的插件,但它还不支持元数据。 :-)
  • 你的插件是什么?不确定我是否会在这个项目中使用它,但将来了解它可能会有用。

标签: java jai


【解决方案1】:

这是使用标准 ImageIO API 和标准元数据格式提取 DPI(实际上是每毫米像素)的完整示例。复杂性,我们来了... :-P

public class DPITest {
    public static void main(String[] args) throws IOException {
        File input = new File(args[0]);

        ImageInputStream stream = ImageIO.createImageInputStream(input);
        Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);

        if (readers.hasNext()) {
            ImageReader reader = readers.next();
            reader.setInput(stream);

            IIOMetadata metadata = reader.getImageMetadata(0);
            IIOMetadataNode standardTree = (IIOMetadataNode) metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
            IIOMetadataNode dimension = (IIOMetadataNode) standardTree.getElementsByTagName("Dimension").item(0);
            float horizontalPixelSizeMM = getPixelSizeMM(dimension, "HorizontalPixelSize");
            float verticalPixelSizeMM = getPixelSizeMM(dimension, "VerticalPixelSize");

            // TODO: Convert pixelsPerMM to DPI left as an exercise to the reader.. ;-)  

            System.err.println("horizontalPixelSizeMM: " + horizontalPixelSizeMM);
            System.err.println("verticalPixelSizeMM: " + verticalPixelSizeMM);
        }
        else {
            System.err.printf("Could not read %s\n", input);
        }
    }

    private static float getPixelSizeMM(final IIOMetadataNode dimension, final String elementName) {
        // NOTE: The standard metadata format has defined dimension to pixels per millimeters, not DPI...
        NodeList pixelSizes = dimension.getElementsByTagName(elementName);
        IIOMetadataNode pixelSize = pixelSizes.getLength() > 0 ? (IIOMetadataNode) pixelSizes.item(0) : null;
        return pixelSize != null ? Float.parseFloat(pixelSize.getAttribute("value")) : -1;
    }
}

一些参考资料:

【讨论】:

  • 哇,他们绝对不会让 JAI 很容易弄清楚......我真的觉得我有时会搞砸它(而且我对 Java 并不完全陌生)。所以,看起来我可以将InputStream 传递给ImageIO.createImageInputStream 而不是File,这应该适用于我正在做的事情。当我星期一回到办公室时会试试这个。感谢您的信息!
  • @Michael 这只是 ImageIO API,不是 JAI 特定的(但 jai-imageio 确实提供了实现此 API 的 TIFF ImageReader 插件),因此请尝试使用谷歌搜索。但不确定是否有“权威指南”...InputStream 应该可以。我会用一些指针更新答案。
  • 那不是整数,fe: 0.0846 for 300DPI,使用 Double.valueOf 代替
  • @DanielHári 好收获!在格式中,值被定义为“Float”,所以我更新了代码以使用它(float)。 double 也可以。
【解决方案2】:

用于获取图像信息的 Apache Commons Sanselan 库:http://commons.apache.org/imaging/index.html

final ImageInfo imageInfo = Sanselan.getImageInfo(file);

final int physicalWidthDpi = imageInfo.getPhysicalWidthDpi();
final int physicalHeightDpi = imageInfo.getPhysicalHeightDpi();

【讨论】:

  • 不使用 Commons Imaging 就没有办法做到这一点吗?我宁愿不必为这项任务包含一个额外的库。此外,要使用此方法,我必须将其编码回字节数组。如果我没有在TIFFEncodeParam 中指定 DPI 设置,那么上面的代码会为这两个值返回 -1。如果我为编码器指定 DPI 设置,我会得到一个值,但显然它将是我指定的 DPI,而不是图像的原始值。
猜你喜欢
  • 2016-08-18
  • 1970-01-01
  • 2017-02-24
  • 2011-10-31
  • 1970-01-01
  • 2013-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多