2016-12-21 5 views
-1

Ich verwende ein Stück code gepostet auf Stackover-Flow, um benutzerdefinierte Metadaten in PNG-Bild zu schreiben und zu lesen. Die Write-Funktion scheint gut zu funktionieren, aber wenn ich versuche, Daten zu lesen, die ich geschrieben habe, löst es NullPointerException aus. Kann mir jemand sagen, was falsch ist? HierPNG-Metadaten lesen und schreiben

ist Code für das Schreiben von Metadaten

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

Methode Metadaten

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

zu schreiben Lesen Metadaten

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

Methode Metadaten lesen

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; 
} 
Nachricht

Fehler

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

wäre interessant, die Fehlermeldung zu sehen. Enthält das PNG tatsächlich das Meta-Datum 'Name'? Othewise readCustomData() gibt eine Null zurück, was ein Hinweis sein könnte, wie Sie eine NullPointerException erwähnt haben. –

+0

Bitte editieren Sie Ihre Frage und fügen Sie den kompletten Stack-Trace der Ausnahme ein, die Sie sehen. – VGR

+0

@VGR ich habe Stack-Trace hinzugefügt – saim2025

Antwort

1

nennen Hier ist der effizienteste Weg, zu modifizieren und dann das Lesen der Metadaten, die ich kenne. Im Gegensatz zu dem vom OP geposteten Code ersetzt diese Version nicht vollständig die Metadaten im Bild, sondern führt den neuen Inhalt mit einem vorhandenen Inhalt zusammen.

Da es das "Standard" -Metadatenformat verwendet, sollte es auch für jedes von ImageIO unterstützte Format funktionieren, das willkürliche Textkommentare erlaubt (ich habe nur für PNG getestet). Die tatsächlich geschriebenen Daten sollten in diesem Fall mit dem nativen PNG-Metadatenformat übereinstimmen.

Es liest alle Bildpixeldaten und -metadaten mit einer einzigen Methode, um zu vermeiden, dass die Datenströme beim Öffnen/Schließen und Suchen und Speichern unnötig sind. Es schreibt alle Bildpixeldaten und Metadaten gleichzeitig aus dem gleichen Grund. Für verlustfreie Einzelbildformate wie PNG sollte dieser Roundtrip keine Qualität oder Metadaten verlieren.

Beim Zurücklesen von Metadaten werden nur die Metadaten gelesen, Pixeldaten werden ignoriert.

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

Erwartete Ausgabe des obigen Codes ist:

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

Das hat gut funktioniert. sehr geschätzt – saim2025

3

Die Ausgabe enthält "nicht gefunden", die von

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

Deshalb erstellt

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

mit einem Nullpointer scheitern muss. pngmeta.getStandardTextNode() führt zu null, so dass Sie actully

null.getChildNodes(); 
+0

Ich fügte hinzu, dass zu prüfen, ob Pngmeta irgendwelche Daten enthielt. Der Code funktioniert auch nach dem Entfernen der if-Anweisung nicht – saim2025

+0

Die if-Anweisung zeigt Ihnen das Problem, es ist nicht das Problem selbst. pngmeta.getStandardTextNode() enthält einfach gar nichts. –

+0

Die Datei enthält jedoch Metadaten. Es zeigt sich, wenn ich ein anderes Tool verwende, um Metadaten anzuzeigen – saim2025