Writing image metadata in Java, preferably PNG

前端 未结 4 1104
青春惊慌失措
青春惊慌失措 2020-12-02 21:38

I would like to write metadata to a PNG image that I create.

My understanding of Java Advanced Image API is that I should use IIOMetadata, but code snip

相关标签:
4条回答
  • 2020-12-02 21:56

    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..

    To write a custom metadata to a PNG file:

    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;
    }
    
    0 讨论(0)
  • 2020-12-02 21:57

    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.

    There is a method of doing it without using the proprietary API, by searching the metadata tree for tEXtEntry nodes:

    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);
    }
    
    0 讨论(0)
  • 2020-12-02 21:58

    To add to other answer, you can also try the PNGJ library, it has full metadata support.

    BTW, I don't understand what you are refering to with the "XML-like" structure of metadata.

    0 讨论(0)
  • 2020-12-02 22:09

    Java provides the metadata package and the ImageWriter class along with the ImageIO package.

    You create your IIOMetadata object, then getImageWriters for your BufferedImage or IIOImage and use them to write the metadata.

    0 讨论(0)
提交回复
热议问题