2016-12-21 76 views
-1

我正在使用一張code張貼在stackover流中,將自定義元數據寫入PNG圖像並讀取它。寫函數似乎工作正常,但是當我嘗試讀取我寫它的數據時拋出NullPointerException。有人能告訴我什麼是錯的嗎?PNG元數據讀寫

這裏是寫代碼的元數據

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) 
+0

很想看到錯誤信息。 PNG實際上是否包含元數據「名稱」? Othewise readCustomData()返回一個null,這可能是一個提示,就像你提到的一個NullPointerException –

+0

請編輯你的問題,幷包含你看到的異常的完整堆棧跟蹤。 – VGR

+0

@VGR我已添加堆棧跟蹤 – saim2025

回答

1

這裏的修改,然後閱讀,我知道的元數據的最有效方式。與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 
+0

這工作得很好。非常感激 – saim2025

3

你的輸出包含 「未發現」,這是由

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

創建因此

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

一定會失敗,一個NullPointerException。 pngmeta.getStandardTextNode()導致空,所以你actully調用

null.getChildNodes(); 
+0

我補充說,檢查pngmeta是否包含任何數據。即使在刪除語句後,代碼也不起作用 – saim2025

+0

if語句向您顯示問題,它本身不是問題。 pngmeta.getStandardTextNode()根本不包含任何內容。 –

+0

但文件確實包含元數據。它顯示了當我使用其他工具查看元數據 – saim2025