Reputation: 1089
I'm trying to extract the Date info from a picture. I'm getting along quite good but I have this problem bugging me for 2 days. I've even rewriten the entire code once and still get it.
I obviously get an NP because I return a null in the method grabExifSubIFDDirectory. This is the main problem, it claims there is no Directory available while there should be one. Why can't it grab the directory? I'm using standrd jpegs and other formats.
The jar is placed inside a folder with pictures.
If somebody could point (hehe) me int the direction?
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:
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));
}
}
Upvotes: 1
Views: 1041
Reputation: 6162
(This is a general advice from the image codec perspective. It may or may not be applicable to the users of the open source library by Drew Noakes.)
My first step is to use Phil Harvey's ExifTool to dump the metadata from the JPEG file in a rather exhaustive way.
Once you are sure that the JPEG file contains EXIF data, what follows is troubleshooting effort to find out why the library does not return that part of data. It might be properly parsing it, but perhaps your code didn't retrieve it from its API in the way it expects.
(Since I don't know this open-source library, I cannot give any advice specific to this library.)
Check whether the JPEG file contains an APP1 segment. The APP1 segment is marked by a two-byte sequence 0xFF 0xE1
.
Different image libraries provide different ways of finding out whether an APP1 segment is present. Other libraries may skip over, ignore, or consume and hide this segment from the API user.
If your library allows it, install a metadata header event handler for APP1 so that you can see what processing is performed on its data. You can then track down how the library intends to store and provide that data via its API.
http://www.digitalpreservation.gov/formats/fdd/fdd000147.shtml
http://en.wikipedia.org/wiki/JPEG
Upvotes: 1
Reputation: 11363
What you have to realize is that not all images contain that EXIF information. For any number of reasons, the metadata can be scrubbed from an image.
I was going through a similar issue earlier today, and this was my solution:
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;
}
As you can see, I check if the ExifSubIFDDirectory
object exists before doing any work. If it does, then the metadata fields I want are saved in a HashMap object, which is later persisted in the database. If the tag doesn't exist, it is stored as a null value, which is later replaced with a 'No Value Found' string.
Essentially, your issue here was not checking if ExifSubIFDDirectory
object is initialized via the metadata.getDirectory
call. I think if you use an image with the metadata set, you wouldn't encounter this issue during testing.
Upvotes: 1
Reputation: 16833
The getDate(String filePath)
method is working just fine, I tested it.
So it must come from the picture itself
getDate
method is working for you. Do the test with a picture coming from the Internet too.Metadata
is not null, the file does exist so the picture has no EXIF information, there is no possible doubt.Upvotes: 2