mirror of
https://github.com/elisspace/autopsy.git
synced 2026-10-03 15:59:52 +00:00
move ReadImageTask to ImageUtils, refactoring in IG to use readImageTask
This commit is contained in:
@@ -21,23 +21,16 @@ package org.sleuthkit.autopsy.corecomponents;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import static java.util.Objects.nonNull;
|
||||
import java.util.SortedSet;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import javafx.application.Platform;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.concurrent.WorkerStateEvent;
|
||||
import javafx.embed.swing.JFXPanel;
|
||||
import javafx.embed.swing.SwingFXUtils;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Cursor;
|
||||
@@ -49,13 +42,7 @@ import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.event.IIOReadProgressListener;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.swing.JPanel;
|
||||
import org.controlsfx.control.MaskerPane;
|
||||
import org.openide.util.NbBundle;
|
||||
@@ -66,8 +53,6 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.FileNode;
|
||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.ReadContentInputStream;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Image viewer part of the Media View layered pane. Uses JavaFX to display the
|
||||
@@ -113,7 +98,7 @@ public class MediaViewImagePanel extends JPanel implements DataContentViewerMedi
|
||||
.map("."::concat) //NOI18N
|
||||
.collect(Collectors.toList());
|
||||
|
||||
private ReadImageTask readImageTask;
|
||||
private Task<Image> readImageTask;
|
||||
|
||||
/**
|
||||
* Creates new form MediaViewImagePanel
|
||||
@@ -186,36 +171,31 @@ public class MediaViewImagePanel extends JPanel implements DataContentViewerMedi
|
||||
if (readImageTask != null) {
|
||||
readImageTask.cancel();
|
||||
}
|
||||
readImageTask = new ReadImageTask(file);
|
||||
readImageTask.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
|
||||
|
||||
@Override
|
||||
public void handle(WorkerStateEvent event) {
|
||||
//Note that all error conditions are allready logged in readImageTask.succeeded()
|
||||
if (!Case.isCaseOpen()) {
|
||||
/*
|
||||
* handle in-between condition when case is being closed
|
||||
* and an image was previously selected
|
||||
*/
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Image fxImage = readImageTask.get();
|
||||
if (nonNull(fxImage)) {
|
||||
//we have non-null image show it
|
||||
fxImageView.setImage(fxImage);
|
||||
borderpane.setCenter(fxImageView);
|
||||
} else {
|
||||
showErrorNode(file);
|
||||
}
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
showErrorNode(file);
|
||||
}
|
||||
borderpane.setCursor(Cursor.DEFAULT);
|
||||
readImageTask = ImageUtils.newReadImageTask(file);
|
||||
readImageTask.setOnSucceeded((WorkerStateEvent event) -> {
|
||||
//Note that all error conditions are allready logged in readImageTask.succeeded()
|
||||
if (!Case.isCaseOpen()) {
|
||||
/*
|
||||
* handle in-between condition when case is being closed and
|
||||
* an image was previously selected
|
||||
*/
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Image fxImage = readImageTask.get();
|
||||
if (nonNull(fxImage)) {
|
||||
//we have non-null image show it
|
||||
fxImageView.setImage(fxImage);
|
||||
borderpane.setCenter(fxImageView);
|
||||
} else {
|
||||
showErrorNode(file);
|
||||
}
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
showErrorNode(file);
|
||||
}
|
||||
borderpane.setCursor(Cursor.DEFAULT);
|
||||
});
|
||||
readImageTask.setOnFailed(new EventHandler<WorkerStateEvent>() {
|
||||
|
||||
@@ -230,11 +210,7 @@ public class MediaViewImagePanel extends JPanel implements DataContentViewerMedi
|
||||
return;
|
||||
}
|
||||
|
||||
externalViewerButton.setOnAction(actionEvent -> //fx ActionEvent
|
||||
new ExternalViewerAction(Bundle.MediaViewImagePanel_externalViewerButton_text(), new FileNode(file))
|
||||
.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "")) //Swing ActionEvent //NOI18N
|
||||
);
|
||||
borderpane.setCenter(errorNode);
|
||||
showErrorNode(file);
|
||||
borderpane.setCursor(Cursor.DEFAULT);
|
||||
}
|
||||
});
|
||||
@@ -295,136 +271,4 @@ public class MediaViewImagePanel extends JPanel implements DataContentViewerMedi
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
static private class ReadImageTask extends Task<Image> implements IIOReadProgressListener {
|
||||
|
||||
private final AbstractFile file;
|
||||
volatile private BufferedImage bufferedImage = null;
|
||||
|
||||
ReadImageTask(AbstractFile file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NbBundle.Messages({
|
||||
"# {0} - file name",
|
||||
"LoadImageTask.mesageText=Reading image: {0}"})
|
||||
protected Image call() throws Exception {
|
||||
updateMessage(Bundle.LoadImageTask_mesageText(file.getName()));
|
||||
try (InputStream inputStream = new BufferedInputStream(new ReadContentInputStream(file));) {
|
||||
|
||||
if (ImageUtils.isGIF(file)) {
|
||||
//directly read GIF to preserve potential animation,
|
||||
Image image = new Image(new BufferedInputStream(inputStream));
|
||||
if (image.isError() == false) {
|
||||
return image;
|
||||
}
|
||||
//fall through to default iamge reading code if there was an error
|
||||
}
|
||||
|
||||
ImageInputStream input = ImageIO.createImageInputStream(inputStream);
|
||||
if (input == null) {
|
||||
throw new IIOException("Could not create ImageInputStream."); //NOI18N
|
||||
}
|
||||
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
|
||||
|
||||
if (readers.hasNext()) {
|
||||
ImageReader reader = readers.next();
|
||||
reader.addIIOReadProgressListener(this);
|
||||
reader.setInput(input);
|
||||
/*
|
||||
* This is the important part, get or create a ReadParam,
|
||||
* create a destination image to hold the decoded result,
|
||||
* then pass that image with the param.
|
||||
*/
|
||||
ImageReadParam param = reader.getDefaultReadParam();
|
||||
|
||||
bufferedImage = reader.getImageTypes(0).next().createBufferedImage(reader.getWidth(0), reader.getHeight(0));
|
||||
param.setDestination(bufferedImage);
|
||||
try {
|
||||
reader.read(0, param);
|
||||
} catch (IOException iOException) {
|
||||
// Ignore this exception or display a warning or similar, for exceptions happening during decoding
|
||||
logError(iOException);
|
||||
}
|
||||
reader.removeIIOReadProgressListener(this);
|
||||
return SwingFXUtils.toFXImage(bufferedImage, null);
|
||||
} else {
|
||||
throw new IIOException("No ImageReader found for file."); //NOI18N
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void logError(@Nullable Throwable e) {
|
||||
String message = e == null ? "" : "It may be unsupported or corrupt: " + e.getLocalizedMessage(); //NOI18N
|
||||
try {
|
||||
LOGGER.log(Level.WARNING, "Could not read the image: {0}. {1}", new Object[]{file.getUniquePath(), message}); //NOI18N
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
LOGGER.log(Level.WARNING, "Could not read the image: {0}. {1}", new Object[]{file.getName(), message}); //NOI18N
|
||||
LOGGER.log(Level.SEVERE, "Failed to get unique path for file", tskCoreException); //NOI18N
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void failed() {
|
||||
super.failed();
|
||||
logError(getException());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void succeeded() {
|
||||
super.succeeded();
|
||||
try {
|
||||
Image fxImage = get();
|
||||
if (fxImage == null) {
|
||||
logError(null);
|
||||
} else {
|
||||
if (fxImage.isError()) {
|
||||
//if there was somekind of error, log it
|
||||
logError(fxImage.getException());
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
logError(ex.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void imageProgress(ImageReader source, float percentageDone) {
|
||||
//update this task with the progress reported by ImageReader.read
|
||||
updateProgress(percentageDone, 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sequenceStarted(ImageReader source, int minIndex) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sequenceComplete(ImageReader source) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void imageStarted(ImageReader source, int imageIndex) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void imageComplete(ImageReader source) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void thumbnailStarted(ImageReader source, int imageIndex, int thumbnailIndex) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void thumbnailProgress(ImageReader source, float percentageDone) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void thumbnailComplete(ImageReader source) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readAborted(ImageReader source) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,28 +27,37 @@ import com.google.common.io.Files;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import static java.util.Objects.isNull;
|
||||
import static java.util.Objects.nonNull;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.logging.Level;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.embed.swing.SwingFXUtils;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.event.IIOReadProgressListener;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
|
||||
import org.opencv.core.Core;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.corelibs.ScalrWrapper;
|
||||
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
|
||||
@@ -141,8 +150,8 @@ public class ImageUtils {
|
||||
/**
|
||||
* thread that saves generated thumbnails to disk in the background
|
||||
*/
|
||||
private static final Executor imageSaver =
|
||||
Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder()
|
||||
private static final Executor imageSaver
|
||||
= Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder()
|
||||
.namingPattern("icon saver-%d").build());
|
||||
|
||||
public static List<String> getSupportedImageExtensions() {
|
||||
@@ -319,7 +328,7 @@ public class ImageUtils {
|
||||
* @return a thumbnail for the given image or a default one if there was a
|
||||
* problem making a thumbnail.
|
||||
*/
|
||||
public static Image getThumbnail(Content content, int iconSize) {
|
||||
public static BufferedImage getThumbnail(Content content, int iconSize) {
|
||||
if (content instanceof AbstractFile) {
|
||||
AbstractFile file = (AbstractFile) content;
|
||||
// If a thumbnail file is already saved locally
|
||||
@@ -333,7 +342,7 @@ public class ImageUtils {
|
||||
return thumbnail;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOGGER.log(Level.WARNING, "Error while reading image: " + content.getName(), ex); //NON-NLS
|
||||
LOGGER.log(Level.WARNING, "ImageIO had a problem reading thumbnail for image {0}: {1}", new Object[]{content.getName(), ex.getLocalizedMessage()}); //NON-NLS
|
||||
return generateAndSaveThumbnail(file, iconSize, cacheFile);
|
||||
}
|
||||
} else {
|
||||
@@ -490,7 +499,7 @@ public class ImageUtils {
|
||||
*
|
||||
* @return Generated icon or null on error
|
||||
*/
|
||||
private static Image generateAndSaveThumbnail(AbstractFile file, int iconSize, File cacheFile) {
|
||||
private static BufferedImage generateAndSaveThumbnail(AbstractFile file, int iconSize, File cacheFile) {
|
||||
BufferedImage thumbnail = null;
|
||||
try {
|
||||
if (VideoUtils.isVideoThumbnailSupported(file)) {
|
||||
@@ -537,13 +546,15 @@ public class ImageUtils {
|
||||
* there was a problem.
|
||||
*/
|
||||
@Nullable
|
||||
private static BufferedImage generateImageThumbnail(Content content, int iconSize) {
|
||||
private static BufferedImage generateImageThumbnail(AbstractFile content, int iconSize) {
|
||||
|
||||
try (InputStream inputStream = new BufferedInputStream(new ReadContentInputStream(content));) {
|
||||
BufferedImage bi = ImageIO.read(inputStream);
|
||||
try {
|
||||
final ReadImageTask readImageTask = new ReadImageTask(content);
|
||||
|
||||
readImageTask.run();
|
||||
BufferedImage bi = SwingFXUtils.fromFXImage(readImageTask.get(), null);
|
||||
|
||||
if (bi == null) {
|
||||
LOGGER.log(Level.WARNING, "No image reader for file: {0}", content.getName()); //NON-NLS
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
@@ -554,13 +565,191 @@ public class ImageUtils {
|
||||
return ScalrWrapper.cropImage(bi, Math.min(iconSize, bi.getWidth()), Math.min(iconSize, bi.getHeight()));
|
||||
}
|
||||
} catch (OutOfMemoryError e) {
|
||||
LOGGER.log(Level.WARNING, "Could not scale image (too large) " + content.getName(), e); //NON-NLS
|
||||
} catch (EOFException e) {
|
||||
LOGGER.log(Level.WARNING, "Could not load image (EOF) {0}", content.getName()); //NON-NLS
|
||||
LOGGER.log(Level.WARNING, "Could not scale image (too large) " + content.getName() + ": " + e.getLocalizedMessage()); //NON-NLS
|
||||
} catch (Exception e) {
|
||||
LOGGER.log(Level.WARNING, "Could not load image " + content.getName(), e); //NON-NLS
|
||||
LOGGER.log(Level.WARNING, "ImageIO could not load image " + content.getName() + ": " + e.getLocalizedMessage()); //NON-NLS
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static public int getWidth(AbstractFile file) throws IIOException, IOException {
|
||||
|
||||
try (InputStream inputStream = new BufferedInputStream(new ReadContentInputStream(file));) {
|
||||
|
||||
try (ImageInputStream input = ImageIO.createImageInputStream(inputStream)) {
|
||||
if (input == null) {
|
||||
throw new IIOException("Could not create ImageInputStream."); //NOI18N
|
||||
}
|
||||
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
|
||||
|
||||
if (readers.hasNext()) {
|
||||
ImageReader reader = readers.next();
|
||||
reader.setInput(input);
|
||||
return reader.getWidth(0);
|
||||
} else {
|
||||
throw new IIOException("No ImageReader found for file." + file.getName()); //NOI18N
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public int getHeight(AbstractFile file) throws IIOException, IOException {
|
||||
try (InputStream inputStream = new BufferedInputStream(new ReadContentInputStream(file));) {
|
||||
|
||||
try (ImageInputStream input = ImageIO.createImageInputStream(inputStream)) {
|
||||
if (input == null) {
|
||||
throw new IIOException("Could not create ImageInputStream."); //NOI18N
|
||||
}
|
||||
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
|
||||
|
||||
if (readers.hasNext()) {
|
||||
ImageReader reader = readers.next();
|
||||
reader.setInput(input);
|
||||
|
||||
return reader.getHeight(0);
|
||||
} else {
|
||||
throw new IIOException("No ImageReader found for file." + file.getName()); //NOI18N
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static Task<javafx.scene.image.Image> newReadImageTask(AbstractFile file) {
|
||||
return new ReadImageTask(file);
|
||||
}
|
||||
|
||||
static private class ReadImageTask extends Task<javafx.scene.image.Image> implements IIOReadProgressListener {
|
||||
|
||||
private final AbstractFile file;
|
||||
volatile private BufferedImage bufferedImage = null;
|
||||
|
||||
ReadImageTask(AbstractFile file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NbBundle.Messages({
|
||||
"# {0} - file name",
|
||||
"LoadImageTask.mesageText=Reading image: {0}"})
|
||||
protected javafx.scene.image.Image call() throws Exception {
|
||||
updateMessage(Bundle.LoadImageTask_mesageText(file.getName()));
|
||||
try (InputStream inputStream = new BufferedInputStream(new ReadContentInputStream(file));) {
|
||||
|
||||
if (ImageUtils.isGIF(file)) {
|
||||
//directly read GIF to preserve potential animation,
|
||||
javafx.scene.image.Image image = new javafx.scene.image.Image(new BufferedInputStream(inputStream));
|
||||
if (image.isError() == false) {
|
||||
return image;
|
||||
}
|
||||
//fall through to default iamge reading code if there was an error
|
||||
}
|
||||
|
||||
try (ImageInputStream input = ImageIO.createImageInputStream(inputStream)) {
|
||||
if (input == null) {
|
||||
throw new IIOException("Could not create ImageInputStream."); //NOI18N
|
||||
}
|
||||
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
|
||||
|
||||
if (readers.hasNext()) {
|
||||
ImageReader reader = readers.next();
|
||||
reader.addIIOReadProgressListener(this);
|
||||
reader.setInput(input);
|
||||
/*
|
||||
* This is the important part, get or create a
|
||||
* ReadParam, create a destination image to hold the
|
||||
* decoded result, then pass that image with the param.
|
||||
*/
|
||||
ImageReadParam param = reader.getDefaultReadParam();
|
||||
|
||||
bufferedImage = reader.getImageTypes(0).next().createBufferedImage(reader.getWidth(0), reader.getHeight(0));
|
||||
param.setDestination(bufferedImage);
|
||||
try {
|
||||
reader.read(0, param);
|
||||
} catch (IOException iOException) {
|
||||
// Ignore this exception or display a warning or similar, for exceptions happening during decoding
|
||||
logError(iOException);
|
||||
}
|
||||
reader.removeIIOReadProgressListener(this);
|
||||
return SwingFXUtils.toFXImage(bufferedImage, null);
|
||||
} else {
|
||||
throw new IIOException("No ImageReader found for file."); //NOI18N
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void logError(@Nullable Throwable e) {
|
||||
String message = e == null ? "" : "It may be unsupported or corrupt: " + e.getLocalizedMessage(); //NOI18N
|
||||
try {
|
||||
LOGGER.log(Level.WARNING, "Could not read the image: {0}. {1}", new Object[]{file.getUniquePath(), message}); //NOI18N
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
LOGGER.log(Level.WARNING, "Could not read the image: {0}. {1}", new Object[]{file.getName(), message}); //NOI18N
|
||||
LOGGER.log(Level.SEVERE, "Failed to get unique path for file", tskCoreException); //NOI18N
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void failed() {
|
||||
super.failed();
|
||||
logError(getException());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void succeeded() {
|
||||
super.succeeded();
|
||||
try {
|
||||
javafx.scene.image.Image fxImage = get();
|
||||
if (fxImage == null) {
|
||||
logError(null);
|
||||
} else {
|
||||
if (fxImage.isError()) {
|
||||
//if there was somekind of error, log it
|
||||
logError(fxImage.getException());
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
logError(ex.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void imageProgress(ImageReader source, float percentageDone) {
|
||||
//update this task with the progress reported by ImageReader.read
|
||||
updateProgress(percentageDone, 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void imageStarted(ImageReader source, int imageIndex) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void imageComplete(ImageReader source) {
|
||||
updateProgress(100, 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sequenceStarted(ImageReader source, int minIndex) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sequenceComplete(ImageReader source) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void thumbnailStarted(ImageReader source, int imageIndex, int thumbnailIndex) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void thumbnailProgress(ImageReader source, float percentageDone) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void thumbnailComplete(ImageReader source) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readAborted(ImageReader source) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,6 +391,7 @@ public class DetailViewPane extends AbstractVisualizationPane<DateTime, EventStr
|
||||
"DetailViewPane.loggedTask.queryDb=Retreiving event data",
|
||||
"DetailViewPane.loggedTask.name=Updating Details View",
|
||||
"DetailViewPane.loggedTask.updateUI=Populating visualization",
|
||||
"# {0} - the numner of events",
|
||||
"DetailViewPane.loggedTask.prompt=You are about to show details for {0} events. This might be very slow or even crash Autopsy.\n\nDo you want to continue?"})
|
||||
private class DetailsUpdateTask extends VisualizationUpdateTask<Interval> {
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ import java.net.MalformedURLException;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.embed.swing.SwingFXUtils;
|
||||
@@ -99,7 +98,7 @@ public enum ThumbnailCache {
|
||||
try {
|
||||
return cache.get(file.getId(), () -> load(file)).orElse(null);
|
||||
} catch (UncheckedExecutionException | CacheLoader.InvalidCacheLoadException | ExecutionException ex) {
|
||||
LOGGER.log(Level.WARNING, "failed to load icon for file: " + file.getName(), ex.getCause());
|
||||
LOGGER.log(Level.WARNING, "Failed to load thumbnail for file: " + file.getName(), ex.getCause());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -109,7 +108,7 @@ public enum ThumbnailCache {
|
||||
try {
|
||||
return get(ImageGalleryController.getDefault().getFileFromId(fileID));
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.WARNING, "failed to load icon for file id : " + fileID, ex.getCause());
|
||||
LOGGER.log(Level.WARNING, "Failed to load thumbnail for file: " + fileID, ex.getCause());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -130,27 +129,24 @@ public enum ThumbnailCache {
|
||||
return Optional.of(new Image(new BufferedInputStream(new ReadContentInputStream(file.getAbstractFile())), MAX_THUMBNAIL_SIZE, MAX_THUMBNAIL_SIZE, true, true));
|
||||
}
|
||||
|
||||
BufferedImage thumbnail = getCacheFile(file).map(new Function<File, BufferedImage>() {
|
||||
@Override
|
||||
public BufferedImage apply(File cachFile) {
|
||||
if (cachFile.exists()) {
|
||||
// If a thumbnail file is already saved locally, load it
|
||||
try {
|
||||
BufferedImage cachedThumbnail = ImageIO.read(cachFile);
|
||||
BufferedImage thumbnail = getCacheFile(file).map((File cachFile) -> {
|
||||
if (cachFile.exists()) {
|
||||
// If a thumbnail file is already saved locally, load it
|
||||
try {
|
||||
BufferedImage cachedThumbnail = ImageIO.read(cachFile);
|
||||
|
||||
if (cachedThumbnail.getWidth() < MAX_THUMBNAIL_SIZE) {
|
||||
return cachedThumbnail;
|
||||
}
|
||||
} catch (MalformedURLException ex) {
|
||||
LOGGER.log(Level.WARNING, "Unable to parse cache file path: " + cachFile.getPath(), ex);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.WARNING, "Unable to read cache file " + cachFile.getPath(), ex);
|
||||
if (cachedThumbnail.getWidth() < MAX_THUMBNAIL_SIZE) {
|
||||
return cachedThumbnail;
|
||||
}
|
||||
} catch (MalformedURLException ex) {
|
||||
LOGGER.log(Level.WARNING, "Unable to parse cache file path: " + cachFile.getPath(), ex);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.WARNING, "Unable to read cache file " + cachFile.getPath(), ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}).orElseGet(() -> {
|
||||
return (BufferedImage) ImageUtils.getThumbnail(file.getAbstractFile(), MAX_THUMBNAIL_SIZE);
|
||||
return ImageUtils.getThumbnail(file.getAbstractFile(), MAX_THUMBNAIL_SIZE);
|
||||
});
|
||||
|
||||
WritableImage jfxthumbnail;
|
||||
@@ -176,7 +172,7 @@ public enum ThumbnailCache {
|
||||
try {
|
||||
return Optional.of(ImageUtils.getCachedThumbnailFile(file.getAbstractFile(), MAX_THUMBNAIL_SIZE));
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
} catch (Exception e) {
|
||||
LOGGER.log(Level.WARNING, "Failed to create cache file.{0}", e.getLocalizedMessage());
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2015 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.imagegallery.actions;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.controlsfx.control.action.Action;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.datamodel.FileNode;
|
||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
|
||||
/**
|
||||
* Wraps {@link ExternalViewerAction} in a ControlsFX {@link Action} with
|
||||
* appropriate text and graphic
|
||||
*/
|
||||
@NbBundle.Messages({"MediaViewImagePanel.externalViewerButton.text=Open in External Viewer"})
|
||||
public class OpenExternalViewerAction extends Action {
|
||||
|
||||
private static final Image EXTERNAL = new Image(OpenExternalViewerAction.class.getResource("/org/sleuthkit/autopsy/imagegallery/images/external.png").toExternalForm());
|
||||
private static final ActionEvent ACTION_EVENT = new ActionEvent(OpenExternalViewerAction.class, ActionEvent.ACTION_PERFORMED, ""); //Swing ActionEvent //NOI18N
|
||||
|
||||
public OpenExternalViewerAction(AbstractFile file) {
|
||||
super("External Viewer");
|
||||
|
||||
/**
|
||||
* TODO: why is the name passed to the action? it means we duplicate
|
||||
* this string all over the place -jm
|
||||
*/
|
||||
ExternalViewerAction externalViewerAction = new ExternalViewerAction(Bundle.MediaViewImagePanel_externalViewerButton_text(), new FileNode(file));
|
||||
|
||||
setLongText(Bundle.MediaViewImagePanel_externalViewerButton_text());
|
||||
setEventHandler(actionEvent -> //fx ActionEvent
|
||||
SwingUtilities.invokeLater(() -> externalViewerAction.actionPerformed(ACTION_EVENT))
|
||||
);
|
||||
setGraphic(new ImageView(EXTERNAL));
|
||||
}
|
||||
}
|
||||
@@ -25,10 +25,12 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.util.Pair;
|
||||
import javax.annotation.Nonnull;
|
||||
@@ -91,12 +93,36 @@ public abstract class DrawableFile<T extends AbstractFile> extends AbstractFile
|
||||
private String model;
|
||||
|
||||
protected DrawableFile(T file, Boolean analyzed) {
|
||||
/* @TODO: the two 'new Integer(0).shortValue()' values and null are
|
||||
/*
|
||||
* @TODO: the two 'new Integer(0).shortValue()' values and null are
|
||||
* placeholders because the super constructor expects values i can't get
|
||||
* easily at the moment. I assume this is related to why
|
||||
* ReadContentInputStream can't read from DrawableFiles. */
|
||||
* ReadContentInputStream can't read from DrawableFiles.
|
||||
*/
|
||||
|
||||
super(file.getSleuthkitCase(), file.getId(), file.getAttrType(), file.getAttrId(), file.getName(), file.getType(), file.getMetaAddr(), (int) file.getMetaSeq(), file.getDirType(), file.getMetaType(), null, new Integer(0).shortValue(), file.getSize(), file.getCtime(), file.getCrtime(), file.getAtime(), file.getMtime(), new Integer(0).shortValue(), file.getUid(), file.getGid(), file.getMd5Hash(), file.getKnown(), file.getParentPath());
|
||||
super(file.getSleuthkitCase(),
|
||||
file.getId(),
|
||||
file.getAttrType(),
|
||||
file.getAttrId(),
|
||||
file.getName(),
|
||||
file.getType(),
|
||||
file.getMetaAddr(),
|
||||
(int) file.getMetaSeq(),
|
||||
file.getDirType(),
|
||||
file.getMetaType(),
|
||||
null,
|
||||
new Integer(0).shortValue(),
|
||||
file.getSize(),
|
||||
file.getCtime(),
|
||||
file.getCrtime(),
|
||||
file.getAtime(),
|
||||
file.getMtime(),
|
||||
new Integer(0).shortValue(),
|
||||
file.getUid(),
|
||||
file.getGid(),
|
||||
file.getMd5Hash(),
|
||||
file.getKnown(),
|
||||
file.getParentPath());
|
||||
this.analyzed = new SimpleBooleanProperty(analyzed);
|
||||
this.file = file;
|
||||
}
|
||||
@@ -213,7 +239,9 @@ public abstract class DrawableFile<T extends AbstractFile> extends AbstractFile
|
||||
return category;
|
||||
}
|
||||
|
||||
/** set the category property to the most severe one found */
|
||||
/**
|
||||
* set the category property to the most severe one found
|
||||
*/
|
||||
private void updateCategory() {
|
||||
try {
|
||||
category.set(getSleuthkitCase().getContentTagsByContent(this).stream()
|
||||
@@ -224,7 +252,7 @@ public abstract class DrawableFile<T extends AbstractFile> extends AbstractFile
|
||||
.orElse(Category.ZERO)
|
||||
);
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.WARNING, "problem looking up category for file " + this.getName(), ex);
|
||||
LOGGER.log(Level.WARNING, "problem looking up category for file " + this.getName() + ex.getLocalizedMessage());
|
||||
} catch (IllegalStateException ex) {
|
||||
// We get here many times if the case is closed during ingest, so don't print out a ton of warnings.
|
||||
}
|
||||
@@ -234,7 +262,17 @@ public abstract class DrawableFile<T extends AbstractFile> extends AbstractFile
|
||||
return ThumbnailCache.getDefault().get(this);
|
||||
}
|
||||
|
||||
public abstract Image getFullSizeImage();
|
||||
@Deprecated
|
||||
|
||||
public Image getFullSizeImage() {
|
||||
try {
|
||||
return getReadFullSizeImageTask().get();
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract Task<Image> getReadFullSizeImageTask();
|
||||
|
||||
public void setAnalyzed(Boolean analyzed) {
|
||||
this.analyzed.set(analyzed);
|
||||
|
||||
@@ -18,17 +18,17 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.imagegallery.datamodel;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import javafx.embed.swing.SwingFXUtils;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.scene.image.Image;
|
||||
import javax.imageio.ImageIO;
|
||||
import org.sleuthkit.autopsy.coreutils.ImageUtils;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.imagegallery.FileTypeUtils;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.ReadContentInputStream;
|
||||
|
||||
/**
|
||||
* ImageGallery data model object that represents an image file. It is a
|
||||
@@ -49,43 +49,53 @@ public class ImageFile<T extends AbstractFile> extends DrawableFile<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getFullSizeImage() {
|
||||
public Task<Image> getReadFullSizeImageTask() {
|
||||
Image image = (imageRef != null) ? imageRef.get() : null;
|
||||
if (image == null || image.isError()) {
|
||||
if (FileTypeUtils.isGIF(getAbstractFile())) {
|
||||
//directly read gif to preserve potential animation,
|
||||
image = new Image(new BufferedInputStream(new ReadContentInputStream(getAbstractFile())));
|
||||
}
|
||||
final Task<Image> newReadImageTask = ImageUtils.newReadImageTask(this.getAbstractFile());
|
||||
newReadImageTask.stateProperty().addListener((Observable observable) -> {
|
||||
switch (newReadImageTask.getState()) {
|
||||
case CANCELLED:
|
||||
break;
|
||||
case FAILED:
|
||||
break;
|
||||
case SUCCEEDED:
|
||||
try {
|
||||
imageRef = new SoftReference<>(newReadImageTask.get());
|
||||
} catch (InterruptedException | ExecutionException interruptedException) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
return newReadImageTask;
|
||||
} else {
|
||||
return new Task<Image>() {
|
||||
@Override
|
||||
protected Image call() throws Exception {
|
||||
return image;
|
||||
}
|
||||
};
|
||||
}
|
||||
if (image == null || image.isError()) {
|
||||
try (BufferedInputStream readContentInputStream = new BufferedInputStream(new ReadContentInputStream(this.getAbstractFile()))) {
|
||||
BufferedImage read = ImageIO.read(readContentInputStream);
|
||||
image = SwingFXUtils.toFXImage(read, null);
|
||||
} catch (Exception ex) {
|
||||
LOGGER.log(Level.WARNING, "unable to read file " + getName(), ex.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
imageRef = new SoftReference<>(image);
|
||||
return image;
|
||||
}
|
||||
|
||||
@Override
|
||||
Double getWidth() {
|
||||
final Image fullSizeImage = getFullSizeImage();
|
||||
if (fullSizeImage != null) {
|
||||
return fullSizeImage.getWidth();
|
||||
try {
|
||||
return (double) ImageUtils.getWidth(this.getAbstractFile());
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.WARNING, "getWidth", ex);
|
||||
return -1.0;
|
||||
}
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
@Override
|
||||
Double getHeight() {
|
||||
final Image fullSizeImage = getFullSizeImage();
|
||||
if (fullSizeImage != null) {
|
||||
return fullSizeImage.getHeight();
|
||||
try {
|
||||
return (double) ImageUtils.getHeight(this.getAbstractFile());
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.WARNING, "getHeight", ex);
|
||||
return -1.0;
|
||||
}
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,7 +25,10 @@ import java.io.IOException;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.embed.swing.SwingFXUtils;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.media.Media;
|
||||
@@ -51,16 +54,43 @@ public class VideoFile<T extends AbstractFile> extends DrawableFile<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getFullSizeImage() {
|
||||
Image image = (null == imageRef) ? null : imageRef.get();
|
||||
public Task<Image> getReadFullSizeImageTask() {
|
||||
Image image = (imageRef != null) ? imageRef.get() : null;
|
||||
if (image == null || image.isError()) {
|
||||
Task<Image> newReadImageTask = new Task<Image>() {
|
||||
|
||||
if (image == null) {
|
||||
final BufferedImage bufferedImage = (BufferedImage) ImageUtils.getThumbnail(getAbstractFile(), 1024);
|
||||
image = (bufferedImage == ImageUtils.getDefaultThumbnail()) ? null : SwingFXUtils.toFXImage(bufferedImage, null);
|
||||
imageRef = new SoftReference<>(image);
|
||||
@Override
|
||||
protected Image call() throws Exception {
|
||||
final BufferedImage bufferedImage = (BufferedImage) ImageUtils.getThumbnail(getAbstractFile(), 1024);
|
||||
return (bufferedImage == ImageUtils.getDefaultThumbnail())
|
||||
? null
|
||||
: SwingFXUtils.toFXImage(bufferedImage, null);
|
||||
}
|
||||
};
|
||||
|
||||
newReadImageTask.stateProperty().addListener((Observable observable) -> {
|
||||
switch (newReadImageTask.getState()) {
|
||||
case CANCELLED:
|
||||
break;
|
||||
case FAILED:
|
||||
break;
|
||||
case SUCCEEDED:
|
||||
try {
|
||||
imageRef = new SoftReference<>(newReadImageTask.get());
|
||||
} catch (InterruptedException | ExecutionException interruptedException) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
return newReadImageTask;
|
||||
} else {
|
||||
return new Task<Image>() {
|
||||
@Override
|
||||
protected Image call() throws Exception {
|
||||
return image;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
private SoftReference<Media> mediaRef;
|
||||
|
||||
+3
-1
@@ -90,7 +90,7 @@ public class DrawableTile extends DrawableTileBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
CachedLoaderTask<Image, DrawableFile<?>> getNewImageLoadTask(DrawableFile<?> file) {
|
||||
CachedLoaderTask<Image, DrawableFile<?>> newReadImageTask(DrawableFile<?> file) {
|
||||
return new ThumbnailLoaderTask(file);
|
||||
}
|
||||
|
||||
@@ -99,4 +99,6 @@ public class DrawableTile extends DrawableTileBase {
|
||||
return getFile().map(AbstractContent::getName).orElse("");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+8
-12
@@ -47,6 +47,7 @@ import javafx.scene.layout.Region;
|
||||
import javafx.scene.paint.Color;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.controlsfx.control.action.ActionUtils;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.actions.Presenter;
|
||||
@@ -58,7 +59,6 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.ContextMenuActionsProvider;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.FileNode;
|
||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.autopsy.imagegallery.FileIDSelectionModel;
|
||||
@@ -67,6 +67,7 @@ import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent;
|
||||
import org.sleuthkit.autopsy.imagegallery.actions.AddDrawableTagAction;
|
||||
import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction;
|
||||
import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction;
|
||||
import org.sleuthkit.autopsy.imagegallery.actions.OpenExternalViewerAction;
|
||||
import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter;
|
||||
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute;
|
||||
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile;
|
||||
@@ -221,15 +222,10 @@ public abstract class DrawableTileBase extends DrawableUIBase {
|
||||
});
|
||||
menuItems.add(contentViewer);
|
||||
|
||||
MenuItem externalViewer = new MenuItem(Bundle.DrawableTileBase_externalViewerAction_text());
|
||||
final ExternalViewerAction externalViewerAction = new ExternalViewerAction(Bundle.DrawableTileBase_externalViewerAction_text(), new FileNode(file.getAbstractFile()));
|
||||
|
||||
externalViewer.setDisable(externalViewerAction.isEnabled() == false);
|
||||
externalViewer.setOnAction((ActionEvent t) -> {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
externalViewerAction.actionPerformed(null);
|
||||
});
|
||||
});
|
||||
OpenExternalViewerAction openExternalViewerAction = new OpenExternalViewerAction(file.getAbstractFile());
|
||||
MenuItem externalViewer = ActionUtils.createMenuItem(openExternalViewerAction);
|
||||
externalViewer.textProperty().unbind();
|
||||
externalViewer.textProperty().bind(openExternalViewerAction.longTextProperty());
|
||||
menuItems.add(externalViewer);
|
||||
|
||||
Collection<? extends ContextMenuActionsProvider> menuProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class);
|
||||
@@ -311,12 +307,12 @@ public abstract class DrawableTileBase extends DrawableUIBase {
|
||||
updateSelectionState();
|
||||
updateCategory();
|
||||
updateFollowUpIcon();
|
||||
updateUI();
|
||||
updateContent();
|
||||
updateMetaData();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateUI() {
|
||||
private void updateMetaData() {
|
||||
getFile().ifPresent(file -> {
|
||||
final boolean isVideo = file.isVideo();
|
||||
final boolean hasHashSetHits = hasHashHit();
|
||||
|
||||
+90
-65
@@ -18,32 +18,46 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.imagegallery.gui.drawableviews;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.Objects;
|
||||
import static java.util.Objects.isNull;
|
||||
import static java.util.Objects.nonNull;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.logging.Level;
|
||||
import javafx.application.Platform;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.concurrent.WorkerStateEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ProgressIndicator;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import org.controlsfx.control.action.ActionUtils;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
|
||||
import org.sleuthkit.autopsy.imagegallery.actions.OpenExternalViewerAction;
|
||||
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@NbBundle.Messages({"MediaViewImagePanel.errorLabel.text=Could not load file."})
|
||||
abstract public class DrawableUIBase extends AnchorPane implements DrawableView {
|
||||
|
||||
static final Executor exec = Executors.newWorkStealingPool();
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(DrawableUIBase.class.getName());
|
||||
|
||||
@FXML
|
||||
@@ -56,9 +70,7 @@ abstract public class DrawableUIBase extends AnchorPane implements DrawableView
|
||||
private Optional<DrawableFile<?>> fileOpt = Optional.empty();
|
||||
|
||||
private Optional<Long> fileIDOpt = Optional.empty();
|
||||
private Task<Image> imageTask;
|
||||
private SoftReference<Image> imageCache;
|
||||
private ProgressIndicator progressIndicator;
|
||||
protected volatile Task<Image> imageTask;
|
||||
|
||||
public DrawableUIBase(ImageGalleryController controller) {
|
||||
this.controller = controller;
|
||||
@@ -107,20 +119,41 @@ abstract public class DrawableUIBase extends AnchorPane implements DrawableView
|
||||
synchronized public void setFile(Long newFileID) {
|
||||
if (getFileID().isPresent()) {
|
||||
if (Objects.equals(newFileID, getFileID().get()) == false) {
|
||||
if (Objects.nonNull(newFileID)) {
|
||||
setFileHelper(newFileID);
|
||||
}
|
||||
// if (Objects.nonNull(newFileID)) {
|
||||
setFileHelper(newFileID);
|
||||
// }
|
||||
}
|
||||
} else if (Objects.nonNull(newFileID)) {
|
||||
} else {//if (Objects.nonNull(newFileID)) {
|
||||
setFileHelper(newFileID);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized protected void updateContent() {
|
||||
Node content = getContentNode();
|
||||
Platform.runLater(() -> {
|
||||
imageBorder.setCenter(content);
|
||||
if (getFile().isPresent() == false) {
|
||||
Platform.runLater(() -> imageBorder.setCenter(null));
|
||||
} else {
|
||||
DrawableFile<?> file = getFile().get();
|
||||
//is an image
|
||||
doReadImageTask(file);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized Node doReadImageTask(DrawableFile<?> file) {
|
||||
disposeContent();
|
||||
final Task<Image> myTask = newReadImageTask(file);
|
||||
imageTask = myTask;
|
||||
Node progressNode = newProgressIndicator(myTask);
|
||||
Platform.runLater(() -> imageBorder.setCenter(progressNode));
|
||||
|
||||
imageTask.setOnSucceeded((WorkerStateEvent event) -> {
|
||||
showImage(file, myTask);//on fx thread already
|
||||
});
|
||||
imageTask.setOnFailed((WorkerStateEvent event) -> {
|
||||
showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file);//on fx thread already
|
||||
});
|
||||
|
||||
exec.execute(myTask);
|
||||
return progressNode;
|
||||
}
|
||||
|
||||
synchronized protected void disposeContent() {
|
||||
@@ -128,50 +161,52 @@ abstract public class DrawableUIBase extends AnchorPane implements DrawableView
|
||||
imageTask.cancel(true);
|
||||
}
|
||||
imageTask = null;
|
||||
imageCache = null;
|
||||
Platform.runLater(() -> imageView.setImage(null));
|
||||
|
||||
}
|
||||
|
||||
ProgressIndicator getLoadingProgressIndicator() {
|
||||
if (progressIndicator == null) {
|
||||
progressIndicator = new ProgressIndicator();
|
||||
}
|
||||
return progressIndicator;
|
||||
/**
|
||||
*
|
||||
* @param file the value of file
|
||||
* @param imageTask the value of imageTask
|
||||
*/
|
||||
Node newProgressIndicator(final Task<?> imageTask) {
|
||||
ProgressIndicator loadingProgressIndicator = new ProgressIndicator(-1);
|
||||
loadingProgressIndicator.progressProperty().bind(imageTask.progressProperty());
|
||||
return loadingProgressIndicator;
|
||||
}
|
||||
|
||||
Node getContentNode() {
|
||||
if (getFile().isPresent() == false) {
|
||||
imageCache = null;
|
||||
Platform.runLater(() -> {
|
||||
if (imageView != null) {
|
||||
imageView.setImage(null);
|
||||
}
|
||||
});
|
||||
return null;
|
||||
} else {
|
||||
Image thumbnail = isNull(imageCache) ? null : imageCache.get();
|
||||
|
||||
if (nonNull(thumbnail)) {
|
||||
Platform.runLater(() -> {
|
||||
if (imageView != null) {
|
||||
imageView.setImage(thumbnail);
|
||||
}
|
||||
});
|
||||
return imageView;
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
void showImage(DrawableFile<?> file, Task<Image> imageTask) {
|
||||
//Note that all error conditions are allready logged in readImageTask.succeeded()
|
||||
try {
|
||||
Image fxImage = imageTask.get();
|
||||
if (nonNull(fxImage)) {
|
||||
//we have non-null image show it
|
||||
imageView.setImage(fxImage);
|
||||
imageBorder.setCenter(imageView);
|
||||
} else {
|
||||
DrawableFile<?> file = getFile().get();
|
||||
|
||||
if (isNull(imageTask)) {
|
||||
imageTask = getNewImageLoadTask(file);
|
||||
new Thread(imageTask).start();
|
||||
} else if (imageTask.isDone()) {
|
||||
return null;
|
||||
}
|
||||
return getLoadingProgressIndicator();
|
||||
showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file);
|
||||
}
|
||||
} catch (CancellationException ex) {
|
||||
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file);
|
||||
}
|
||||
}
|
||||
|
||||
abstract CachedLoaderTask<Image, DrawableFile<?>> getNewImageLoadTask(DrawableFile<?> file);
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
void showErrorNode(String errorMessage, AbstractFile file) {
|
||||
Button createButton = ActionUtils.createButton(new OpenExternalViewerAction(file));
|
||||
|
||||
VBox vBox = new VBox(10,
|
||||
new Label(errorMessage), createButton);
|
||||
|
||||
vBox.setAlignment(Pos.CENTER);
|
||||
imageBorder.setCenter(vBox);
|
||||
}
|
||||
|
||||
abstract Task<Image> newReadImageTask(DrawableFile<?> file);
|
||||
|
||||
abstract class CachedLoaderTask<X, Y extends DrawableFile<?>> extends Task<X> {
|
||||
|
||||
@@ -186,7 +221,7 @@ abstract public class DrawableUIBase extends AnchorPane implements DrawableView
|
||||
return (isCancelled() == false) ? load() : null;
|
||||
}
|
||||
|
||||
abstract X load();
|
||||
abstract X load() throws Exception;
|
||||
|
||||
@Override
|
||||
protected void succeeded() {
|
||||
@@ -194,7 +229,6 @@ abstract public class DrawableUIBase extends AnchorPane implements DrawableView
|
||||
if (isCancelled() == false) {
|
||||
try {
|
||||
saveToCache(get());
|
||||
updateContent();
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
LOGGER.log(Level.WARNING, "Failed to cache content for" + file.getName(), ex);
|
||||
}
|
||||
@@ -210,23 +244,9 @@ abstract public class DrawableUIBase extends AnchorPane implements DrawableView
|
||||
abstract void saveToCache(X result);
|
||||
}
|
||||
|
||||
abstract class ImageLoaderTask extends CachedLoaderTask<Image, DrawableFile<?>> {
|
||||
class ThumbnailLoaderTask extends CachedLoaderTask<Image, DrawableFile<?>> {
|
||||
|
||||
public ImageLoaderTask(DrawableFile<?> file) {
|
||||
super(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
void saveToCache(Image result) {
|
||||
synchronized (DrawableUIBase.this) {
|
||||
imageCache = new SoftReference<>(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ThumbnailLoaderTask extends ImageLoaderTask {
|
||||
|
||||
public ThumbnailLoaderTask(DrawableFile<?> file) {
|
||||
ThumbnailLoaderTask(DrawableFile<?> file) {
|
||||
super(file);
|
||||
}
|
||||
|
||||
@@ -234,5 +254,10 @@ abstract public class DrawableUIBase extends AnchorPane implements DrawableView
|
||||
Image load() {
|
||||
return isCancelled() ? null : file.getThumbnail();
|
||||
}
|
||||
|
||||
@Override
|
||||
void saveToCache(Image result) {
|
||||
// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-11
@@ -27,7 +27,6 @@ import java.util.Objects;
|
||||
import static java.util.Objects.isNull;
|
||||
import static java.util.Objects.nonNull;
|
||||
import java.util.Optional;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
@@ -52,6 +51,7 @@ import javafx.scene.text.Text;
|
||||
import javafx.util.Pair;
|
||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.imagegallery.FXMLConstructor;
|
||||
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
|
||||
import org.sleuthkit.autopsy.imagegallery.datamodel.Category;
|
||||
@@ -166,7 +166,7 @@ public class MetaDataPane extends DrawableUIBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void setFileHelper(Long newFileID) {
|
||||
synchronized protected void setFileHelper(Long newFileID) {
|
||||
setFileIDOpt(Optional.ofNullable(newFileID));
|
||||
if (newFileID == null) {
|
||||
Platform.runLater(() -> {
|
||||
@@ -177,25 +177,24 @@ public class MetaDataPane extends DrawableUIBase {
|
||||
});
|
||||
} else {
|
||||
disposeContent();
|
||||
updateUI();
|
||||
updateAttributesTable();
|
||||
updateCategory();
|
||||
updateContent();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
CachedLoaderTask<Image, DrawableFile<?>> getNewImageLoadTask(DrawableFile<?> file) {
|
||||
CachedLoaderTask<Image, DrawableFile<?>> newReadImageTask(DrawableFile<?> file) {
|
||||
return new ThumbnailLoaderTask(file);
|
||||
}
|
||||
|
||||
public void updateUI() {
|
||||
public void updateAttributesTable() {
|
||||
getFile().ifPresent(file -> {
|
||||
final List<Pair<DrawableAttribute<?>, Collection<?>>> attributesList = file.getAttributesList();
|
||||
Platform.runLater(() -> {
|
||||
tableView.getItems().clear();
|
||||
tableView.getItems().setAll(attributesList);
|
||||
});
|
||||
|
||||
updateCategory();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -204,13 +203,15 @@ public class MetaDataPane extends DrawableUIBase {
|
||||
return imageBorder;
|
||||
}
|
||||
|
||||
/** {@inheritDoc } */
|
||||
/**
|
||||
* {@inheritDoc }
|
||||
*/
|
||||
@Subscribe
|
||||
@Override
|
||||
public void handleCategoryChanged(CategoryManager.CategoryChangeEvent evt) {
|
||||
getFileID().ifPresent(fileID -> {
|
||||
if (evt.getFileIDs().contains(fileID)) {
|
||||
updateUI();
|
||||
updateAttributesTable();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -220,7 +221,7 @@ public class MetaDataPane extends DrawableUIBase {
|
||||
public void handleTagAdded(ContentTagAddedEvent evt) {
|
||||
getFileID().ifPresent((fileID) -> {
|
||||
if (Objects.equals(evt.getAddedTag().getContent().getId(), fileID)) {
|
||||
updateUI();
|
||||
updateAttributesTable();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -229,7 +230,7 @@ public class MetaDataPane extends DrawableUIBase {
|
||||
public void handleTagDeleted(ContentTagDeletedEvent evt) {
|
||||
getFileID().ifPresent((fileID) -> {
|
||||
if (Objects.equals(evt.getDeletedTagInfo().getContentID(), fileID)) {
|
||||
updateUI();
|
||||
updateAttributesTable();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -241,4 +242,5 @@ public class MetaDataPane extends DrawableUIBase {
|
||||
getValueDisplayString(selectedItem)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+93
-46
@@ -23,15 +23,19 @@ import java.lang.ref.SoftReference;
|
||||
import static java.util.Objects.isNull;
|
||||
import static java.util.Objects.nonNull;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.concurrent.WorkerStateEvent;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ProgressBar;
|
||||
import javafx.scene.control.ProgressIndicator;
|
||||
import javafx.scene.image.Image;
|
||||
import static javafx.scene.input.KeyCode.LEFT;
|
||||
import static javafx.scene.input.KeyCode.RIGHT;
|
||||
@@ -40,7 +44,8 @@ import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.media.Media;
|
||||
import javafx.scene.media.MediaException;
|
||||
import javafx.scene.media.MediaPlayer;
|
||||
import javafx.scene.text.Text;
|
||||
import org.controlsfx.control.MaskerPane;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType;
|
||||
@@ -50,7 +55,9 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.Category;
|
||||
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile;
|
||||
import org.sleuthkit.autopsy.imagegallery.datamodel.VideoFile;
|
||||
import org.sleuthkit.autopsy.imagegallery.gui.VideoPlayer;
|
||||
import static org.sleuthkit.autopsy.imagegallery.gui.drawableviews.DrawableUIBase.exec;
|
||||
import static org.sleuthkit.autopsy.imagegallery.gui.drawableviews.DrawableView.CAT_BORDER_WIDTH;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Displays the files of a group one at a time. Designed to be embedded in a
|
||||
@@ -69,7 +76,7 @@ public class SlideShowView extends DrawableTileBase {
|
||||
|
||||
@FXML
|
||||
private BorderPane footer;
|
||||
private Task<Node> mediaTask;
|
||||
|
||||
|
||||
SlideShowView(GroupPane gp, ImageGalleryController controller) {
|
||||
super(gp, controller);
|
||||
@@ -159,42 +166,87 @@ public class SlideShowView extends DrawableTileBase {
|
||||
stopVideo();
|
||||
|
||||
super.disposeContent();
|
||||
if (mediaTask != null) {
|
||||
mediaTask.cancel(true);
|
||||
}
|
||||
mediaTask = null;
|
||||
// if (mediaTask != null) {
|
||||
// mediaTask.cancel(true);
|
||||
// }
|
||||
// mediaTask = null;
|
||||
mediaCache = null;
|
||||
}
|
||||
private SoftReference<Node> mediaCache;
|
||||
|
||||
/**
|
||||
* {@inheritDoc }
|
||||
*/
|
||||
@Override
|
||||
Node getContentNode() {
|
||||
synchronized protected void updateContent() {
|
||||
if (getFile().isPresent() == false) {
|
||||
mediaCache = null;
|
||||
return super.getContentNode();
|
||||
Platform.runLater(() -> imageBorder.setCenter(null));
|
||||
|
||||
} else {
|
||||
DrawableFile<?> file = getFile().get();
|
||||
if (file.isVideo()) {
|
||||
//specially handling for videos
|
||||
Node mediaNode = (isNull(mediaCache)) ? null : mediaCache.get();
|
||||
if (nonNull(mediaNode)) {
|
||||
return mediaNode;
|
||||
Platform.runLater(() -> imageBorder.setCenter(mediaNode));
|
||||
} else {
|
||||
if (isNull(mediaTask)) {
|
||||
mediaTask = new MediaLoadTask(((VideoFile<?>) file));
|
||||
new Thread(mediaTask).start();
|
||||
} else if (mediaTask.isDone()) {
|
||||
return null;
|
||||
}
|
||||
return getLoadingProgressIndicator();
|
||||
// if (isNull(mediaTask)) {
|
||||
MediaLoadTask mediaTask = new MediaLoadTask(((VideoFile<?>) file));
|
||||
Node progressNode = newProgressIndicator(mediaTask);
|
||||
|
||||
mediaTask.setOnSucceeded((WorkerStateEvent event) -> {
|
||||
showMedia(file, mediaTask);//on fx thread already
|
||||
});
|
||||
mediaTask.setOnFailed((WorkerStateEvent event) -> {
|
||||
showErrorNode(getMediaLoadErrorLabel(mediaTask), file);//on fx thread already
|
||||
});
|
||||
Platform.runLater(() -> imageBorder.setCenter(progressNode));
|
||||
exec.execute(mediaTask);
|
||||
// } else {
|
||||
// //not on fx thread;
|
||||
// Platform.runLater(() -> showMedia(file));
|
||||
// }
|
||||
}
|
||||
} else {
|
||||
super.updateContent();
|
||||
}
|
||||
return super.getContentNode();
|
||||
}
|
||||
}
|
||||
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
|
||||
private void showMedia(DrawableFile<?> file, Task<Node> mediaTask) {
|
||||
//Note that all error conditions are allready logged in readImageTask.succeeded()
|
||||
try {
|
||||
Node mediaNode = mediaTask.get();
|
||||
if (nonNull(mediaNode)) {
|
||||
//we have non-null media node show it
|
||||
imageBorder.setCenter(mediaNode);
|
||||
} else {
|
||||
showErrorNode(getMediaLoadErrorLabel(mediaTask), file);
|
||||
}
|
||||
} catch (InterruptedException | ExecutionException ex) {
|
||||
showErrorNode(getMediaLoadErrorLabel(mediaTask), file);
|
||||
}
|
||||
}
|
||||
|
||||
private String getMediaLoadErrorLabel(Task<Node> mediaTask) {
|
||||
return Bundle.MediaViewImagePanel_errorLabel_text() + ": " + mediaTask.getException().getLocalizedMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param file the value of file
|
||||
* @param imageTask the value of imageTask
|
||||
*/
|
||||
@Override
|
||||
Node newProgressIndicator(final Task<?> imageTask) {
|
||||
MaskerPane maskerPane = new MaskerPane();
|
||||
ProgressIndicator loadingProgressIndicator = new ProgressBar(-1);
|
||||
maskerPane.setProgressNode(loadingProgressIndicator);
|
||||
|
||||
maskerPane.textProperty().bind(imageTask.messageProperty());
|
||||
loadingProgressIndicator.progressProperty().bind(imageTask.progressProperty());
|
||||
return maskerPane;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc }
|
||||
*/
|
||||
@@ -250,46 +302,41 @@ public class SlideShowView extends DrawableTileBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
CachedLoaderTask<Image, DrawableFile<?>> getNewImageLoadTask(DrawableFile<?> file) {
|
||||
Task<Image> newReadImageTask(DrawableFile<?> file) {
|
||||
return file.getReadFullSizeImageTask();
|
||||
|
||||
return new ImageLoaderTask(file) {
|
||||
|
||||
@Override
|
||||
Image load() {
|
||||
return isCancelled() ? null : file.getFullSizeImage();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private class MediaLoadTask extends CachedLoaderTask<Node, VideoFile<?>> {
|
||||
@NbBundle.Messages({"# {0} - file name",
|
||||
"MediaLoadTask.messageText=Reading media: {0}"})
|
||||
private class MediaLoadTask extends Task<Node> {
|
||||
|
||||
public MediaLoadTask(VideoFile<?> file) {
|
||||
super(file);
|
||||
private final VideoFile<?> file;
|
||||
|
||||
MediaLoadTask(VideoFile<?> file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
void saveToCache(Node result) {
|
||||
synchronized (SlideShowView.this) {
|
||||
mediaCache = new SoftReference<>(result);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Node load() {
|
||||
protected Node call() throws Exception {
|
||||
updateMessage(Bundle.MediaLoadTask_messageText(file.getName()));
|
||||
try {
|
||||
final Media media = file.getMedia();
|
||||
return new VideoPlayer(new MediaPlayer(media), file);
|
||||
} catch (MediaException | IOException | OutOfMemoryError ex) {
|
||||
Logger.getLogger(VideoFile.class.getName()).log(Level.WARNING, "failed to initialize MediaControl for file " + file.getName(), ex);
|
||||
try {
|
||||
Logger.getLogger(VideoFile.class.getName()).log(Level.WARNING, "Failed to initialize VideoPlayer for file {0} : {1}", new Object[]{file.getUniquePath(), ex.getLocalizedMessage()});
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
Logger.getLogger(VideoFile.class.getName()).log(Level.WARNING, "Failed to get unique path " + file.getName(), tskCoreException);
|
||||
Logger.getLogger(VideoFile.class.getName()).log(Level.WARNING, "Failed to initialize VideoPlayer for file {0} : {1}", new Object[]{file.getName(), ex.getLocalizedMessage()});
|
||||
}
|
||||
|
||||
if (file.isDisplayableAsImage()) {
|
||||
Image fullSizeImage = file.getFullSizeImage();
|
||||
Platform.runLater(() -> {
|
||||
imageView.setImage(fullSizeImage);
|
||||
});
|
||||
return imageView;
|
||||
return doReadImageTask(file);
|
||||
}
|
||||
return new Text(ex.getLocalizedMessage() + "\nSee the logs for details.\n\nTry the \"Open In External Viewer\" action.");
|
||||
|
||||
//if we couldn't even show it as an image. rethrow exception.
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 685 B |
Reference in New Issue
Block a user