diff --git a/bindings/java/jni/auto_db_java.cpp b/bindings/java/jni/auto_db_java.cpp
index 625739f8a5a374dc18ef49a0cf983277f1c493c6..a20fd04b4a53c1d9938093babd2ad1e0be6b928a 100644
--- a/bindings/java/jni/auto_db_java.cpp
+++ b/bindings/java/jni/auto_db_java.cpp
@@ -1029,6 +1029,11 @@ TskAutoDbJava::openImage(const char* a_deviceId)
 uint8_t
 TskAutoDbJava::addImageDetails(const char* deviceId)
 {
+    // The image has already been added to the database
+    if (m_curImgId > 0) {
+        return 0;
+    }
+
    string md5 = "";
    string sha1 = "";
    string collectionDetails = "";
@@ -1504,6 +1509,15 @@ TskAutoDbJava::setTz(string tzone)
     m_curImgTZone = tzone;
 }
 
+/**
+ * Set the object ID for the data source
+ */
+void 
+TskAutoDbJava::setDatasourceObjId(int64_t img_id)
+{
+    m_curImgId = img_id;
+}
+
 TSK_RETVAL_ENUM
 TskAutoDbJava::processFile(TSK_FS_FILE * fs_file, const char *path)
 {
diff --git a/bindings/java/jni/auto_db_java.h b/bindings/java/jni/auto_db_java.h
index f2570cf2294b6ebacd0978857c7a17b672269447..26e370d093b7229cad868d813969be22324930a5 100644
--- a/bindings/java/jni/auto_db_java.h
+++ b/bindings/java/jni/auto_db_java.h
@@ -44,6 +44,7 @@ class TskAutoDbJava :public TskAuto {
     virtual void closeImage();
     void close();
     virtual void setTz(string tzone);
+    virtual void setDatasourceObjId(int64_t img_id);
 
     virtual TSK_FILTER_ENUM filterVs(const TSK_VS_INFO * vs_info);
     virtual TSK_FILTER_ENUM filterVol(const TSK_VS_PART_INFO * vs_part);
diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.cpp b/bindings/java/jni/dataModel_SleuthkitJNI.cpp
index 5452ccbeac183314b784bbc25a37ce681511a3af..f4da3b4b62a2c5b29289ca6962b732af7a9bf1eb 100644
--- a/bindings/java/jni/dataModel_SleuthkitJNI.cpp
+++ b/bindings/java/jni/dataModel_SleuthkitJNI.cpp
@@ -15,6 +15,10 @@
 #include "tsk/img/img_writer.h"
 #include "tsk/img/raw.h"
 #include "auto_db_java.h"
+#if HAVE_LIBEWF
+#include "tsk/img/ewf.h"
+#include "tsk/img/tsk_img_i.h"
+#endif
 #include "jni.h"
 #include "dataModel_SleuthkitJNI.h"
 #include <locale.h>
@@ -905,7 +909,7 @@ JNIEXPORT void JNICALL
     TskAutoDbJava *tskAuto = ((TskAutoDbJava *) process);
     if (!tskAuto || tskAuto->m_tag != TSK_AUTO_TAG) {
         setThrowTskCoreError(env, 
-            "runAddImgNat: Invalid TskAutoDbJava object passed in");
+            "runOpenAndAddImgNat: Invalid TskAutoDbJava object passed in");
         return;
     }
 
@@ -914,7 +918,7 @@ JNIEXPORT void JNICALL
     if (NULL != deviceId) {    
         device_id = (const char *) env->GetStringUTFChars(deviceId, &isCopy);
         if (NULL == device_id) {
-            setThrowTskCoreError(env, "runAddImgNat: Can't convert data source id string");
+            setThrowTskCoreError(env, "runOpenAndAddImgNat: Can't convert data source id string");
             return;
         }
     }
@@ -933,7 +937,7 @@ JNIEXPORT void JNICALL
             GetStringUTFChars(jsPath, &isCopy);
         if (imagepaths8[i] == NULL) {
             setThrowTskCoreError(env,
-                "runAddImgNat: Can't convert path strings.");
+                "runOpenAndAddImgNat: Can't convert path strings.");
             // @@@ should cleanup here paths that have been converted in imagepaths8[i]
             return;
         }
@@ -997,11 +1001,12 @@ JNIEXPORT void JNICALL
 * @param process the add-image process created by initAddImgNat
 * @param deviceId An ASCII-printable identifier for the device associated with the data source that is intended to be unique across multiple cases (e.g., a UUID)
 * @param a_img_info image info object
+* @param img_id The object ID of the image in the database
 * @param timeZone the timezone the image is from
 */
 JNIEXPORT void JNICALL
 Java_org_sleuthkit_datamodel_SleuthkitJNI_runAddImgNat(JNIEnv * env,
-    jclass obj, jlong process, jstring deviceId, jlong a_img_info, jstring timeZone, jstring imageWriterPathJ) {
+    jclass obj, jlong process, jstring deviceId, jlong a_img_info, jlong img_id, jstring timeZone, jstring imageWriterPathJ) {
     
     TskAutoDbJava *tskAuto = ((TskAutoDbJava *)process);
     if (!tskAuto || tskAuto->m_tag != TSK_AUTO_TAG) {
@@ -1020,6 +1025,9 @@ Java_org_sleuthkit_datamodel_SleuthkitJNI_runAddImgNat(JNIEnv * env,
         }
     }
 
+    // Set the data source object ID
+    tskAuto->setDatasourceObjId(img_id);
+
     // Set the time zone.
     if (env->GetStringLength(timeZone) > 0) {
         const char *time_zone = env->GetStringUTFChars(timeZone, &isCopy);
@@ -1125,7 +1133,6 @@ Java_org_sleuthkit_datamodel_SleuthkitJNI_finishAddImgNat(JNIEnv * env,
 }
 
 
-
 /*
  * Open an image pointer for the given image.
  * @return the created TSK_IMG_INFO pointer
@@ -1142,23 +1149,23 @@ JNIEXPORT jlong JNICALL
     jboolean isCopy;
 
     // get pointers to each of the file names
-    char **imagepaths8 = (char **) tsk_malloc(num_imgs * sizeof(char *));
+    char **imagepaths8 = (char **)tsk_malloc(num_imgs * sizeof(char *));
     if (imagepaths8 == NULL) {
         setThrowTskCoreError(env);
         return 0;
     }
     for (int i = 0; i < num_imgs; i++) {
         imagepaths8[i] =
-            (char *) env->
-            GetStringUTFChars((jstring) env->GetObjectArrayElement(paths,
+            (char *)env->
+            GetStringUTFChars((jstring)env->GetObjectArrayElement(paths,
                 i), &isCopy);
         // @@@ Error check
     }
 
     // open the image
     img_info =
-        tsk_img_open_utf8((int) num_imgs, imagepaths8, TSK_IMG_TYPE_DETECT,
-        sector_size);
+        tsk_img_open_utf8((int)num_imgs, imagepaths8, TSK_IMG_TYPE_DETECT,
+            sector_size);
     if (img_info == NULL) {
         setThrowTskCoreError(env, tsk_error_get());
     }
@@ -1167,14 +1174,186 @@ JNIEXPORT jlong JNICALL
     for (int i = 0; i < num_imgs; i++) {
         env->
             ReleaseStringUTFChars((jstring)
-            env->GetObjectArrayElement(paths, i), imagepaths8[i]);
+                env->GetObjectArrayElement(paths, i), imagepaths8[i]);
     }
     free(imagepaths8);
 
     return (jlong) img_info;
 }
 
+/*
+ * Get the full list of paths associated with an image.
+ */
+JNIEXPORT jobjectArray JNICALL
+Java_org_sleuthkit_datamodel_SleuthkitJNI_getPathsForImageNat(JNIEnv * env,
+    jclass obj, jlong a_img_info) {
+
+    TSK_IMG_INFO *img_info = castImgInfo(env, a_img_info);
+    if (img_info == 0) {
+        //exception already set
+        return 0;
+    }
+
+    char **img_ptrs;
+#ifdef TSK_WIN32
+    // convert image paths to UTF-8
+    img_ptrs = (char **)tsk_malloc(img_info->num_img * sizeof(char *));
+    if (img_ptrs == NULL) {
+        return (jobjectArray)env->NewObjectArray(0, env->FindClass("java/lang/String"), env->NewStringUTF(""));
+    }
+
+    for (int i = 0; i < img_info->num_img; i++) {
+        char * img2 = (char*)tsk_malloc(1024 * sizeof(char));
+        UTF8 *ptr8;
+        UTF16 *ptr16;
+
+        ptr8 = (UTF8 *)img2;
+        ptr16 = (UTF16 *)img_info->images[i];
+
+        uint8_t retval =
+            tsk_UTF16toUTF8_lclorder((const UTF16 **)&ptr16, (UTF16 *)
+                & ptr16[TSTRLEN(img_info->images[i]) + 1], &ptr8,
+                (UTF8 *)((uintptr_t)ptr8 + 1024), TSKlenientConversion);
+        if (retval != TSKconversionOK) {
+            tsk_error_reset();
+            tsk_error_set_errno(TSK_ERR_AUTO_UNICODE);
+            tsk_error_set_errstr("Error converting image to UTF-8\n");
+            return (jobjectArray)env->NewObjectArray(0, env->FindClass("java/lang/String"), env->NewStringUTF(""));
+        }
+        img_ptrs[i] = img2;
+    }
+#else 
+    img_ptrs = img_info->images;
+#endif
+
+    jobjectArray path_list = (jobjectArray)env->NewObjectArray(img_info->num_img, env->FindClass("java/lang/String"), env->NewStringUTF(""));
+    for (int i = 0; i < img_info->num_img; i++) {
+        env->SetObjectArrayElement(path_list, i, env->NewStringUTF(img_ptrs[i]));
+    }
+
+    return path_list;
+}
+
+
+/*
+ * Get the size of an image.
+ */
+JNIEXPORT jlong JNICALL
+Java_org_sleuthkit_datamodel_SleuthkitJNI_getSizeForImageNat(JNIEnv * env,
+    jclass obj, jlong a_img_info) {
+
+    TSK_IMG_INFO *img_info = castImgInfo(env, a_img_info);
+    if (img_info == 0) {
+        //exception already set
+        return 0;
+    }
+
+    return img_info->size;
+}
+
+
+/*
+ * Get the type of an image.
+ */
+JNIEXPORT jlong JNICALL
+Java_org_sleuthkit_datamodel_SleuthkitJNI_getTypeForImageNat(JNIEnv * env,
+    jclass obj, jlong a_img_info) {
+
+    TSK_IMG_INFO *img_info = castImgInfo(env, a_img_info);
+    if (img_info == 0) {
+        //exception already set
+        return 0;
+    }
+
+    return img_info->itype;
+}
+
+
+/*
+* Get the computed sector size of an image.
+*/
+JNIEXPORT jlong JNICALL
+Java_org_sleuthkit_datamodel_SleuthkitJNI_getSectorSizeForImageNat(JNIEnv * env,
+    jclass obj, jlong a_img_info) {
+
+    TSK_IMG_INFO *img_info = castImgInfo(env, a_img_info);
+    if (img_info == 0) {
+        //exception already set
+        return 0;
+    }
+
+    return img_info->sector_size;
+}
+
+/*
+* Get the md5 hash of an image.
+*/
+JNIEXPORT jstring JNICALL
+Java_org_sleuthkit_datamodel_SleuthkitJNI_getMD5HashForImageNat(JNIEnv * env,
+    jclass obj, jlong a_img_info) {
+
+    TSK_IMG_INFO *img_info = castImgInfo(env, a_img_info);
+    if (img_info == 0) {
+        //exception already set
+        return 0;
+    }
+    // env->NewStringUTF(img_ptrs[i])
+#if HAVE_LIBEWF 
+    if (img_info->itype == TSK_IMG_TYPE_EWF_EWF) {
+        IMG_EWF_INFO *ewf_info = (IMG_EWF_INFO *)img_info;
+        if (ewf_info->md5hash_isset) {
+            return env->NewStringUTF(ewf_info->md5hash);
+        }
+    }
+#endif
+    return env->NewStringUTF("");
+}
 
+/*
+* Get the sha1 hash of an image.
+*/
+JNIEXPORT jstring JNICALL
+Java_org_sleuthkit_datamodel_SleuthkitJNI_getSha1HashForImageNat(JNIEnv * env,
+    jclass obj, jlong a_img_info) {
+
+    TSK_IMG_INFO *img_info = castImgInfo(env, a_img_info);
+    if (img_info == 0) {
+        //exception already set
+        return 0;
+    }
+    // env->NewStringUTF(img_ptrs[i])
+#if HAVE_LIBEWF 
+    if (img_info->itype == TSK_IMG_TYPE_EWF_EWF) {
+        IMG_EWF_INFO *ewf_info = (IMG_EWF_INFO *)img_info;
+        if (ewf_info->sha1hash_isset) {
+            return env->NewStringUTF(ewf_info->sha1hash);
+        }
+    }
+#endif
+    return env->NewStringUTF("");
+}
+
+/*
+* Get the collection details of an image.
+*/
+JNIEXPORT jstring JNICALL
+Java_org_sleuthkit_datamodel_SleuthkitJNI_getCollectionDetailsForImageNat(JNIEnv * env,
+    jclass obj, jlong a_img_info) {
+
+    TSK_IMG_INFO *img_info = castImgInfo(env, a_img_info);
+    if (img_info == 0) {
+        //exception already set
+        return 0;
+    }
+    // env->NewStringUTF(img_ptrs[i])
+#if HAVE_LIBEWF 
+    if (img_info->itype == TSK_IMG_TYPE_EWF_EWF) {
+        IMG_EWF_INFO *ewf_info = (IMG_EWF_INFO *)img_info;
+        ewf_get_details(ewf_info);
+    }
+#endif
+    return env->NewStringUTF("");
+}
 
 /*
  * Open the volume system at the given offset
diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.h b/bindings/java/jni/dataModel_SleuthkitJNI.h
index ebd2b8fc39ef3a1ebe032e5bc153b00f24cf16bf..ed49532dc0106f329d0e134e5909ac8d41504036 100644
--- a/bindings/java/jni/dataModel_SleuthkitJNI.h
+++ b/bindings/java/jni/dataModel_SleuthkitJNI.h
@@ -194,10 +194,10 @@ JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_runOpenAndAddIm
 /*
  * Class:     org_sleuthkit_datamodel_SleuthkitJNI
  * Method:    runAddImgNat
- * Signature: (JLjava/lang/String;JLjava/lang/String;Ljava/lang/String;)V
+ * Signature: (JLjava/lang/String;JJLjava/lang/String;Ljava/lang/String;)V
  */
 JNIEXPORT void JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_runAddImgNat
-  (JNIEnv *, jclass, jlong, jstring, jlong, jstring, jstring);
+  (JNIEnv *, jclass, jlong, jstring, jlong, jlong, jstring, jstring);
 
 /*
  * Class:     org_sleuthkit_datamodel_SleuthkitJNI
@@ -327,6 +327,62 @@ JNIEXPORT jint JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_readFileNat
 JNIEXPORT jint JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_saveFileMetaDataTextNat
   (JNIEnv *, jclass, jlong, jstring);
 
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    getPathsForImageNat
+ * Signature: (J)[Ljava/lang/String;
+ */
+JNIEXPORT jobjectArray JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getPathsForImageNat
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    getSizeForImageNat
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getSizeForImageNat
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    getTypeForImageNat
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getTypeForImageNat
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    getSectorSizeForImageNat
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getSectorSizeForImageNat
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    getMD5HashForImageNat
+ * Signature: (J)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getMD5HashForImageNat
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    getSha1HashForImageNat
+ * Signature: (J)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getSha1HashForImageNat
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     org_sleuthkit_datamodel_SleuthkitJNI
+ * Method:    getCollectionDetailsForImageNat
+ * Signature: (J)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getCollectionDetailsForImageNat
+  (JNIEnv *, jclass, jlong);
+
 /*
  * Class:     org_sleuthkit_datamodel_SleuthkitJNI
  * Method:    closeImgNat
diff --git a/bindings/java/src/org/sleuthkit/datamodel/AddDataSourceCallbacks.java b/bindings/java/src/org/sleuthkit/datamodel/AddDataSourceCallbacks.java
index 2e5ee97dc7d1090fcd1963cd45d2aba474730f7c..ac4912ad33434d58ee146ba4ff1479730d5c47d0 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/AddDataSourceCallbacks.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/AddDataSourceCallbacks.java
@@ -24,13 +24,6 @@
  * Provides callbacks at key points during the process of adding a data source to a case database.
  */
 public interface AddDataSourceCallbacks {
-    /**
-     * Call when the data source has been completely added to the case database.
-     * 
-     * @param dataSourceObjectId The object ID of the new data source
-     */
-    void onDataSourceAdded(long dataSourceObjectId);
-    
     /**
      * Call to add a set of file object IDs that have been added to the database.
      * 
diff --git a/bindings/java/src/org/sleuthkit/datamodel/DefaultAddDataSourceCallbacks.java b/bindings/java/src/org/sleuthkit/datamodel/DefaultAddDataSourceCallbacks.java
index 920f6079dcb79813f1faaacbdd30eb40988441ac..db378ae750103d5f4b08f0f389a6fef766cd8f62 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/DefaultAddDataSourceCallbacks.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/DefaultAddDataSourceCallbacks.java
@@ -24,15 +24,8 @@
  * Do-nothing version of AddDataSourceCallbacks
  */
 public class DefaultAddDataSourceCallbacks implements AddDataSourceCallbacks {
-
-	@Override
-	public void onDataSourceAdded(long dataSourceObjectId) {
-		// Do nothing
-	}
-
-	@Override
-	public void onFilesAdded(List<Long> fileObjectIds) {
-		// Do nothing
-	}
-	
+    @Override
+    public void onFilesAdded(List<Long> fileObjectIds) {
+        // Do nothing
+    }	
 }
diff --git a/bindings/java/src/org/sleuthkit/datamodel/Image.java b/bindings/java/src/org/sleuthkit/datamodel/Image.java
index 161e51f3adb132a14d83394f521c0349293ac93b..a465af5975966e2f9cc12870732f1af7f1a3328c 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/Image.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/Image.java
@@ -129,6 +129,10 @@ public synchronized long getImageHandle() throws TskCoreException {
 
 		return imageHandle;
 	}
+	
+	synchronized void setImageHandle(long imageHandle) {
+		this.imageHandle = imageHandle;
+	}
 
 	@Override
 	public Content getDataSource() {
diff --git a/bindings/java/src/org/sleuthkit/datamodel/JniDbHelper.java b/bindings/java/src/org/sleuthkit/datamodel/JniDbHelper.java
index 8c6c1d545bf191500fcf022558d8af95c3e2e502..95df24bf8c5fbc19fca86e9eaa08bfb88206d64c 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/JniDbHelper.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/JniDbHelper.java
@@ -107,6 +107,8 @@ void finish() {
     /**
      * Add a new image to the database.
      * Intended to be called from the native code during the add image process.
+	 * Will not be called if the image was added to the database prior to starting
+	 * the add image process.
      * 
      * @param type        Type of image.
      * @param ssize       Sector size.
@@ -131,14 +133,6 @@ long addImageInfo(int type, long ssize, String timezone,
                 caseDb.addImageNameJNI(objId, paths[i], i, trans);
             }
             commitTransaction();
-            
-			try {
-				addDataSourceCallbacks.onDataSourceAdded(objId);
-			} catch (Exception ex) {
-				// Exception firewall - we do not want to return to the native code without
-				// passing it the data source ID
-				logger.log(Level.SEVERE, "Unexpected error from data source added callback", ex);
-			}
             return objId;
         } catch (TskCoreException ex) {
             logger.log(Level.SEVERE, "Error adding image to the database", ex);
diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
index 3c9ea38d733ae1fcc1ca3093c2fa6199d42d1f73..cc6b85ba950d1df91ec5e650054ce038624835eb 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java
@@ -5920,7 +5920,16 @@ public Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size
 			connection.executeUpdate(preparedStatement);
 
 			// Create the new Image object
-			return new Image(this, newObjId, type.getValue(), deviceId, sectorSize, displayName,
+			String name = displayName;
+			if (name == null || name.isEmpty()) {
+				if (imagePaths.size() > 0) {
+					String path = imagePaths.get(0);
+					name = (new java.io.File(path)).getName();
+				} else {
+					name = "";
+				}
+			}			
+			return new Image(this, newObjId, type.getValue(), deviceId, sectorSize, name,
 					imagePaths.toArray(new String[imagePaths.size()]), timezone, md5, sha1, sha256, savedSize);
 		} catch (SQLException ex) {
 			if (!imagePaths.isEmpty()) {
diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java
index d0ad7bb3d437b07288b78a71a7c2f73dd609c8e3..104488c1e4fd1e6bf7e10b302d2ebcc6fd63099b 100644
--- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java
+++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java
@@ -35,7 +35,9 @@
 import java.util.UUID;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
+import org.apache.commons.lang3.StringUtils;
 import org.sleuthkit.datamodel.TskData.TSK_FS_ATTR_TYPE_ENUM;
+import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction;
 
 /**
  * A utility class that provides a interface to the SleuthKit via JNI. Supports
@@ -514,32 +516,29 @@ private AddImageProcess(String timeZone, boolean addUnallocSpace, boolean skipFa
 			 *                          the process)
 			 */
 			public void run(String deviceId, String[] imageFilePaths, int sectorSize) throws TskCoreException, TskDataException {
-				run(deviceId, imageFilePaths, sectorSize, new DefaultAddDataSourceCallbacks());
+				Image img = addImageToDatabase(skCase, imageFilePaths, sectorSize, "", "", "", "", deviceId);
+				run(deviceId, img, sectorSize, new DefaultAddDataSourceCallbacks());
 			}
-			
+
 			/**
 			 * Starts the process of adding an image to the case database.
-			 * Either AddImageProcess.commit or AddImageProcess.revert MUST be
-			 * called after calling AddImageProcess.run.
 			 *
 			 * @param deviceId       An ASCII-printable identifier for the
 			 *                       device associated with the image that
 			 *                       should be unique across multiple cases
 			 *                       (e.g., a UUID).
-			 * @param imageFilePaths Full path(s) to the image file(s).
-			 * @param sectorSize     The sector size (use '0' for autodetect).
+			 * @param image          The image object (has already been added to the database)
+			 * @param sectorSize     The sector size (no longer used).
 			 * @param addDataSourceCallbacks  The callbacks to use to send data to ingest (may do nothing).
 			 *
-			 * @return The object ID of the new image.
-			 * 
 			 * @throws TskCoreException if a critical error occurs within the
 			 *                          SleuthKit.
 			 * @throws TskDataException if a non-critical error occurs within
 			 *                          the SleuthKit (should be OK to continue
 			 *                          the process)
 			 */
-			public long run(String deviceId, String[] imageFilePaths, int sectorSize, 
-					AddDataSourceCallbacks addDataSourceCallbacks) throws TskCoreException, TskDataException {
+			public void run(String deviceId, Image image, int sectorSize, 
+					AddDataSourceCallbacks addDataSourceCallbacks) throws TskCoreException, TskDataException {			
 				dbHelper = new JniDbHelper(skCase, addDataSourceCallbacks);
 				getTSKReadLock();
 				try {
@@ -549,7 +548,7 @@ public long run(String deviceId, String[] imageFilePaths, int sectorSize,
 							throw new TskCoreException("Add image process already started");
 						}
 						if (!isCanceled) { //with isCanceled being guarded by this it will have the same value everywhere in this synchronized block
-							imageHandle = openImage(imageFilePaths, sectorSize, false, caseDbIdentifier);
+							imageHandle = image.getImageHandle();
 							tskAutoDbPointer = initAddImgNat(dbHelper, timezoneLongToShort(timeZone), addUnallocSpace, skipFatFsOrphans);
 						}
 						if (0 == tskAutoDbPointer) {
@@ -557,16 +556,12 @@ public long run(String deviceId, String[] imageFilePaths, int sectorSize,
 						}
 					}
 					if (imageHandle != 0) {
-						runAddImgNat(tskAutoDbPointer, deviceId, imageHandle, timeZone, imageWriterPath);
-						
+						runAddImgNat(tskAutoDbPointer, deviceId, imageHandle, image.getId(), timeZone, imageWriterPath);
 					}
 				} finally {
 					finishAddImageProcess();
 					releaseTSKReadLock();
 				}
-				synchronized (this) {
-					return imageId;
-				}
 			}			
 
 			/**
@@ -679,8 +674,6 @@ public void run(String[] imageFilePaths) throws TskCoreException, TskDataExcepti
 
 			/**
 			 * Starts the process of adding an image to the case database.
-			 * Either AddImageProcess.commit or AddImageProcess.revert MUST be
-			 * called after calling AddImageProcess.run.
 			 *
 			 * @param deviceId       An ASCII-printable identifier for the
 			 *                       device associated with the image that
@@ -837,7 +830,6 @@ public static long openImage(String[] imageFiles, int sSize, SleuthkitCase skCas
 	 *                          TSK
 	 */
 	private static long openImage(String[] imageFiles, int sSize, boolean useCache, String caseIdentifer) throws TskCoreException {
-
 		getTSKReadLock();
 		try {
 			long imageHandle;
@@ -884,6 +876,105 @@ private static long openImage(String[] imageFiles, int sSize, boolean useCache,
 			releaseTSKReadLock();
 		}
 	}
+	
+	/**
+	 * This is a temporary measure to support opening an image at the beginning
+	 * of the add image process. The open image handle is put into the normal image cache so
+	 * it won't be opened a second time and it will be closed during case closing.
+	 * 
+	 * This will change when all image opens are done by object ID and not paths.
+	 * 
+	 * @param skCase      The case the image belongs to.
+	 * @param imagePaths  The complete list of paths for the image.
+	 * @param imageHandle The open image handle from TSK.
+	 */
+	private static void cacheImageHandle(SleuthkitCase skCase, List<String> imagePaths, long imageHandle) {
+		
+		// Construct the hash key from the image paths
+		StringBuilder keyBuilder = new StringBuilder();
+		for (int i = 0; i < imagePaths.size(); ++i) {
+			keyBuilder.append(imagePaths.get(i));
+		}
+		final String imageKey = keyBuilder.toString();
+		
+		// Get the case identifier
+		try {
+			String caseIdentifier = skCase.getUniqueCaseIdentifier();
+		
+			synchronized (HandleCache.cacheLock) {
+				HandleCache.getCaseHandles(caseIdentifier).fsHandleCache.put(imageHandle, new HashMap<>());
+				HandleCache.getCaseHandles(caseIdentifier).imageHandleCache.put(imageKey, imageHandle);
+			}
+		} catch (TskCoreException ex) {
+			// getUniqueCaseIdentfier() will only fail if the case is closed
+		}
+	}
+	
+	/**
+	 * Add an image to the database and return the open image.
+	 * 
+	 * @param skCase     The current case.
+	 * @param imagePaths The path(s) to the image (will just be the first for .e01, .001, etc).
+	 * @param sectorSize The sector size (0 for auto-detect).
+	 * @param timeZone   The time zone.
+	 * @param md5fromSettings        MD5 hash (if known).
+	 * @param sha1fromSettings       SHA1 hash (if known).
+	 * @param sha256fromSettings     SHA256 hash (if known).
+	 * @param deviceId   Device ID.
+	 * 
+	 * @return The Image object.
+	 * 
+	 * @throws TskCoreException 
+	 */
+	public static Image addImageToDatabase(SleuthkitCase skCase, String[] imagePaths, int sectorSize,
+		String timeZone, String md5fromSettings, String sha1fromSettings, String sha256fromSettings, String deviceId) throws TskCoreException {
+		
+		// Open the image
+		long imageHandle = openImgNat(imagePaths, 1, sectorSize);
+		
+		// Get the fields stored in the native code
+		List<String> computedPaths = Arrays.asList(getPathsForImageNat(imageHandle));
+		long size = getSizeForImageNat(imageHandle);
+		long type = getTypeForImageNat(imageHandle);
+		long computedSectorSize = getSectorSizeForImageNat(imageHandle);
+		String md5 = md5fromSettings;
+		if (StringUtils.isEmpty(md5)) {
+			md5 = getMD5HashForImageNat(imageHandle);
+		}
+		String sha1 = sha1fromSettings;
+		if (StringUtils.isEmpty(sha1)) {
+			sha1 = getSha1HashForImageNat(imageHandle);
+		}
+		// Sleuthkit does not currently generate any SHA256 hashes. Set to empty
+		// string for consistency.
+		String sha256 = sha256fromSettings;
+		if (sha256 == null) {
+			sha256 = "";
+		}
+		String collectionDetails = getCollectionDetailsForImageNat(imageHandle);
+		
+		//  Now save to database
+		CaseDbTransaction transaction = skCase.beginTransaction();
+		try {
+			Image img = skCase.addImage(TskData.TSK_IMG_TYPE_ENUM.valueOf(type), computedSectorSize, 
+				size, null, computedPaths, 
+				timeZone, md5, sha1, sha256, 
+				deviceId, transaction);
+			if (!StringUtils.isEmpty(collectionDetails)) {
+				skCase.setAcquisitionDetails(img, collectionDetails);
+			}
+			transaction.commit();
+			
+		    img.setImageHandle(imageHandle);
+			cacheImageHandle(skCase, computedPaths, imageHandle);
+			return img;
+		} catch (TskCoreException ex) {
+			transaction.rollback();
+			throw(ex);
+		}
+	}
+	
+	
 
 	/**
 	 * Get volume system Handle
@@ -2000,7 +2091,7 @@ public static long openFile(long fsHandle, long fileId, TSK_FS_ATTR_TYPE_ENUM at
 
 	private static native void runOpenAndAddImgNat(long process, String deviceId, String[] imgPath, int splits, String timezone) throws TskCoreException, TskDataException;
 
-	private static native void runAddImgNat(long process, String deviceId, long a_img_info, String timeZone, String imageWriterPath) throws TskCoreException, TskDataException;
+	private static native void runAddImgNat(long process, String deviceId, long a_img_info, long image_id, String timeZone, String imageWriterPath) throws TskCoreException, TskDataException;
 
 	private static native void stopAddImgNat(long process) throws TskCoreException;
 
@@ -2033,6 +2124,20 @@ public static long openFile(long fsHandle, long fileId, TSK_FS_ATTR_TYPE_ENUM at
 	private static native int readFileNat(long fileHandle, byte[] readBuffer, long offset, int offset_type, long len) throws TskCoreException;
 
 	private static native int saveFileMetaDataTextNat(long fileHandle, String fileName) throws TskCoreException;
+	
+	private static native String[] getPathsForImageNat(long imgHandle);
+	
+	private static native long getSizeForImageNat(long imgHandle);
+	
+	private static native long getTypeForImageNat(long imgHandle);
+	
+	private static native long getSectorSizeForImageNat(long imgHandle);
+	
+	private static native String getMD5HashForImageNat(long imgHandle);
+	
+	private static native String getSha1HashForImageNat(long imgHandle);
+	
+	private static native String getCollectionDetailsForImageNat(long imgHandle);
 
 	private static native void closeImgNat(long imgHandle);