似乎无法检索ExifSubIFDDirectory

时间:2014-11-17 18:23:44

标签: java image metadata exif

我正在尝试从图片中提取日期信息。我相处得很好但我有这个问题困扰了我2天。我甚至一次重写整个代码仍然得到它。

我显然得到了一个N​​P,因为我在方法grabExifSubIFDDirectory中返回null。这是主要问题,它声称有没有目录可用,而应该有一个。 为什么它不能抓住目录?我正在使用standrd jpegs和其他格式。

将jar放在带有图片的文件夹中。

如果有人能指出(嘿)我的方向?

Package utils:

package utils;

import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifSubIFDDirectory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import javax.swing.JOptionPane;

public class FileUtils {

    private ArrayList<String> fileNamesList;

    public FileUtils(String jarFilePath) {
        setFileNames(jarFilePath);
    }

    // Retrieves a Metadata object from a File object and returns it.
    public Metadata grabFileMetaData(String filePath) {
        Metadata metadata = null;
        File file = new File(filePath);
        try {
            metadata = ImageMetadataReader.readMetadata(file);
        } catch (ImageProcessingException e) {
            JOptionPane.showMessageDialog(null, "Error: " + e);
        } catch (IOException e) {
            JOptionPane.showMessageDialog(null, "Error: " + e);
        }
        return metadata;
    }

    // Retrieves a ExifSubIFDDirectory object from a Metadata object and returns it. 
    public ExifSubIFDDirectory grabExifSubIFDDirectory(Metadata metadata, String filePath) {
        ExifSubIFDDirectory directory;
        if (metadata.containsDirectory(ExifSubIFDDirectory.class)) {
            directory = (ExifSubIFDDirectory) metadata.getDirectory(ExifSubIFDDirectory.class);
            return directory;
        } else {
            JOptionPane.showMessageDialog(null, "File at: " + filePath + " does not contain exif date.");
            return null;
        }
    }

    // Retrieves a Date object from a ExifSubIFDDirectory object and returns it.
    public Date grabDate(ExifSubIFDDirectory directory) {
        Date date;
        date = directory.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL);
        return date;
    }

    // Return the actual Date object using the above methods.
    public Date getDate(String filePath) {
        return grabDate(grabExifSubIFDDirectory(grabFileMetaData(filePath), filePath));
    }

    // Retrieves the names of the files in the same folder as the executed jar.
    // Saves them in a variable.
    public void setFileNames(String jarPath) {
        ArrayList<String> temp = new ArrayList();
        String path = jarPath;
        String files;
        File folder = new File(path);
        File[] listOfFiles = folder.listFiles();
        for (File listOfFile : listOfFiles) {
            if (listOfFile.isFile()) {
                files = listOfFile.getName();
                if (!"PhotoRenamer.jar".equals(files) && !"Thumbs.db".equals(files)) {
                    temp.add(files);
                }
            }
        }
        this.fileNamesList = temp;
    }

    // getter
    public ArrayList<String> getFileNamesList() {
        return fileNamesList;
    }

}

Package domein:

package domein;

    import utils.FileUtils;
    import utils.JarUtils;
    import java.util.ArrayList;

    public class DomeinController {

        FileUtils fileUtils;
        JarUtils jarUtils;

        public DomeinController() {
            this.jarUtils = new JarUtils();
            this.fileUtils = new FileUtils(jarUtils.getJarPath());
        }

        public ArrayList<String> getFileNamesList() {
            return fileUtils.getFileNamesList();
        }

        public String getJarPath() {
            return jarUtils.getJarPath();
        }

        // Retrieve string from Date object of the file with the number i.
        public String getDate(int i) {
            return fileUtils.getDate(createFilePath(i)).toString();
        }

        public String createFilePath(int i) {
            return getJarPath() + "\\" + fileUtils.getFileNamesList().get(i);
        }

    }

包启动:

 package startup;

import domein.DomeinController;
import java.net.URISyntaxException;
import javax.swing.JOptionPane;

public class Main {

    public static void main(String[] args) throws URISyntaxException {
        DomeinController  dc = new DomeinController();

        // print out jar path
        JOptionPane.showMessageDialog(null,dc.getJarPath());

        // print out file names in folder
        String lijstje = "";
        for (int i=0;i<dc.getFileNamesList().size();i++){
            lijstje += dc.getFileNamesList().get(i);
        }
        JOptionPane.showMessageDialog(null,lijstje);

        JOptionPane.showMessageDialog(null,dc.getDate(1));
    }

}

3 个答案:

答案 0 :(得分:2)

getDate(String filePath)方法工作正常,我测试了它。

所以它必须来自图片本身

  • 使用单张图片测试您的代码(使用单元测试),确保getDate方法适合您。用来自互联网的图片进行测试。
  • 由于Metadata不为空,文件确实存在,因此图片没有EXIF信息,毫无疑问。
  • 使用this tool检查您的图片是否包含EXIF信息

答案 1 :(得分:1)

您必须意识到并非所有图像都包含EXIF信息。出于多种原因,可以从图像中清除元数据。

我今天早些时候遇到过类似的问题,这是我的解决方案:

public HashMap<String, String> getMetadata(File photoFile){
    Metadata metadata;
    ExifSubIFDDirectory exifSubIFDDirectory;
    HashMap<String, String> tagMap = new HashMap<>();

    try {
        metadata = ImageMetadataReader.readMetadata(photoFile);
        exifSubIFDDirectory = metadata.getDirectory(ExifSubIFDDirectory.class);
        ExifSubIFDDescriptor exifSubIFDDescriptor = new ExifSubIFDDescriptor(exifSubIFDDirectory);

        if (exifSubIFDDirectory != null) {
            tagMap.put("lens", exifSubIFDDirectory.getDescription(ExifSubIFDDirectory.TAG_LENS_MODEL).toString());
            tagMap.put("captureDate", exifSubIFDDirectory.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL).toString());
            tagMap.put("shutter", exifSubIFDDescriptor.getExposureTimeDescription());
            tagMap.put("aperture", exifSubIFDDescriptor.getFNumberDescription());
            tagMap.put("focalLength", exifSubIFDDescriptor.getFocalLengthDescription());
            tagMap.put("iso", exifSubIFDDescriptor.getIsoEquivalentDescription());
            tagMap.put("meterMode", exifSubIFDDescriptor.getMeteringModeDescription());                

            //null is a possible return value from the method calls above.  Replace them
            //with default no value string
            for (String key : tagMap.keySet()){
                if (tagMap.get(key) == null)
                    tagMap.put(key, "No Value Recorded");
            }
        } else {
            Date currentDate = new Date();
            tagMap.put("captureDate", currentDate.toString());
            tagMap.put("shutter", "No Value Recorded");
            tagMap.put("aperture", "No Value Recorded");
            tagMap.put("focalLength", "No Value Recorded");
            tagMap.put("iso", "No Value Recorded");
            tagMap.put("meterMode","No Value Recorded");
            tagMap.put("lens", "No Value Recorded");

        }
    } catch (ImageProcessingException|IOException|NullPointerException e) { 
        //unhandled exception, put out logging statement
        log.error("Error processing metadata for file " + photoFile.getName() + "\n" + e.getStackTrace());
    }

    return tagMap;
}

如您所见,我在做任何工作之前检查ExifSubIFDDirectory对象是否存在。如果是,则我想要的元数据字段保存在HashMap对象中,该对象稍后会保留在数据库中。如果标记不存在,则将其存储为空值,稍后将替换为“未找到值”字符串。

基本上,您的问题不是检查ExifSubIFDDirectory对象是否通过metadata.getDirectory调用初始化。我认为如果您使用带有元数据集的图像,则在测试期间不会遇到此问题。

答案 2 :(得分:1)

(这是来自图像编解码器视角的一般建议。它可能适用于或不适用于Drew Noakes的开源库用户。)

我的第一步是使用Phil Harvey's ExifTool以相当详尽的方式从JPEG文件中转储元数据。

一旦您确定JPEG文件包含EXIF数据,接下来就是为了找出库不返回该部分数据的故障排除工作。它可能正确地解析它,但也许你的代码没有按照预期的方式从它的API中检索它。

(由于我不知道这个开源库,我不能提供任何特定于此库的建议。)

检查JPEG文件是否包含APP1段。 APP1段由两个字节的序列0xFF 0xE1标记。

不同的图像库提供了查找APP1段是否存在的不同方法。其他库可能会从API用户跳过,忽略或使用和隐藏此段。

如果您的库允许,请为APP1安装元数据头事件处理程序,以便您可以查看对其数据执行的处理。然后,您可以跟踪库打算如何存储并通过其API提供该数据。

http://www.digitalpreservation.gov/formats/fdd/fdd000147.shtml

http://en.wikipedia.org/wiki/JPEG