mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
face detection feature added
This commit is contained in:
parent
f40776c322
commit
2ba62e440e
@ -2,7 +2,8 @@ file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar
|
||||
file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar
|
||||
file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.jar
|
||||
file.reference.jython.jar-1=release/modules/ext/jython.jar
|
||||
file.reference.metadata-extractor-2.6.2.jar=release/modules/ext/metadata-extractor-2.6.2.jar
|
||||
file.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1.jar
|
||||
file.reference.opencv-248.jar=release/modules/ext/opencv-248.jar
|
||||
file.reference.Rejistry-1.0-SNAPSHOT.jar=release/modules/ext/Rejistry-1.0-SNAPSHOT.jar
|
||||
file.reference.sevenzipjbinding-AllPlatforms.jar=release/modules/ext/sevenzipjbinding-AllPlatforms.jar
|
||||
file.reference.sevenzipjbinding.jar=release/modules/ext/sevenzipjbinding.jar
|
||||
@ -10,12 +11,13 @@ file.reference.sqlite-jdbc-3.8.11.jar=release/modules/ext/sqlite-jdbc-3.8.11.jar
|
||||
file.reference.StixLib.jar=release/modules/ext/StixLib.jar
|
||||
file.reference.tika-core-1.2.jar=release/modules/ext/tika-core-1.2.jar
|
||||
file.reference.Tsk_DataModel.jar=release/modules/ext/Tsk_DataModel.jar
|
||||
file.reference.xmpcore.jar=release/modules/ext/xmpcore.jar
|
||||
file.reference.xmpcore-5.1.2.jar=release/modules/ext/xmpcore-5.1.2.jar
|
||||
javac.source=1.8
|
||||
javac.compilerargs=-Xlint -Xlint:-serial
|
||||
license.file=../LICENSE-2.0.txt
|
||||
nbm.homepage=http://www.sleuthkit.org/
|
||||
nbm.module.author=Brian Carrier
|
||||
nbm.needs.restart=true
|
||||
source.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1-src.zip!/Source/
|
||||
spec.version.base=10.3
|
||||
|
||||
|
@ -203,10 +203,26 @@
|
||||
<package>org.sleuthkit.autopsy.report</package>
|
||||
<package>org.sleuthkit.datamodel</package>
|
||||
</public-packages>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/xmpcore-5.1.2.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/xmpcore-5.1.2.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/jdom-2.0.5.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/jdom-2.0.5.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/StixLib.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/StixLib.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/sqlite-jdbc-3.8.11.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/sqlite-jdbc-3.8.11.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/opencv-248.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/opencv-248.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/Rejistry-1.0-SNAPSHOT.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/Rejistry-1.0-SNAPSHOT.jar</binary-origin>
|
||||
@ -219,34 +235,18 @@
|
||||
<runtime-relative-path>ext/jython-standalone-2.7.0.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/jython-standalone-2.7.0.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/StixLib.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/StixLib.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/opencv-248.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/opencv-248.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/sqlite-jdbc-3.8.11.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/sqlite-jdbc-3.8.11.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/sevenzipjbinding-AllPlatforms.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/sevenzipjbinding-AllPlatforms.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/metadata-extractor-2.6.2.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/metadata-extractor-2.6.2.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/xmpcore.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/xmpcore.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/tika-core-1.2.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/tika-core-1.2.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/metadata-extractor-2.8.1.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/metadata-extractor-2.8.1.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/jdom-2.0.5-contrib.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/jdom-2.0.5-contrib.jar</binary-origin>
|
||||
|
Binary file not shown.
BIN
Core/release/modules/ext/metadata-extractor-2.8.1.jar
Executable file
BIN
Core/release/modules/ext/metadata-extractor-2.8.1.jar
Executable file
Binary file not shown.
BIN
Core/release/modules/ext/xmpcore-5.1.2.jar
Executable file
BIN
Core/release/modules/ext/xmpcore-5.1.2.jar
Executable file
Binary file not shown.
Binary file not shown.
@ -22,10 +22,21 @@ import com.drew.imaging.ImageMetadataReader;
|
||||
import com.drew.imaging.ImageProcessingException;
|
||||
import com.drew.lang.GeoLocation;
|
||||
import com.drew.lang.Rational;
|
||||
import com.drew.metadata.Directory;
|
||||
import com.drew.metadata.Metadata;
|
||||
import com.drew.metadata.MetadataException;
|
||||
import com.drew.metadata.exif.makernotes.CanonMakernoteDirectory;
|
||||
import com.drew.metadata.exif.ExifIFD0Directory;
|
||||
import com.drew.metadata.exif.ExifSubIFDDirectory;
|
||||
import com.drew.metadata.exif.GpsDirectory;
|
||||
import com.drew.metadata.exif.makernotes.CasioType1MakernoteDirectory;
|
||||
import com.drew.metadata.exif.makernotes.FujifilmMakernoteDirectory;
|
||||
import com.drew.metadata.exif.makernotes.KodakMakernoteDirectory;
|
||||
import com.drew.metadata.exif.makernotes.NikonType2MakernoteDirectory;
|
||||
import com.drew.metadata.exif.makernotes.PanasonicMakernoteDirectory;
|
||||
import com.drew.metadata.exif.makernotes.PentaxMakernoteDirectory;
|
||||
import com.drew.metadata.exif.makernotes.SanyoMakernoteDirectory;
|
||||
import com.drew.metadata.exif.makernotes.SonyType1MakernoteDirectory;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -33,6 +44,8 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.util.NbBundle;
|
||||
@ -47,6 +60,8 @@ import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.Image;
|
||||
import org.sleuthkit.datamodel.ReadContentInputStream;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
@ -63,10 +78,13 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
|
||||
private final IngestServices services = IngestServices.getInstance();
|
||||
private final AtomicInteger filesProcessed = new AtomicInteger(0);
|
||||
private volatile boolean filesToFire = false;
|
||||
private volatile boolean facesDetected = false;
|
||||
private final List<BlackboardArtifact> listOfFacesDetectedArtifacts = new ArrayList<>();
|
||||
private long jobId;
|
||||
private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter();
|
||||
private FileTypeDetector fileTypeDetector;
|
||||
private final HashSet<String> supportedMimeTypes = new HashSet<>();
|
||||
private TimeZone timeZone = null;
|
||||
|
||||
ExifParserFileIngestModule() {
|
||||
supportedMimeTypes.add("audio/x-wav");
|
||||
@ -103,9 +121,16 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
|
||||
|
||||
// update the tree every 1000 files if we have EXIF data that is not being being displayed
|
||||
final int filesProcessedValue = filesProcessed.incrementAndGet();
|
||||
if ((filesToFire) && (filesProcessedValue % 1000 == 0)) {
|
||||
services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF));
|
||||
filesToFire = false;
|
||||
if ((filesProcessedValue % 1000 == 0)) {
|
||||
if (filesToFire) {
|
||||
services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF));
|
||||
filesToFire = false;
|
||||
}
|
||||
if (facesDetected) {
|
||||
services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_FACE_DETECTED, listOfFacesDetectedArtifacts));
|
||||
listOfFacesDetectedArtifacts.clear();
|
||||
facesDetected = false;
|
||||
}
|
||||
}
|
||||
|
||||
//skip unsupported
|
||||
@ -125,11 +150,24 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
|
||||
bin = new BufferedInputStream(in);
|
||||
|
||||
Collection<BlackboardAttribute> attributes = new ArrayList<>();
|
||||
Metadata metadata = ImageMetadataReader.readMetadata(bin, true);
|
||||
Metadata metadata = ImageMetadataReader.readMetadata(bin);
|
||||
|
||||
// Date
|
||||
ExifSubIFDDirectory exifDir = metadata.getDirectory(ExifSubIFDDirectory.class);
|
||||
ExifSubIFDDirectory exifDir = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
|
||||
if (exifDir != null) {
|
||||
|
||||
// set the timeZone for the current datasource.
|
||||
if (timeZone == null) {
|
||||
try {
|
||||
Content dataSource = f.getDataSource();
|
||||
if ((dataSource != null) && (dataSource instanceof Image)) {
|
||||
Image image = (Image) dataSource;
|
||||
timeZone = TimeZone.getTimeZone(image.getTimeZone());
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.INFO, "Error getting time zones", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
Date date = exifDir.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL);
|
||||
if (date != null) {
|
||||
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID(), ExifParserModuleFactory.getModuleName(), date.getTime() / 1000));
|
||||
@ -137,7 +175,7 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
|
||||
}
|
||||
|
||||
// GPS Stuff
|
||||
GpsDirectory gpsDir = metadata.getDirectory(GpsDirectory.class);
|
||||
GpsDirectory gpsDir = metadata.getFirstDirectoryOfType(GpsDirectory.class);
|
||||
if (gpsDir != null) {
|
||||
GeoLocation loc = gpsDir.getGeoLocation();
|
||||
if (loc != null) {
|
||||
@ -147,14 +185,14 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
|
||||
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID(), ExifParserModuleFactory.getModuleName(), longitude));
|
||||
}
|
||||
|
||||
Rational altitude = gpsDir.getRational(GpsDirectory.TAG_GPS_ALTITUDE);
|
||||
Rational altitude = gpsDir.getRational(GpsDirectory.TAG_ALTITUDE);
|
||||
if (altitude != null) {
|
||||
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID(), ExifParserModuleFactory.getModuleName(), altitude.doubleValue()));
|
||||
}
|
||||
}
|
||||
|
||||
// Device info
|
||||
ExifIFD0Directory devDir = metadata.getDirectory(ExifIFD0Directory.class);
|
||||
ExifIFD0Directory devDir = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
|
||||
if (devDir != null) {
|
||||
String model = devDir.getString(ExifIFD0Directory.TAG_MODEL);
|
||||
if (model != null && !model.isEmpty()) {
|
||||
@ -167,6 +205,11 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
|
||||
}
|
||||
}
|
||||
|
||||
if (containsFace(metadata)) {
|
||||
listOfFacesDetectedArtifacts.add(f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_FACE_DETECTED));
|
||||
facesDetected = true;
|
||||
}
|
||||
|
||||
// Add the attributes, if there are any, to a new artifact
|
||||
if (!attributes.isEmpty()) {
|
||||
BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF);
|
||||
@ -199,6 +242,121 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this metadata contains any tags related to facial information.
|
||||
* NOTE: Cases with this metadata containing tags like enabled red-eye
|
||||
* reduction settings, portrait settings, etc are also assumed to contain
|
||||
* facial information. The method returns true. The return value of this
|
||||
* method does NOT guarantee actual presence of face.
|
||||
*
|
||||
* @param metadata the metadata which needs to be parsed for possible facial
|
||||
* information.
|
||||
*
|
||||
* @return returns true if the metadata contains any tags related to facial
|
||||
* information.
|
||||
*/
|
||||
private boolean containsFace(Metadata metadata) {
|
||||
Directory d = metadata.getFirstDirectoryOfType(CanonMakernoteDirectory.class);
|
||||
if (d != null) {
|
||||
if (d.containsTag(CanonMakernoteDirectory.TAG_FACE_DETECT_ARRAY_1)
|
||||
&& d.getString(CanonMakernoteDirectory.TAG_FACE_DETECT_ARRAY_1) != null) {
|
||||
return true;
|
||||
}
|
||||
if (d.containsTag(CanonMakernoteDirectory.TAG_FACE_DETECT_ARRAY_2)
|
||||
&& d.getString(CanonMakernoteDirectory.TAG_FACE_DETECT_ARRAY_2) != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
d = metadata.getFirstDirectoryOfType(CasioType1MakernoteDirectory.class);
|
||||
if (d != null) {
|
||||
try {
|
||||
if (d.containsTag(CasioType1MakernoteDirectory.TAG_FLASH_MODE)
|
||||
&& d.getInt(CasioType1MakernoteDirectory.TAG_FLASH_MODE) == 0x04) { //0x04 = "Red eye reduction"
|
||||
return true;
|
||||
}
|
||||
} catch (MetadataException ex) {
|
||||
// move on and check next directory
|
||||
}
|
||||
}
|
||||
|
||||
d = metadata.getFirstDirectoryOfType(FujifilmMakernoteDirectory.class);
|
||||
if (d != null) {
|
||||
if (d.containsTag(FujifilmMakernoteDirectory.TAG_FACES_DETECTED)
|
||||
&& d.getString(FujifilmMakernoteDirectory.TAG_FACES_DETECTED) != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
d = metadata.getFirstDirectoryOfType(KodakMakernoteDirectory.class);
|
||||
if (d != null) {
|
||||
try {
|
||||
if (d.containsTag(KodakMakernoteDirectory.TAG_FLASH_MODE)
|
||||
&& d.getInt(KodakMakernoteDirectory.TAG_FLASH_MODE) == 0x03) { //0x03 = "Red Eye"
|
||||
return true;
|
||||
}
|
||||
} catch (MetadataException ex) {
|
||||
/// move on and check next directory
|
||||
}
|
||||
}
|
||||
|
||||
d = metadata.getFirstDirectoryOfType(NikonType2MakernoteDirectory.class);
|
||||
if (d != null) {
|
||||
if (d.containsTag(NikonType2MakernoteDirectory.TAG_SCENE_MODE)
|
||||
&& d.getString(NikonType2MakernoteDirectory.TAG_SCENE_MODE) != null
|
||||
&& (d.getString(NikonType2MakernoteDirectory.TAG_SCENE_MODE).equals("BEST FACE") // NON-NLS
|
||||
|| (d.getString(NikonType2MakernoteDirectory.TAG_SCENE_MODE).equals("SMILE")))) { // NON-NLS
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
d = metadata.getFirstDirectoryOfType(PanasonicMakernoteDirectory.class);
|
||||
if (d != null) {
|
||||
if (d.containsTag(PanasonicMakernoteDirectory.TAG_FACES_DETECTED)
|
||||
&& d.getString(PanasonicMakernoteDirectory.TAG_FACES_DETECTED) != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
d = metadata.getFirstDirectoryOfType(PentaxMakernoteDirectory.class);
|
||||
if (d != null) {
|
||||
try {
|
||||
if (d.containsTag(PentaxMakernoteDirectory.TAG_FLASH_MODE)
|
||||
&& d.getInt(PentaxMakernoteDirectory.TAG_FLASH_MODE) == 6) { // 6 = Red-eye Reduction
|
||||
return true;
|
||||
}
|
||||
} catch (MetadataException ex) {
|
||||
// move on and check next directory
|
||||
}
|
||||
}
|
||||
|
||||
d = metadata.getFirstDirectoryOfType(SanyoMakernoteDirectory.class);
|
||||
if (d != null) {
|
||||
if (d.containsTag(SanyoMakernoteDirectory.TAG_MANUAL_FOCUS_DISTANCE_OR_FACE_INFO)
|
||||
&& d.getString(SanyoMakernoteDirectory.TAG_MANUAL_FOCUS_DISTANCE_OR_FACE_INFO) != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
d = metadata.getFirstDirectoryOfType(SonyType1MakernoteDirectory.class);
|
||||
if (d != null) {
|
||||
try {
|
||||
if (d.containsTag(SonyType1MakernoteDirectory.TAG_AF_MODE)
|
||||
&& d.getInt(SonyType1MakernoteDirectory.TAG_AF_MODE) == 15) { //15 = "Face Detected"
|
||||
return true;
|
||||
}
|
||||
if (d.containsTag(SonyType1MakernoteDirectory.TAG_EXPOSURE_MODE)
|
||||
&& d.getInt(SonyType1MakernoteDirectory.TAG_EXPOSURE_MODE) == 14) { //14 = "Smile shutter"
|
||||
return true;
|
||||
}
|
||||
} catch (MetadataException ex) {
|
||||
// move on and check next directory
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if should try to attempt to extract exif. Currently checks if JPEG
|
||||
* image (by signature)
|
||||
@ -225,10 +383,15 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
|
||||
public void shutDown() {
|
||||
// We only need to check for this final event on the last module per job
|
||||
if (refCounter.decrementAndGet(jobId) == 0) {
|
||||
timeZone = null;
|
||||
if (filesToFire) {
|
||||
//send the final new data event
|
||||
services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF));
|
||||
}
|
||||
if (facesDetected) {
|
||||
//send the final new data event
|
||||
services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_FACE_DETECTED, listOfFacesDetectedArtifacts));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user