用 Java 编写图像元数据,最好是 PNG

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6495518/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 16:06:23  来源:igfitidea点击:

Writing image metadata in Java, preferably PNG

javaimagemetadata

提问by Alexis Laporte

I would like to write metadata to a PNG image that I create.

我想将元数据写入我创建的 PNG 图像。

My understanding of Java Advanced Image API is that I should use IIOMetadata, but code snippets I found seem overly complicated. Then I searched for a library and found Sanselanbut it seems a bit old, and not very handy for writingmetadata.

我对 Java Advanced Image API 的理解是应该使用IIOMetadata,但我发现的代码片段似乎过于复杂。然后我搜索了一个库并找到了Sanselan,但它似乎有点旧,并且不太适合编写元数据。

To actually create the image, I use

要实际创建图像,我使用

ImageIO.write(image, "png", baos);

I understand image metadatas are complex to handle due to its XML-like structure. Could anybody point me to a tutorial, solution, or library that will help?

我了解图像元数据由于其类似于 XML 的结构而难以处理。任何人都可以指出我有帮助的教程、解决方案或库吗?

回答by Rogel Garcia

I had to do the the same thing some days ago.. I have not found the exact solution on the internet either but looking at the com.sun.imageio.plugins.png.PNGMetadataclass I could achieve some results..

几天前我不得不做同样的事情com.sun.imageio.plugins.png.PNGMetadata

To write a custom metadata to a PNG file:

将自定义元数据写入 PNG 文件:

public byte[] writeCustomData(BufferedImage buffImg, String key, String value) throws Exception {
    ImageWriter writer = ImageIO.getImageWritersByFormatName("png").next();

    ImageWriteParam writeParam = writer.getDefaultWriteParam();
    ImageTypeSpecifier typeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);

    //adding metadata
    IIOMetadata metadata = writer.getDefaultImageMetadata(typeSpecifier, writeParam);

    IIOMetadataNode textEntry = new IIOMetadataNode("tEXtEntry");
    textEntry.setAttribute("keyword", key);
    textEntry.setAttribute("value", value);

    IIOMetadataNode text = new IIOMetadataNode("tEXt");
    text.appendChild(textEntry);

    IIOMetadataNode root = new IIOMetadataNode("javax_imageio_png_1.0");
    root.appendChild(text);

    metadata.mergeTree("javax_imageio_png_1.0", root);

    //writing the data
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ImageOutputStream stream = ImageIO.createImageOutputStream(baos);
    writer.setOutput(stream);
    writer.write(metadata, new IIOImage(buffImg, null, metadata), writeParam);
    stream.close();

    return baos.toByteArray();
}

Then, to read the data:

然后,读取数据:

public String readCustomData(byte[] imageData, String key) throws IOException{
    ImageReader imageReader = ImageIO.getImageReadersByFormatName("png").next();

    imageReader.setInput(ImageIO.createImageInputStream(new ByteArrayInputStream(imageData)), true);

    // read metadata of first image
    IIOMetadata metadata = imageReader.getImageMetadata(0);

    //this cast helps getting the contents
    PNGMetadata pngmeta = (PNGMetadata) metadata; 
    NodeList childNodes = pngmeta.getStandardTextNode().getChildNodes();

    for (int i = 0; i < childNodes.getLength(); i++) {
        Node node = childNodes.item(i);
        String keyword = node.getAttributes().getNamedItem("keyword").getNodeValue();
        String value = node.getAttributes().getNamedItem("value").getNodeValue();
        if(key.equals(keyword)){
            return value;
        }
    }
    return null;
}

回答by c00kiemon5ter

Java provides the metadatapackage and the ImageWriterclass along with the ImageIOpackage.

Java 提供metadata包和ImageWriter类以及ImageIO包。

You create your IIOMetadataobject, then getImageWritersfor your BufferedImageor IIOImageand use them to writethe metadata.

您创建您的IIOMetadata对象,然后getImageWriters用于您的BufferedImageIIOImage并将它们用于write元数据。

回答by leonbloy

To add to other answer, you can also try the PNGJlibrary, it has full metadata support.

要添加其他答案,您还可以尝试使用PNGJ库,它具有完整的元数据支持。

BTW, I don't understand what you are refering to with the "XML-like" structure of metadata.

顺便说一句,我不明白您在使用元数据的“类 XML”结构指的是什么。

回答by wakjah

Using the method from posted by the OP gets most of the way there; the only issue is that PNGMetadatais proprietary and so causes compiler warnings.

使用 OP 发布的方法可以获得大部分方法;唯一的问题是它PNGMetadata是专有的,因此会导致编译器警告。

There is a method of doing it without using the proprietary API, by searching the metadata tree for tEXtEntrynodes:

有一种方法可以在不使用专有 API 的情况下通过在元数据树中搜索tEXtEntry节点来实现:

private List<Node> findNodesWithName(String name, Node root) {
    List<Node> found = new ArrayList<>();
    Node n = root.getFirstChild();
    while (n != null) {
        if (n.getNodeName().equals(name)) {
            found.add(n);
        }
        found.addAll(findNodesWithName(name, n));
        n = n.getNextSibling();
    }
}

// ...
// To use it:
IIOMetadata metadata = ...;
List<Node> tEXtNodes = findNodesWithName(
        "tEXtEntry",
        metadata.getAsTree(metadata.getNativeMetadataFormatName()));

for (Node n : tEXtNodes) {
    String keyword = node.getAttributes().getNamedItem("keyword");
    String value = node.getAttributes().getNamedItem("value");
    System.out.println("keyword: " + keyword + "; value: " + value);
}