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.Arrays;
33 import java.util.Collection;
34 import java.util.Date;
36 import java.util.HashSet;
37 import java.util.List;
38 import java.util.TimeZone;
39 import java.util.logging.Level;
40 import org.apache.commons.lang3.StringUtils;
41 import org.openide.util.NbBundle;
42 import org.openide.util.lookup.ServiceProvider;
52 import static org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
73 "ExifProcessor.userContent.description=EXIF metadata data exists for this file."
78 try (BufferedInputStream bin =
new BufferedInputStream(
new ReadContentInputStream(file));) {
80 final Collection<BlackboardAttribute> attributes =
new ArrayList<>();
81 final Metadata metadata = ImageMetadataReader.readMetadata(bin);
84 final ExifSubIFDDirectory exifDir = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
85 if (exifDir != null) {
88 TimeZone timeZone = null;
90 Content dataSource = file.getDataSource();
91 if ((dataSource != null) && (dataSource instanceof Image)) {
92 Image image = (Image) dataSource;
93 timeZone = TimeZone.getTimeZone(image.getTimeZone());
95 }
catch (TskCoreException ex) {
96 logger.log(Level.INFO,
"Error getting time zones", ex);
99 final Date date = exifDir.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL, timeZone);
101 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED, MODULE_NAME, date.getTime() / 1000));
110 final GpsDirectory gpsDir = metadata.getFirstDirectoryOfType(GpsDirectory.class);
111 if (gpsDir != null) {
112 final GeoLocation loc = gpsDir.getGeoLocation();
114 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, MODULE_NAME, loc.getLatitude()));
115 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, MODULE_NAME, loc.getLongitude()));
118 final Rational altitude = gpsDir.getRational(GpsDirectory.TAG_ALTITUDE);
119 if (altitude != null) {
120 double alt = altitude.doubleValue();
121 if (Double.isInfinite(alt)) {
124 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE, MODULE_NAME, alt));
133 final ExifIFD0Directory devDir = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
134 if (devDir != null) {
135 final String model = devDir.getString(ExifIFD0Directory.TAG_MODEL);
136 if (StringUtils.isNotBlank(model)) {
137 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL, MODULE_NAME, model));
140 final String make = devDir.getString(ExifIFD0Directory.TAG_MAKE);
141 if (StringUtils.isNotBlank(make)) {
142 attributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE, MODULE_NAME, make));
152 if (!attributes.isEmpty() && !blackboard.artifactExists(file, BlackboardArtifact.Type.TSK_METADATA_EXIF, attributes)) {
153 List<BlackboardArtifact> artifacts =
new ArrayList<>();
154 final BlackboardArtifact exifArtifact = (file.newAnalysisResult(
155 BlackboardArtifact.Type.TSK_METADATA_EXIF,
158 attributes)).getAnalysisResult();
159 artifacts.add(exifArtifact);
161 final BlackboardArtifact userSuspectedArtifact = file.newAnalysisResult(
162 BlackboardArtifact.Type.TSK_USER_CONTENT_SUSPECTED,
165 Arrays.asList(
new BlackboardAttribute(
166 BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT,
168 Bundle.ExifProcessor_userContent_description())))
169 .getAnalysisResult();
170 artifacts.add(userSuspectedArtifact);
173 blackboard.postArtifacts(artifacts, MODULE_NAME, context.
getJobId());
174 }
catch (Blackboard.BlackboardException ex) {
175 logger.log(Level.SEVERE, String.format(
"Error posting TSK_METADATA_EXIF and TSK_USER_CONTENT_SUSPECTED artifacts for %s (object ID = %d)", file.getName(), file.getId()), ex);
178 }
catch (TskCoreException ex) {
179 logger.log(Level.SEVERE, String.format(
"Error creating TSK_METADATA_EXIF and TSK_USER_CONTENT_SUSPECTED artifacts for %s (object ID = %d)", file.getName(), file.getId()), ex);
180 }
catch (IOException | ImageProcessingException ex) {
181 logger.log(Level.WARNING, String.format(
"Error parsing %s (object ID = %d), presumed corrupt", file.getName(), file.getId()), ex);
183 logger.log(Level.SEVERE, String.format(
"Error processing %s (object ID = %d)", file.getName(), file.getId()), ex);
189 return new HashSet<String>() {
void process(IngestJobContext context, AbstractFile file)
static String getModuleName()
SleuthkitCase getSleuthkitCase()
boolean fileIngestIsCancelled()
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
Set< String > mimeTypes()