繁体   English   中英

PNG元数据读写

[英]PNG metadata read and write

我正在使用发布在stackover流上的一段代码将自定义元数据写入PNG图像并进行读取。 写入功能似乎可以正常工作,但是当我尝试读取已写入的数据时,它将引发NullPointerException。 有人可以告诉我怎么了吗?

这是用于编写元数据的代码

try{
    image=ImageIO.read(new FileInputStream("input.png"));
    writeCustomData(image, "software", "FRDDC");
    ImageIO.write(image, "png", new File("output.png"));
    }
    catch(Exception e){
    e.printStackTrace();
    }

写元数据的方法

   public static 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
        javax.imageio.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();
        javax.imageio.stream.ImageOutputStream stream = ImageIO.createImageOutputStream(baos);
    writer.setOutput(stream);
    writer.write(metadata, new IIOImage(buffImg, null, metadata), writeParam);

    try {

            ImageIO.write(buffImg, "png", new File("new.png"));
        } catch (Exception e) {
            e.printStackTrace();
        }

    stream.close();

    return baos.toByteArray();
}

读取元数据

try{
image=ImageIO.read(new FileInputStream("output.png"));

            ByteArrayOutputStream baos=new ByteArrayOutputStream();
            ImageIO.write(image, "png", baos );
            byte[] b=baos.toByteArray();
            String out=readCustomData(b, "software");
}
catch(Exception e){
e.printStackTrace();
}

读取元数据的方法

 public static 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
        javax.imageio.metadata.IIOMetadata metadata = imageReader.getImageMetadata(0);

    //this cast helps getting the contents

     //Node n=metadata.getAsTree("javax_imageio_png_1.0");
     //NodeList childNodes=n.getChildNodes();
    PNGMetadata pngmeta = (PNGMetadata) metadata; 
    if(pngmeta.getStandardTextNode()==null){
        System.out.println("not found");
    }
    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;
}

错误信息

not found
java.lang.NullPointerException
    at PNGMeta.readCustomData(PNGMeta.java:104)
    at PNGMeta.main(PNGMeta.java:40)
BUILD SUCCESSFUL (total time: 2 seconds)

您的输出包含“未找到”,它是由创建的

if(pngmeta.getStandardTextNode()==null){
    System.out.println("not found");
}

因此

NodeList childNodes = pngmeta.getStandardTextNode().getChildNodes();

必须失败,并出现NullPointerException。 pngmeta.getStandardTextNode()结果为null,因此您可以强制调用

null.getChildNodes();

这里的修改,然后阅读,我知道的元数据的最有效方式。 与OP发布的代码相反,此版本并未完全替换图像中的元数据,而是将新内容与任何现有内容合并。

由于它使用“标准”元数据格式,因此它也应适用于ImageIO支持的任何允许任意文本注释的格式(不过,我仅测试了PNG)。 写入的实际数据,应该匹配,在这种情况下,本地PNG元数据格式。

它使用一种方法读取所有图像像素数据和元数据,以避免过多的流打开/关闭以及查找和内存使用。 由于相同的原因,它一次写入所有图像像素数据和元数据。 对于无损的单一图像格式(如PNG),此往返过程不应丢失任何质量或元数据。

当回读元数据时,仅读取元数据,而忽略像素数据。

public class IIOMetadataUpdater {

    public static void main(final String[] args) throws IOException {
        File in = new File(args[0]);
        File out = new File(in.getParent(), createOutputName(in));

        System.out.println("Output path: " + out.getAbsolutePath());

        try (ImageInputStream input = ImageIO.createImageInputStream(in);
             ImageOutputStream output = ImageIO.createImageOutputStream(out)) {

            Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
            ImageReader reader = readers.next(); // TODO: Validate that there are readers

            reader.setInput(input);
            IIOImage image = reader.readAll(0, null);

            addTextEntry(image.getMetadata(), "foo", "bar");

            ImageWriter writer = ImageIO.getImageWriter(reader); // TODO: Validate that there are writers
            writer.setOutput(output);
            writer.write(image);
        }

        try (ImageInputStream input = ImageIO.createImageInputStream(out)) {
            Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
            ImageReader reader = readers.next(); // TODO: Validate that there are readers

            reader.setInput(input);
            String value = getTextEntry(reader.getImageMetadata(0), "foo");

            System.out.println("value: " + value);
        }
    }

    private static String createOutputName(final File file) {
        String name = file.getName();
        int dotIndex = name.lastIndexOf('.');

        String baseName = name.substring(0, dotIndex);
        String extension = name.substring(dotIndex);

        return baseName + "_copy" + extension;
    }

    private static void addTextEntry(final IIOMetadata metadata, final String key, final String value) throws IIOInvalidTreeException {
        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(IIOMetadataFormatImpl.standardMetadataFormatName);
        root.appendChild(text);

        metadata.mergeTree(IIOMetadataFormatImpl.standardMetadataFormatName, root);
    }

    private static String getTextEntry(final IIOMetadata metadata, final String key) {
        IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
        NodeList entries = root.getElementsByTagName("TextEntry");

        for (int i = 0; i < entries.getLength(); i++) {
            IIOMetadataNode node = (IIOMetadataNode) entries.item(i);
            if (node.getAttribute("keyword").equals(key)) {
                return node.getAttribute("value");
            }
        }

        return null;
    }
}

上面代码的预期输出为:

Output path: /path/to/yourfile_copy.png
value: bar

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM