2016-12-21 21 views
-1

Я использую кусок code, размещенный в потоке стека, чтобы писать пользовательские метаданные в 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() возвращает нуль, что может быть подсказкой, поскольку вы упомянули об ошибке NullPointerException. –

+0

. Измените свой вопрос и включите полную статистику стека исключения, которое вы видите. – VGR

+0

@ VGR я добавил трассировку стека – saim2025

ответ

1

Вот наиболее эффективный способ изменения, а затем читает метаданные, которые я знаю. В отличие от кода, отправленного OP, эта версия не полностью заменяет метаданные на изображении, но объединяет новый контент с любым существующим контентом.

Поскольку он использует «стандартный» формат метаданных, он также должен работать в любом формате, поддерживаемом ImageIO, что позволяет произвольные текстовые комментарии (я тестировал только PNG, хотя). Фактические данные, написанные, должны совпадать с фактическим форматом метаданных PNG в этом случае.

Он считывает все данные пикселов изображения и метаданные одним методом, чтобы избежать открытия/закрытия избыточного потока и поиска и использования памяти. Он записывает все данные пикселя изображения и метаданные сразу по той же причине. Для без потерь, единых графических форматов, таких как PNG, этот roundtrip не должен терять качество или метаданные.

При чтении метаданных назад считываются только метаданные, данные пикселей игнорируются.

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