在Java中编写图像元数据,最好是PNG格式

20

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

据我对Java高级图像API的理解,应该使用IIOMetadata,但我找到的代码片段似乎过于复杂。然后我搜索了一个库,并找到了Sanselan,但它似乎有点旧,并且不太方便写入元数据。

要实际创建图像,我使用

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

我了解图像元数据由于其类似XML的结构而难以处理。有人能否指点我一下教程、解决方案或库,以帮助我处理它们呢?


1
你是怎么让它工作的?你能分享一下你的代码,或者回答这个问题:http://stackoverflow.com/questions/24714345/unable-to-read-write-image-metadata-in-java - Ali
使用这个库,只需调用PNGTweaker.insertTextChunk(ChunkType.TEXT, "keyword", "value", is, os),即可轻松实现。 - dragon66
4个回答

31

几天前我也需要做同样的事情... 我也没有在互联网上找到确切的解决方案,但是查看com.sun.imageio.plugins.png.PNGMetadata类后,我得到了一些结果..

要将自定义元数据写入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();
}

然后,要读取数据:

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;
}

非常有帮助!只需要进行一些小的修改,就可以处理'iTXt'数据而不是'tEXt'数据。非常感谢! - hohonuuli
@Rogel Garcia,你在这个项目中使用哪个库? - Ankesh kumar Jaisansaria
@AnkeshkumarJaisansaria 很抱歉回复晚了... 我只是使用常规的Java类.. 没有使用任何库(Oracle分发) - Rogel Garcia
有一个常量IIOMetadataFormatImpl.standardMetadataFormatName可以用来替代字面上的"javax_imageio_png_1.0"。 - abyrd

1

0
补充其他答案,您还可以尝试使用PNGJ库,它具有完整的元数据支持。
顺便说一下,我不明白您所指的元数据的“类似XML”的结构是什么意思。

看起来非常有前途,我会试一试。谢谢! - Alexis Laporte
元数据可能包含复杂的层次结构。Java XML文档对象模型(DOM)API用于表示这些结构... https://docs.oracle.com/javase/8/docs/technotes/guides/imageio/spec/apps.fm5.html - abyrd

0

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

有一种方法可以在不使用专有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);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接