diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java index f4b971961a..c34f465589 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/MediaViewImagePanel.java @@ -249,6 +249,16 @@ public class MediaViewImagePanel extends JPanel implements DataContentViewerMedi 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 diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java index d44111a231..bec4a9acbd 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ImageUtils.java @@ -22,6 +22,7 @@ */ package org.sleuthkit.autopsy.coreutils; +import com.google.common.collect.ImmutableSortedSet; import com.google.common.io.Files; import java.awt.Image; import java.awt.image.BufferedImage; @@ -36,6 +37,7 @@ import java.util.Collections; 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.Executor; @@ -76,8 +78,11 @@ public class ImageUtils { private static final Logger logger = LOGGER; private static final BufferedImage DEFAULT_THUMBNAIL; + private static final String IMAGE_GIF_MIME = "image/gif"; + private static final SortedSet GIF_MIME_SET = ImmutableSortedSet.copyOf(new String[]{IMAGE_GIF_MIME}); + private static final List SUPPORTED_IMAGE_EXTENSIONS; - private static final TreeSet SUPPORTED_IMAGE_MIME_TYPES; + private static final SortedSet SUPPORTED_IMAGE_MIME_TYPES; private static final List CONDITIONAL_MIME_TYPES = Arrays.asList("audio/x-aiff", "application/octet-stream"); private static final boolean openCVLoaded; @@ -124,7 +129,7 @@ public class ImageUtils { "image/x-ms-bmp", "image/x-portable-graymap", "image/x-portable-bitmap", - "application/x-123")); + "application/x-123")); //TODO: is this correct? -jm SUPPORTED_IMAGE_MIME_TYPES.removeIf("application/octet-stream"::equals); } @@ -200,6 +205,30 @@ public class ImageUtils { || hasImageFileHeader(file); } + public static boolean isGIF(AbstractFile file) { + try { + final FileTypeDetector fileTypeDetector = getFileTypeDetector(); + if (nonNull(fileTypeDetector)) { + String fileType = fileTypeDetector.getFileType(file); + return IMAGE_GIF_MIME.equalsIgnoreCase(fileType); + } + } catch (TskCoreException | FileTypeDetectorInitException ex) { + LOGGER.log(Level.WARNING, "Failed to get mime type with FileTypeDetector.", ex); + } + LOGGER.log(Level.WARNING, "Falling back on direct mime type check."); + switch (file.isMimeType(GIF_MIME_SET)) { + + case TRUE: + return true; + case UNDEFINED: + LOGGER.log(Level.WARNING, "Falling back on extension check."); + return "gif".equals(file.getNameExtension()); + case FALSE: + default: + return false; + } + } + /** * Check if a file is "supported" by checking it mimetype and extension * diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java index f73d136df5..bddfe6f1e7 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/FileTypeUtils.java @@ -26,7 +26,6 @@ import static java.util.Objects.isNull; import static java.util.Objects.nonNull; import java.util.Optional; import java.util.Set; -import java.util.TreeSet; import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -81,10 +80,6 @@ public enum FileTypeUtils { */ private static FileTypeDetector FILE_TYPE_DETECTOR; - private static final String IMAGE_GIF_MIME = "image/gif"; - - private static final TreeSet GIF_MIME_SET = new TreeSet<>(Arrays.asList(IMAGE_GIF_MIME)); - /** * static initalizer block to initialize sets of extensions and mimetypes to * be supported @@ -161,7 +156,8 @@ public enum FileTypeUtils { return FILE_TYPE_DETECTOR; } - /** is the given file supported by image analyzer? ie, does it have a + /** + * is the given file supported by image analyzer? ie, does it have a * supported mime type (image/*, or video/*). if no mime type is found, does * it have a supported extension or a jpeg/png header? * @@ -181,27 +177,7 @@ public enum FileTypeUtils { } public static boolean isGIF(AbstractFile file) { - try { - final FileTypeDetector fileTypeDetector = getFileTypeDetector(); - if (nonNull(fileTypeDetector)) { - String fileType = fileTypeDetector.getFileType(file); - return IMAGE_GIF_MIME.equalsIgnoreCase(fileType); - } - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Failed to get mime type with FileTypeDetector.", ex); - } - LOGGER.log(Level.WARNING, "Falling back on direct mime type check."); - switch (file.isMimeType(GIF_MIME_SET)) { - - case TRUE: - return true; - case UNDEFINED: - LOGGER.log(Level.WARNING, "Falling back on extension check."); - return "gif".equals(file.getNameExtension()); - case FALSE: - default: - return false; - } + return ImageUtils.isGIF(file); } /** @@ -210,8 +186,8 @@ public enum FileTypeUtils { * @param file * * @return an Optional containg: True if the file has an image or video mime - * type. False if a non image/video mimetype. empty Optional if - * a mimetype could not be detected. + * type. False if a non image/video mimetype. empty Optional if a + * mimetype could not be detected. */ static Optional hasDrawableMimeType(AbstractFile file) throws TskCoreException {