19 package org.sleuthkit.autopsy.modules.pictureanalyzer.impls;
21 import com.drew.imaging.ImageMetadataReader;
22 import com.drew.imaging.ImageProcessingException;
23 import com.drew.lang.GeoLocation;
24 import com.drew.lang.Rational;
25 import com.drew.metadata.Metadata;
26 import com.drew.metadata.exif.ExifIFD0Directory;
27 import com.drew.metadata.exif.ExifSubIFDDirectory;
28 import com.drew.metadata.exif.GpsDirectory;
29 import java.io.BufferedInputStream;
30 import java.io.IOException;
31 import java.util.ArrayList;
32 import java.util.Collection;
33 import java.util.Date;
35 import java.util.HashSet;
36 import java.util.TimeZone;
37 import java.util.logging.Level;
38 import org.apache.commons.lang3.StringUtils;
39 import org.openide.util.NbBundle;
40 import org.openide.util.lookup.ServiceProvider;
50 import static org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF;
51 import static org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_USER_CONTENT_SUSPECTED;
53 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
73 "ExifProcessor.indexError.message=Failed to post EXIF Metadata artifact(s).",
74 "ExifProcessor.userContent.description=EXIF metadata data exists for this file."
79 try (BufferedInputStream bin =
new BufferedInputStream(
new ReadContentInputStream(file));) {
81 final Collection<BlackboardAttribute> attributes =
new ArrayList<>();
82 final Metadata metadata = ImageMetadataReader.readMetadata(bin);
85 final ExifSubIFDDirectory exifDir = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
86 if (exifDir != null) {
89 TimeZone timeZone = null;
91 Content dataSource = file.getDataSource();
92 if ((dataSource != null) && (dataSource instanceof Image)) {
93 Image image = (Image) dataSource;
94 timeZone = TimeZone.getTimeZone(image.getTimeZone());
96 }
catch (TskCoreException ex) {
97 logger.log(Level.INFO,
"Error getting time zones", ex);
100 final Date date = exifDir.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL, timeZone);
102 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED, MODULE_NAME, date.getTime() / 1000));
111 final GpsDirectory gpsDir = metadata.getFirstDirectoryOfType(GpsDirectory.class);
112 if (gpsDir != null) {
113 final GeoLocation loc = gpsDir.getGeoLocation();
115 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, MODULE_NAME, loc.getLatitude()));
116 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, MODULE_NAME, loc.getLongitude()));
119 final Rational altitude = gpsDir.getRational(GpsDirectory.TAG_ALTITUDE);
120 if (altitude != null) {
121 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE, MODULE_NAME, altitude.doubleValue()));
130 final ExifIFD0Directory devDir = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
131 if (devDir != null) {
132 final String model = devDir.getString(ExifIFD0Directory.TAG_MODEL);
133 if (StringUtils.isNotBlank(model)) {
134 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL, MODULE_NAME, model));
137 final String make = devDir.getString(ExifIFD0Directory.TAG_MAKE);
138 if (StringUtils.isNotBlank(make)) {
139 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE, MODULE_NAME, make));
149 if (!attributes.isEmpty() && !blackboard.artifactExists(file, TSK_METADATA_EXIF, attributes)) {
151 final BlackboardArtifact exifArtifact = file.newArtifact(TSK_METADATA_EXIF);
152 final BlackboardArtifact userSuspectedArtifact = file.newArtifact(TSK_USER_CONTENT_SUSPECTED);
153 exifArtifact.addAttributes(attributes);
154 userSuspectedArtifact.addAttribute(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT,
155 MODULE_NAME, Bundle.ExifProcessor_userContent_description()));
158 blackboard.postArtifact(exifArtifact, MODULE_NAME);
159 blackboard.postArtifact(userSuspectedArtifact, MODULE_NAME);
160 }
catch (Blackboard.BlackboardException ex) {
161 logger.log(Level.SEVERE,
"Unable to index blackboard artifact " + exifArtifact.getArtifactID(), ex);
163 Bundle.ExifProcessor_indexError_message(), exifArtifact.getDisplayName());
166 }
catch (TskCoreException ex) {
167 logger.log(Level.WARNING,
"Failed to create blackboard artifact for "
168 +
"exif metadata ({0}).", ex.getLocalizedMessage());
169 }
catch (ImageProcessingException ex) {
170 logger.log(Level.WARNING, String.format(
"Failed to process the image "
171 +
"file '%s/%s' (id=%d).", file.getParentPath(), file.getName(), file.getId()), ex);
172 }
catch (ReadContentInputStream.ReadContentInputStreamException ex) {
173 logger.log(Level.WARNING, String.format(
"Error while trying to read "
174 +
"image file '%s/%s' (id=%d).", file.getParentPath(), file.getName(), file.getId()), ex);
175 }
catch (IOException ex) {
176 logger.log(Level.WARNING, String.format(
"IOException when parsing "
177 +
"image file '%s/%s' (id=%d).", file.getParentPath(), file.getName(), file.getId()), ex);
179 logger.log(Level.INFO,
"Exception while getting open case.", ex);
185 return new HashSet<String>() {
void process(IngestJobContext context, AbstractFile file)
static String getModuleName()
SleuthkitCase getSleuthkitCase()
boolean fileIngestIsCancelled()
static void error(String title, String message)
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
Set< String > mimeTypes()