有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java ImageIO,无法更改元数据树

我正在尝试使用ImageIO更改文件的JPEG注释字段(COM)。我读取元数据,对DOM做一些更改(更改注释字段的属性),然后保存/打印元数据。但是我的更改没有显示出来。 这是代码(在带有static 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属性,然后它更改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被更改了,但它看起来像元。setFromTree()方法未使用新树。我也试过运行meta。reset()应该清除元数据,但这似乎对元对象没有影响

有人能看出我在这个非常简单的ImageIO测试中做错了什么吗


共 (2) 个答案

  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的源代码(免费提供),以便更好地理解它是如何工作的以及为什么这样工作的

  2. # 2 楼答案

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