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

时间:2011-06-27 15:53:34

标签: java image metadata

来自stackoverflow的人们,

我花了一些时间在谷歌搜索我的问题的解决方案,但没有什么伟大的出现。

我想将元数据写入我从头开始创建的图像。

我对Java Advanced Image API的理解是我应该使用IIOMetadata,但我发现的代码片段似乎过于复杂。

然后我搜索了一个图书馆并找到了Sanselan,但它看起来有点老了,而且元数据并不是很方便。

我实际上是使用创建图像     ImageIO.write(image,“png”,baos);

我理解图像metadatas由于其类似XML的结构而有点复杂。

有人能指点我一个教程,一个解决方案,一个库......?

谢谢, 亚历。

4 个答案:

答案 0 :(得分:25)

前几天我不得不做同样的事情。我还没有找到互联网上的确切解决方案,但是看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;
}

答案 1 :(得分:1)

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

您为IIOMetadataBufferedImage创建IIOImage对象,然后getImageWriters,并将其用于write元数据。

答案 2 :(得分:0)

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

顺便说一下,我不明白你所使用的“XML式”元数据结构是什么。

答案 3 :(得分:0)

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

通过在元数据树中搜索tEXtEntry个节点,有一种不使用专有API的方法:

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