From 4b9ec7958fd93abb9f6732de1d4a38f34d3bd61d Mon Sep 17 00:00:00 2001 From: millmanorama Date: Mon, 21 Dec 2015 09:13:47 -0500 Subject: [PATCH] taskify thumbnail loading --- .../autopsy/coreutils/ImageUtils.java | 173 +++++++++++++++--- .../autopsy/imagegallery/ThumbnailCache.java | 29 ++- .../imagegallery/datamodel/DrawableFile.java | 19 +- .../imagegallery/datamodel/ImageFile.java | 29 +++ .../imagegallery/datamodel/VideoFile.java | 24 +-- .../gui/drawableviews/DrawableTile.fxml | 5 - .../gui/drawableviews/DrawableTile.java | 5 +- .../gui/drawableviews/DrawableTileBase.java | 9 +- .../gui/drawableviews/DrawableUIBase.java | 36 ++-- .../gui/drawableviews/GroupPane.java | 2 - .../gui/drawableviews/MetaDataPane.java | 5 +- .../gui/drawableviews/SlideShowView.fxml | 5 - .../gui/drawableviews/SlideShowView.java | 8 +- 13 files changed, 251 insertions(+), 98 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index c7f98cc061..538d5a30ad 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -44,6 +44,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.logging.Level; +import javafx.beans.Observable; import javafx.concurrent.Task; import javafx.embed.swing.SwingFXUtils; import javax.annotation.Nonnull; @@ -57,6 +58,7 @@ 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.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corelibs.ScalrWrapper; @@ -409,6 +411,7 @@ public class ImageUtils { } /** + * * Get a file object for where the cached icon should exist. The returned * file may not exist. * @@ -615,17 +618,119 @@ public class ImageUtils { } } - public static Task newReadImageTask(AbstractFile file) { - return new ReadImageTask(file); + public static Task newGetThumbnailTask(AbstractFile file, int iconSize) { + return new GetOrGenerateThumbnailTask(file, iconSize); } - static private class ReadImageTask extends Task implements IIOReadProgressListener { + static private class GetOrGenerateThumbnailTask extends ReadImageTaskBase { + + private final int iconSize; + + private GetOrGenerateThumbnailTask(AbstractFile file, int iconSize) { + super(file); + this.iconSize = iconSize; + } + + @Override + protected javafx.scene.image.Image call() throws Exception { + + // If a thumbnail file is already saved locally, just read that. + File cacheFile = getCachedThumbnailLocation(file.getId()); + if (cacheFile.exists()) { + try { + BufferedImage cachedThumbnail = ImageIO.read(cacheFile); + if (nonNull(cachedThumbnail) && cachedThumbnail.getWidth() == iconSize) { + return SwingFXUtils.toFXImage(cachedThumbnail, null); + } + } catch (Exception ex) { + LOGGER.log(Level.WARNING, "ImageIO had a problem reading thumbnail for image {0}: {1}", new Object[]{file.getName(), ex.getMessage()}); //NON-NLS + } + } + + //no cached thumbnail so read the image from the datasource using the ReadImageTask + final ReadImageTask readImageTask = new ReadImageTask(file); + readImageTask.progressProperty().addListener((Observable observable) + -> updateProgress(readImageTask.getWorkDone(), readImageTask.getTotalWork())); + readImageTask.messageProperty().addListener((Observable observable) + -> updateMessage(readImageTask.getMessage())); + readImageTask.run(); + try { + BufferedImage bufferedImage = readImageTask.getBufferedImage(); + if (isNull(bufferedImage)) { + LOGGER.log(Level.WARNING, "Failed to read image for thumbnail generation."); + throw new IIOException("Failed to read image for thumbnail generation."); + } + + updateMessage("scaling image"); + updateProgress(-1, 1); + + BufferedImage thumbnail; + try { + thumbnail = ScalrWrapper.resizeFast(bufferedImage, iconSize); + } catch (IllegalArgumentException | OutOfMemoryError e) { + // if resizing does not work due to extreme aspect ratio, crop the image instead. + try { + LOGGER.log(Level.WARNING, "Could not scale image {0}: {1}.\nAttemptying to crop {0} instead", new Object[]{file.getUniquePath(), e.getLocalizedMessage()}); //NON-NLS + } catch (TskCoreException tskCoreException) { + LOGGER.log(Level.WARNING, "Could not scale image {0}: {1}.\nAttemptying to crop {0} instead", new Object[]{file.getName(), e.getLocalizedMessage()}); //NON-NLS + LOGGER.log(Level.SEVERE, "Failed to get unique path for file: " + file.getName(), tskCoreException); //NOI18N + } + final int cropHeight = Math.min(iconSize, bufferedImage.getHeight()); + final int cropWidth = Math.min(iconSize, bufferedImage.getWidth()); + try { + thumbnail = ScalrWrapper.cropImage(bufferedImage, cropWidth, cropHeight); + } catch (Exception e2) { + LOGGER.log(Level.WARNING, "Could not scale image {0}: {1}", new Object[]{file.getName(), e2.getLocalizedMessage()}); //NON-NLS + throw e2; + } + } catch (Exception e) { + LOGGER.log(Level.WARNING, "Could not scale image {0}: {1}", new Object[]{file.getName(), e.getLocalizedMessage()}); //NON-NLS + throw e; + } + updateProgress(-1, 1); + + saveThumbnail(thumbnail, cacheFile); + return SwingFXUtils.toFXImage(thumbnail, null); + } catch (InterruptedException | ExecutionException e) { +// try { +// LOGGER.log(Level.WARNING, "Could not scale image {0}: {1}.\nAttemptying to crop {0} instead", new Object[]{file.getUniquePath(), e.getLocalizedMessage()}); //NON-NLS +// } catch (TskCoreException tskCoreException) { +// LOGGER.log(Level.WARNING, "Could not scale image {0}: {1}.\nAttemptying to crop {0} instead", new Object[]{file.getName(), e.getLocalizedMessage()}); //NON-NLS +// LOGGER.log(Level.SEVERE, "Failed to get unique path for file: " + file.getName(), tskCoreException); //NOI18N +// } + throw e; + } + + } + + private void saveThumbnail(BufferedImage thumbnail, File cacheFile) { + if (nonNull(thumbnail) && DEFAULT_THUMBNAIL != thumbnail) { + imageSaver.execute(() -> { + try { + Files.createParentDirs(cacheFile); + if (cacheFile.exists()) { + cacheFile.delete(); + } + ImageIO.write(thumbnail, FORMAT, cacheFile); + } catch (IllegalArgumentException | IOException ex1) { + LOGGER.log(Level.WARNING, "Could not write cache thumbnail: " + file.getName(), ex1); //NON-NLS + } + }); + } + } + } + + public static Task newReadImageTask(AbstractFile file) { + return new ReadImageTask(file); + + } + + static private class ReadImageTask extends ReadImageTaskBase { - private final AbstractFile file; volatile private BufferedImage bufferedImage = null; ReadImageTask(AbstractFile file) { - this.file = file; + super(file); } @Override @@ -635,7 +740,6 @@ public class ImageUtils { 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)); @@ -657,8 +761,9 @@ public class ImageUtils { 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, create a destination image to hold + * the decoded result, then pass that image with the + * param. */ ImageReadParam param = reader.getDefaultReadParam(); @@ -679,20 +784,36 @@ public class ImageUtils { } } - 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 - } + public BufferedImage getBufferedImage() throws InterruptedException, ExecutionException { + get(); + return bufferedImage; + } + + } + + static private abstract class ReadImageTaskBase extends Task implements IIOReadProgressListener { + + protected final AbstractFile file; + + public ReadImageTaskBase(AbstractFile file) { + this.file = file; } @Override - protected void failed() { - super.failed(); - logError(getException()); + public void imageProgress(ImageReader source, float percentageDone) { + //update this task with the progress reported by ImageReader.read + updateProgress(percentageDone, 100); + } + + public void logError(@Nullable Throwable e) { + Exceptions.printStackTrace(e); + String message = e == null ? "" : "It may be unsupported or corrupt: " + e.getLocalizedMessage(); //NOI18N + try { + LOGGER.log(Level.WARNING, "ImageIO could not read {0}. {1}", new Object[]{file.getUniquePath(), message}); //NOI18N + } catch (TskCoreException tskCoreException) { + LOGGER.log(Level.WARNING, "ImageIO could not read {0}. {1}", new Object[]{file.getName(), message}); //NOI18N + LOGGER.log(Level.SEVERE, "Failed to get unique path for file: " + file.getName(), tskCoreException); //NOI18N + } } @Override @@ -714,13 +835,9 @@ public class ImageUtils { } @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) { + protected void failed() { + super.failed(); + logError(getException()); } @Override @@ -728,6 +845,10 @@ public class ImageUtils { updateProgress(100, 100); } + @Override + public void imageStarted(ImageReader source, int imageIndex) { + } + @Override public void sequenceStarted(ImageReader source, int minIndex) { } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java index 19551d6f7f..0a7f936b12 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ThumbnailCache.java @@ -31,12 +31,15 @@ import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.logging.Level; +import javafx.beans.Observable; import javafx.beans.property.SimpleIntegerProperty; +import javafx.concurrent.Task; import javafx.embed.swing.SwingFXUtils; import javafx.scene.image.Image; import javafx.scene.image.WritableImage; import javax.annotation.Nullable; import javax.imageio.ImageIO; +import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; @@ -165,7 +168,7 @@ public enum ThumbnailCache { * * @param id the obj id of the file to get a cache file for * - * @return a Optional containing a File to store the cahced icon in or an + * @return a Optional containing a File to store the cached icon in or an * empty optional if there was a problem. */ private static Optional getCacheFile(DrawableFile file) { @@ -177,4 +180,28 @@ public enum ThumbnailCache { return Optional.empty(); } } + + public Task getThumbnailTask(DrawableFile file) { + final Optional option = cache.getIfPresent(file.getId()); + if (option != null && option.isPresent()) { + return new Task() { + @Override + protected Image call() throws Exception { + return option.get(); + } + }; + } + final Task newGetThumbnailTask = ImageUtils.newGetThumbnailTask(file.getAbstractFile(), MAX_THUMBNAIL_SIZE); + newGetThumbnailTask.stateProperty().addListener((Observable observable) -> { + switch (newGetThumbnailTask.getState()) { + case SUCCEEDED: + try { + cache.put(Long.MIN_VALUE, Optional.of(newGetThumbnailTask.get())); + } catch (InterruptedException | ExecutionException ex) { + Exceptions.printStackTrace(ex); + } + } + }); + return newGetThumbnailTask; + } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index f0f3268678..43a313727b 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -23,7 +23,6 @@ import java.util.ArrayList; import java.util.Collection; 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; @@ -39,7 +38,6 @@ import org.apache.commons.lang3.text.WordUtils; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FileTypeUtils; -import org.sleuthkit.autopsy.imagegallery.ThumbnailCache; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -79,6 +77,7 @@ public abstract class DrawableFile extends AbstractFile } SoftReference imageRef; +// SoftReference thumbref; private String drawablePath; @@ -258,12 +257,19 @@ public abstract class DrawableFile extends AbstractFile } } + @Deprecated public Image getThumbnail() { - return ThumbnailCache.getDefault().get(this); + try { + return getThumbnailTask().get(); + } catch (InterruptedException | ExecutionException ex) { + return null; + } + } - @Deprecated + public abstract Task getThumbnailTask(); + @Deprecated //use non-blocking getReadFullSizeImageTask instead for most cases public Image getFullSizeImage() { try { return getReadFullSizeImageTask().get(); @@ -304,11 +310,6 @@ public abstract class DrawableFile extends AbstractFile } } - public boolean isDisplayableAsImage() { - Image thumbnail = getThumbnail(); - return Objects.nonNull(thumbnail) && thumbnail.errorProperty().get() == false; - } - @Nonnull public Set getHashSetNamesUnchecked() { try { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/ImageFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/ImageFile.java index 103561ce32..504922936d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/ImageFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/ImageFile.java @@ -28,6 +28,7 @@ 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.ThumbnailCache; import org.sleuthkit.datamodel.AbstractFile; /** @@ -48,6 +49,34 @@ public class ImageFile extends DrawableFile { } + @Override + public Task getThumbnailTask() { + return ThumbnailCache.getDefault().getThumbnailTask(this); +// newGetThumbTask.stateProperty().addListener((Observable observable) -> { +// switch (newGetThumbTask.getState()) { +// case CANCELLED: +// break; +// case FAILED: +// break; +// case SUCCEEDED: +// try { +// thumbref = new SoftReference<>(newGetThumbTask.get()); +// } catch (InterruptedException | ExecutionException interruptedException) { +// } +// break; +// } +// }); +// return newGetThumbTask; +// } else { +// return new Task() { +// @Override +// protected Image call() throws Exception { +// return thumbnail; +// } +// }; +// } + } + @Override public Task getReadFullSizeImageTask() { Image image = (imageRef != null) ? imageRef.get() : null; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/VideoFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/VideoFile.java index fde2a890f1..3c230383d6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/VideoFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/VideoFile.java @@ -24,9 +24,7 @@ import java.io.File; 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; @@ -36,9 +34,9 @@ import javafx.scene.media.MediaException; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; import org.sleuthkit.autopsy.coreutils.ImageUtils; -import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.VideoUtils; import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.autopsy.imagegallery.ThumbnailCache; import org.sleuthkit.datamodel.AbstractFile; public class VideoFile extends DrawableFile { @@ -53,6 +51,12 @@ public class VideoFile extends DrawableFile { return VIDEO_ICON; } + @Override + public Task getThumbnailTask() { + return ThumbnailCache.getDefault().getThumbnailTask(VideoFile.this); + + } + @Override public Task getReadFullSizeImageTask() { Image image = (imageRef != null) ? imageRef.get() : null; @@ -61,7 +65,7 @@ public class VideoFile extends DrawableFile { @Override protected Image call() throws Exception { - final BufferedImage bufferedImage = (BufferedImage) ImageUtils.getThumbnail(getAbstractFile(), 1024); + final BufferedImage bufferedImage = ImageUtils.getThumbnail(getAbstractFile(), 1024); return (bufferedImage == ImageUtils.getDefaultThumbnail()) ? null : SwingFXUtils.toFXImage(bufferedImage, null); @@ -119,18 +123,6 @@ public class VideoFile extends DrawableFile { } - public boolean isDisplayableAsMedia() { - try { - Media media = getMedia(); - return Objects.nonNull(media) && Objects.isNull(media.getError()); - } catch (IOException ex) { - Logger.getLogger(VideoFile.class.getName()).log(Level.SEVERE, "failed to write video to cache for playback.", ex); - return false; - } catch (MediaException ex) { - return false; - } - } - @Override Double getWidth() { try { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml index 2d6c8304e4..acfcdc1336 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.fxml @@ -34,11 +34,6 @@ - - - - - diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.java index 6018c323c6..ba7c275063 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTile.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import java.util.Objects; import java.util.logging.Level; import javafx.application.Platform; +import javafx.concurrent.Task; import javafx.fxml.FXML; import javafx.scene.CacheHint; import javafx.scene.control.Control; @@ -90,8 +91,8 @@ public class DrawableTile extends DrawableTileBase { } @Override - CachedLoaderTask> newReadImageTask(DrawableFile file) { - return new ThumbnailLoaderTask(file); + Task newReadImageTask(DrawableFile file) { + return file.getThumbnailTask(); } @Override diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java index aa16c22b5e..809f268902 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableTileBase.java @@ -71,7 +71,6 @@ 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; -import org.sleuthkit.autopsy.imagegallery.datamodel.VideoFile; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewMode; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; @@ -112,8 +111,7 @@ public abstract class DrawableTileBase extends DrawableUIBase { @FXML private ImageView hashHitImageView; - @FXML - protected ImageView undisplayableImageView; + /** * displays the icon representing follow up tag */ @@ -316,7 +314,7 @@ public abstract class DrawableTileBase extends DrawableUIBase { getFile().ifPresent(file -> { final boolean isVideo = file.isVideo(); final boolean hasHashSetHits = hasHashHit(); - final boolean isUndisplayable = (isVideo ? ((VideoFile) file).isDisplayableAsMedia() : file.isDisplayableAsImage()) == false; + final String text = getTextForLabel(); Platform.runLater(() -> { @@ -324,8 +322,7 @@ public abstract class DrawableTileBase extends DrawableUIBase { fileTypeImageView.setVisible(isVideo); hashHitImageView.setManaged(hasHashSetHits); hashHitImageView.setVisible(hasHashSetHits); - undisplayableImageView.setManaged(isUndisplayable); - undisplayableImageView.setVisible(isUndisplayable); + nameLabel.setText(text); nameLabel.setTooltip(new Tooltip(text)); }); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java index 8cc42c8306..8b6cde0022 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableUIBase.java @@ -56,7 +56,7 @@ 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(); + static final Executor exec = Executors.newSingleThreadExecutor(); private static final Logger LOGGER = Logger.getLogger(DrawableUIBase.class.getName()); @@ -158,7 +158,7 @@ abstract public class DrawableUIBase extends AnchorPane implements DrawableView synchronized protected void disposeContent() { if (imageTask != null) { - imageTask.cancel(true); + imageTask.cancel(); } imageTask = null; Platform.runLater(() -> imageView.setImage(null)); @@ -244,20 +244,20 @@ abstract public class DrawableUIBase extends AnchorPane implements DrawableView abstract void saveToCache(X result); } - class ThumbnailLoaderTask extends CachedLoaderTask> { - - ThumbnailLoaderTask(DrawableFile file) { - super(file); - } - - @Override - 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. - } - } +// class ThumbnailLoaderTask extends CachedLoaderTask> { +// +// ThumbnailLoaderTask(DrawableFile file) { +// super(file); +// } +// +// @Override +// 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. +// } +// } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index 0f25e60d30..7bc52d4c5d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -774,12 +774,10 @@ public class GroupPane extends BorderPane { @Override protected void updateItem(Long item, boolean empty) { super.updateItem(item, empty); - tile.setFile(item); } void resetItem() { -// updateItem(null, true); tile.setFile(null); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java index cb77dbd8b2..8395b4ab8c 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java @@ -31,6 +31,7 @@ import java.util.stream.Collectors; import javafx.application.Platform; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; +import javafx.concurrent.Task; import javafx.fxml.FXML; import javafx.scene.control.ContextMenu; import javafx.scene.control.Label; @@ -184,8 +185,8 @@ public class MetaDataPane extends DrawableUIBase { } @Override - CachedLoaderTask> newReadImageTask(DrawableFile file) { - return new ThumbnailLoaderTask(file); + Task newReadImageTask(DrawableFile file) { + return file.getThumbnailTask(); } public void updateAttributesTable() { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.fxml b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.fxml index 712f3a953a..d7a631854e 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.fxml +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.fxml @@ -55,11 +55,6 @@ - - - - - diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java index 13539084ca..f97dbae1c6 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java @@ -331,13 +331,9 @@ public class SlideShowView extends DrawableTileBase { 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()) { + return doReadImageTask(file); - } - - //if we couldn't even show it as an image. rethrow exception. - throw ex; - } + } } } }