Java ImageIO, невозможно изменить дерево метаданных - PullRequest
3 голосов
/ 08 декабря 2011

Я пытаюсь использовать 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тег, а затем он изменяет поле комментария, но возвращает исходное значение.

             ...
                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проверить?

Ответы [ 2 ]

5 голосов
/ 01 марта 2012

Ответ 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 голос
/ 10 декабря 2011

Способ установки атрибута comment элемента COM в метаданных JPEG неверен.

Попробуйте вместо этого сделать следующее:

// ... 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, чтобы лучше понять, как и почему он работает таким образом..

...