用 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
Writing image metadata in Java, preferably PNG
提问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.PNGMetadata
class 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 metadata
package and the ImageWriter
class along with the ImageIO
package.
Java 提供metadata
包和ImageWriter
类以及ImageIO
包。
You create your IIOMetadata
object, then getImageWriters
for your BufferedImage
or IIOImage
and use them to write
the metadata.
您创建您的IIOMetadata
对象,然后getImageWriters
用于您的BufferedImage
或IIOImage
并将它们用于write
元数据。
回答by leonbloy
回答by wakjah
Using the method from posted by the OP gets most of the way there; the only issue is that PNGMetadata
is 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 tEXtEntry
nodes:
有一种方法可以在不使用专有 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);
}