Autopsy  4.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
MediaViewImagePanel.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2017 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.corecomponents;
20 
21 import java.awt.Dimension;
22 import java.awt.EventQueue;
23 import java.awt.event.ActionEvent;
24 import java.util.Collections;
25 import java.util.List;
26 import static java.util.Objects.nonNull;
27 import java.util.SortedSet;
28 import java.util.concurrent.ExecutionException;
29 import java.util.stream.Collectors;
30 import javafx.application.Platform;
31 import javafx.concurrent.Task;
32 import javafx.embed.swing.JFXPanel;
33 import javafx.geometry.Pos;
34 import javafx.scene.Cursor;
35 import javafx.scene.Scene;
36 import javafx.scene.control.Button;
37 import javafx.scene.control.Label;
38 import javafx.scene.control.ProgressBar;
39 import javafx.scene.image.Image;
40 import javafx.scene.image.ImageView;
41 import javafx.scene.layout.BorderPane;
42 import javafx.scene.layout.VBox;
43 import javax.imageio.ImageIO;
44 import javax.swing.JPanel;
45 import org.controlsfx.control.MaskerPane;
46 import org.openide.util.NbBundle;
47 import org.python.google.common.collect.Lists;
54 
59 @NbBundle.Messages({"MediaViewImagePanel.externalViewerButton.text=Open in External Viewer",
60  "MediaViewImagePanel.errorLabel.text=Could not load file into Media View.",
61  "MediaViewImagePanel.errorLabel.OOMText=Could not load file into Media View: insufficent memory."})
62 public class MediaViewImagePanel extends JPanel implements DataContentViewerMedia.MediaViewPanel {
63 
64  private static final Image EXTERNAL = new Image(MediaViewImagePanel.class.getResource("/org/sleuthkit/autopsy/images/external.png").toExternalForm());
65 
66  private static final Logger LOGGER = Logger.getLogger(MediaViewImagePanel.class.getName());
67 
68  private final boolean fxInited;
69 
70  private JFXPanel fxPanel;
71  private ImageView fxImageView;
72  private BorderPane borderpane;
73  private final ProgressBar progressBar = new ProgressBar();
74  private final MaskerPane maskerPane = new MaskerPane();
75 
76  static {
77  ImageIO.scanForPlugins();
78  }
79 
84  static private final SortedSet<String> supportedMimes = ImageUtils.getSupportedImageMimeTypes();
85 
89  static private final List<String> supportedExtensions = ImageUtils.getSupportedImageExtensions().stream()
90  .map("."::concat) //NOI18N
91  .collect(Collectors.toList());
92 
93  private Task<Image> readImageTask;
94 
99  initComponents();
101  if (fxInited) {
102  Platform.runLater(() -> {
103 
104  // build jfx ui (we could do this in FXML?)
105  fxImageView = new ImageView(); // will hold image
106  borderpane = new BorderPane(fxImageView); // centers and sizes imageview
107  borderpane.getStyleClass().add("bg"); //NOI18N
108  fxPanel = new JFXPanel(); // bridge jfx-swing
109  Scene scene = new Scene(borderpane); //root of jfx tree
110  scene.getStylesheets().add(MediaViewImagePanel.class.getResource("MediaViewImagePanel.css").toExternalForm()); //NOI18N
111  fxPanel.setScene(scene);
112 
113  //bind size of image to that of scene, while keeping proportions
114  fxImageView.fitWidthProperty().bind(scene.widthProperty());
115  fxImageView.fitHeightProperty().bind(scene.heightProperty());
116  fxImageView.setPreserveRatio(true);
117  fxImageView.setSmooth(true);
118  fxImageView.setCache(true);
119 
120  EventQueue.invokeLater(() -> {
121  add(fxPanel);//add jfx ui to JPanel
122  });
123  });
124  }
125  }
126 
127  public boolean isInited() {
128  return fxInited;
129  }
130 
134  public void reset() {
135  Platform.runLater(() -> {
136  fxImageView.setImage(null);
137  borderpane.setCenter(null);
138  });
139  }
140 
141  private void showErrorNode(String errorMessage, AbstractFile file) {
142  final Button externalViewerButton = new Button(Bundle.MediaViewImagePanel_externalViewerButton_text(), new ImageView(EXTERNAL));
143  externalViewerButton.setOnAction(actionEvent
144  -> //fx ActionEvent
145  /*
146  * TODO: why is the name passed into the action constructor? it
147  * means we duplicate this string all over the place -jm
148  */ new ExternalViewerAction(Bundle.MediaViewImagePanel_externalViewerButton_text(), new FileNode(file))
149  .actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "")) //Swing ActionEvent
150  );
151 
152  final VBox errorNode = new VBox(10, new Label(errorMessage), externalViewerButton);
153  errorNode.setAlignment(Pos.CENTER);
154  borderpane.setCenter(errorNode);
155  }
156 
163  void showImageFx(final AbstractFile file, final Dimension dims) {
164  if (!fxInited) {
165  return;
166  }
167 
168  Platform.runLater(() -> {
169  if (readImageTask != null) {
170  readImageTask.cancel();
171  }
172  readImageTask = ImageUtils.newReadImageTask(file);
173  readImageTask.setOnSucceeded(succeeded -> {
174  if (!Case.isCaseOpen()) {
175  /*
176  * Handle the in-between condition when case is being closed
177  * and an image was previously selected
178  *
179  * NOTE: I think this is unnecessary -jm
180  */
181  reset();
182  return;
183  }
184 
185  try {
186  Image fxImage = readImageTask.get();
187  if (nonNull(fxImage)) {
188  //we have non-null image show it
189  fxImageView.setImage(fxImage);
190  borderpane.setCenter(fxImageView);
191  } else {
192  showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file);
193  }
194  } catch (InterruptedException | ExecutionException ex) {
195  showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file);
196  }
197  borderpane.setCursor(Cursor.DEFAULT);
198  });
199  readImageTask.setOnFailed(failed -> {
200  if (!Case.isCaseOpen()) {
201  /*
202  * Handle in-between condition when case is being closed and
203  * an image was previously selected
204  *
205  * NOTE: I think this is unnecessary -jm
206  */
207  reset();
208  return;
209  }
210  Throwable exception = readImageTask.getException();
211  if (exception instanceof OutOfMemoryError
212  && exception.getMessage().contains("Java heap space")) {
213  showErrorNode(Bundle.MediaViewImagePanel_errorLabel_OOMText(), file);
214  } else {
215  showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file);
216  }
217 
218  borderpane.setCursor(Cursor.DEFAULT);
219  });
220 
221  maskerPane.setProgressNode(progressBar);
222  progressBar.progressProperty().bind(readImageTask.progressProperty());
223  maskerPane.textProperty().bind(readImageTask.messageProperty());
224  borderpane.setCenter(maskerPane);
225  borderpane.setCursor(Cursor.WAIT);
226  new Thread(readImageTask).start();
227  });
228  }
229 
233  @Override
234  public List<String> getMimeTypes() {
235  return Collections.unmodifiableList(Lists.newArrayList(supportedMimes));
236  }
237 
243  @Override
244  public List<String> getExtensionsList() {
245  return getExtensions();
246  }
247 
253  public List<String> getExtensions() {
254  return Collections.unmodifiableList(supportedExtensions);
255  }
256 
257  @Override
258  public boolean isSupported(AbstractFile file) {
260  }
261 
267  @SuppressWarnings("unchecked")
268  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
269  private void initComponents() {
270 
271  setBackground(new java.awt.Color(0, 0, 0));
272  setLayout(new javax.swing.BoxLayout(this, javax.swing.BoxLayout.Y_AXIS));
273  }// </editor-fold>//GEN-END:initComponents
274  // Variables declaration - do not modify//GEN-BEGIN:variables
275  // End of variables declaration//GEN-END:variables
276 
277 }
static List< String > getSupportedImageExtensions()
synchronized static Logger getLogger(String name)
Definition: Logger.java:161
static boolean isImageThumbnailSupported(AbstractFile file)
void showErrorNode(String errorMessage, AbstractFile file)
static SortedSet< String > getSupportedImageMimeTypes()

Copyright © 2012-2016 Basis Technology. Generated on: Mon Apr 24 2017
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.