我正在尝试使用ImageIO来更改文件的JPEG注释字段(COM)。我读取了元数据,对DOM进行了一些更改(注释字段的更改属性),然后保存/打印元数据。但我没有显示我的更改。 这是代码(在带有静态main()的简单测试类中),'file'已设置。
ImageWriter writer = ImageIO.getImageWritersBySuffix("jpeg").next();
ImageReader reader = ImageIO.getImageReader(writer);
reader.setInput(new FileImageInputStream(file));
RenderedImage img = reader.read(0);
IIOMetadata meta = reader.getImageMetadata(0);
IIOMetadataNode root1 = (IIOMetadataNode) meta.getAsTree("javax_imageio_jpeg_image_1.0");
String comment1 = getCommentFromDOM(root1);
System.out.println("comment 1 = " + comment1);
String comment2 = getCommentFromDOM(root1);
System.out.println("comment 2 = " + comment2);
meta.setFromTree("javax_imageio_jpeg_image_1.0", root1);
//meta.reset();
IIOMetadataNode root2 = (IIOMetadataNode) meta.getAsTree("javax_imageio_jpeg_image_1.0");
String comment3 = getCommentFromDOM(root2);
System.out.println("comment 3 = " + comment3);
方法getCommentFromDOM()只是通过树并获取com标记中的comment属性,然后更改注释字段但返回原始值。
...
if(md.getNodeName().equalsIgnoreCase("com")) {
String comment = md.getAttribute("comment");
md.setAttribute("comment", "FOOOOOOOOOO");
return comment;
}
...
因此,当执行该程序时,它将输出:
comment 1 = originalcomment comment 2 = FOOOOOOOOOOO comment 3 = originalcomment
因此DOM已更改,但看起来meta.setFromTree()方法未使用新树。我也尝试过运行meta.reset(),它应该清除元数据,但这似乎对元对象没有任何影响。
在这个非常简单的ImageIO测试中,谁能看到我做错了什么?
答案 0 :(得分:5)
nowaq的回答让我开始朝着正确的方向前进,但我在处理原始图像没有现有评论的情况下遇到了麻烦(他的解决方案适用于原版已有评论的情况)。在以下两种情况下,以下代码适用于我:
Element tree = (Element) imageMetadata.getAsTree("javax_imageio_jpeg_image_1.0");
NodeList comNL = tree.getElementsByTagName("com");
IIOMetadataNode comNode;
if (comNL.getLength() == 0) {
comNode = new IIOMetadataNode("com");
Node markerSequenceNode = tree.getElementsByTagName("markerSequence").item(0);
markerSequenceNode.insertBefore(comNode,markerSequenceNode.getFirstChild());
} else {
comNode = (IIOMetadataNode) comNL.item(0);
}
comNode.setUserObject(("YourComment").getBytes("ISO-8859-1"));
imageMetadata.setFromTree("javax_imageio_jpeg_image_1.0", tree);
答案 1 :(得分:1)
您在JPEG元数据中设置COM
元素的comment
属性的方式是错误的。
尝试这样做:
// ... some code ...
IIOMetadata meta = reader.getImageMetadata(0);
Element tree = (Element) meta.getAsTree("javax_imageio_jpeg_image_1.0");
IIOMetadataNode comNode = (IIOMetadataNode)tree.getElementsByTagName("com").item(0);
comNode.setUserObject(new String("FOOOOOOOOOO!").getBytes("ISO-8859-1"));
meta.setFromTree("javax_imageio_jpeg_image_1.0", tree);
// ... smoe code ...
您现在可以将文件另存为JPG ......
// set JPG params
JPEGImageWriteParam param = new JPEGImageWriteParam(Locale.getDefault());
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(1);
param.setOptimizeHuffmanTables(true);
// save the image with new comment inside
IIOImage iioimage = new IIOImage(img, null, meta);
writer.setOutput(ImageIO.createImageOutputStream(new File("some_modified.jpg")));
writer.write(null, iioimage, param);
...或者只是将元数据显示为DOM树。你会看到你的评论在那里。
如果您有兴趣,也可以查看com.sun.imageio.plugins.jpeg.COMMarkerSegment(Node node)
和JPEGMetadata
的源代码(免费提供),以便更好地了解其工作方式和原因。