VLab Issue #5421 - Capture frames with date and time in file name

Change-Id: Ie20956810b46abd3d74a93b993d1a4e134785d29

Former-commit-id: 5b9602defb [formerly 4d3fc8e57e5b5d73599620491e0078a4e7e3bbcc]
Former-commit-id: 786afd6b76
This commit is contained in:
Jordan Gerth 2014-12-12 13:33:09 -06:00
parent 8e574d2475
commit a6e007e1c7
7 changed files with 172 additions and 61 deletions

View file

@ -7,6 +7,7 @@ Bundle-Vendor: RAYTHEON
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy
Require-Bundle: com.raytheon.uf.viz.core;bundle-version="1.14.0",
com.raytheon.viz.core.graphing,
com.raytheon.viz.ui;bundle-version="1.14.0",
gov.noaa.nws.ncep.ui.nsharp,
com.raytheon.uf.common.sounding,

View file

@ -24,9 +24,10 @@ import gov.noaa.nws.ncep.ui.nsharp.display.NsharpEditor;
import gov.noaa.nws.ncep.ui.nsharp.display.rsc.NsharpResourceHandler;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Calendar;
import java.util.LinkedHashMap;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.viz.core.IDisplayPane;
import com.raytheon.uf.viz.core.datastructure.LoopProperties;
import com.raytheon.uf.viz.core.exception.VizException;
@ -40,58 +41,68 @@ import com.raytheon.viz.ui.editor.AbstractEditor;
* SOFTWARE HISTORY
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jul 26, 2006 chammack Initial Creation.
* Unknown bsteffen Initial creation
* Unknown cchen Modifications
* Dec 8, 2014 DR16713 jgerth Incorporate date and time
*
* </pre>
*
* @author chammack
* @author bsteffen
* @version 1
*/
public class NSharpSaveScreenAction extends ExportImageHandler {
@Override
protected BufferedImage captureCurrentFrames(AbstractEditor editor) {
return editor.getActiveDisplayPane().getTarget().screenshot();
protected LinkedHashMap<DataTime, BufferedImage> captureCurrentFrames(AbstractEditor editor) {
NsharpResourceHandler handler = ((NsharpEditor) editor).getRscHandler();
LinkedHashMap<DataTime, BufferedImage> dtbiHash = new LinkedHashMap<DataTime, BufferedImage>();
DataTime[] dataTimes = handler.getSkewtPaneRsc().getDescriptor().getFramesInfo().getFrameTimes();
if (dataTimes == null || dataTimes.length == 0) {
dtbiHash.put(buildFakeTime(0), editor.getActiveDisplayPane().getTarget().screenshot());
} else {
dtbiHash.put(dataTimes[handler.getCurrentIndex()], editor.getActiveDisplayPane().getTarget().screenshot());
}
return dtbiHash;
}
@Override
protected List<BufferedImage> captureAllFrames(AbstractEditor editor)
protected LinkedHashMap<DataTime, BufferedImage> captureAllFrames(AbstractEditor editor)
throws VizException {
if(!(editor instanceof NsharpEditor)){
return super.captureAllFrames(editor);
}
NsharpResourceHandler handler = ((NsharpEditor) editor).getRscHandler();
int startIndex = 0;
int endIndex = handler .getFrameCount(); // Chin NsharpFrameIndexUtil.getFrameCount(handler);
int endIndex = handler.getFrameCount();
return captureFrames(editor, startIndex, endIndex);
}
@Override
protected List<BufferedImage> captureFrames(AbstractEditor editor,
protected LinkedHashMap<DataTime, BufferedImage> captureFrames(AbstractEditor editor,
int startIndex, int endIndex) throws VizException {
if(!(editor instanceof NsharpEditor)){
return super.captureFrames(editor, startIndex, endIndex);
}
LinkedHashMap<DataTime, BufferedImage> dtbiHash = new LinkedHashMap<DataTime, BufferedImage>();
IDisplayPane pane = editor.getActiveDisplayPane();
NsharpResourceHandler handler = ((NsharpEditor) editor).getRscHandler();
// save the frame we are on;
int startingIndex = handler.getCurrentIndex(); // Chin NsharpFrameIndexUtil.getCurrentIndex(handler);
List<BufferedImage> images = new ArrayList<BufferedImage>();
LoopProperties loopProperties = ((AbstractEditor) editor)
.getLoopProperties();
int startingIndex = handler.getCurrentIndex();
LoopProperties loopProperties = ((AbstractEditor) editor).getLoopProperties();
renderPane(pane, loopProperties);
DataTime[] dataTimes = handler.getSkewtPaneRsc().getDescriptor().getFramesInfo().getFrameTimes();
for (int i = startIndex; i < endIndex; i++) {
//Chin NsharpFrameIndexUtil.setCurrentIndex(handler, i);
if(handler.setCurrentIndex(i)== false)
continue;
if (handler.setCurrentIndex(i) == false) {
continue;
}
pane.refresh();
renderPane(pane, loopProperties);
images.add(captureCurrentFrames(editor));
dtbiHash.put(dataTimes[i], editor.getActiveDisplayPane().getTarget().screenshot());
}
handler.setCurrentIndex(startingIndex); // Chin NsharpFrameIndexUtil.setCurrentIndex(handler, startingIndex);
handler.setCurrentIndex(startingIndex);
pane.refresh();
renderPane(pane, loopProperties);
return images;
return dtbiHash;
}
}

View file

@ -39,6 +39,7 @@ import org.eclipse.swt.widgets.Text;
import com.raytheon.uf.common.time.util.TimeUtil;
import com.raytheon.uf.viz.image.export.options.ImageExportOptions;
import com.raytheon.uf.viz.image.export.options.ImageExportOptions.DateTimeSelection;
import com.raytheon.uf.viz.image.export.options.ImageExportOptions.FrameSelection;
import com.raytheon.uf.viz.image.export.options.ImageExportOptions.ImageFormat;
import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
@ -54,6 +55,7 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
* ------------- -------- ----------- --------------------------
* Jan 20, 2014 2312 bsteffen Initial creation
* Mar 10, 2014 2867 bsteffen Better frame range validation.
* Dec 4, 2014 DR16713 jgerth Support for date/time selection
*
* </pre>
*
@ -67,6 +69,8 @@ public class ImageExportDialog extends CaveSWTDialog {
protected Text locationText;
protected Button datetimeButton;
protected Button selectedFramesButton;
protected Button currentFramesButton;
@ -132,6 +136,13 @@ public class ImageExportDialog extends CaveSWTDialog {
selectDestinationFile();
}
});
datetimeButton = new Button(group, SWT.CHECK);
datetimeButton.setLayoutData(gridData);
datetimeButton.setText("Include date and time in file name");
datetimeButton
.setSelection(options.getDateTimeSelection() == DateTimeSelection.DATETIME);
datetimeButton
.setToolTipText("Append the date and time to the file name when Animate is not selected.");
}
protected void initializeFramesGroup(Group group) {
@ -209,6 +220,9 @@ public class ImageExportDialog extends CaveSWTDialog {
frameDelayText.setEnabled(animatedButton.getSelection());
firstFrameDwellText.setEnabled(animatedButton.getSelection());
lastFrameDwellText.setEnabled(animatedButton.getSelection());
datetimeButton.setEnabled(!animatedButton.getSelection());
datetimeButton.setSelection(false);
}
});
gridData = new GridData();
@ -362,6 +376,9 @@ public class ImageExportDialog extends CaveSWTDialog {
} else {
options.setImageFormat(ImageFormat.SEQUENCE);
}
if (datetimeButton.getSelection()) {
options.setDateTimeSelection(DateTimeSelection.DATETIME);
}
if (validate()) {
setReturnValue(options);
close();

View file

@ -20,12 +20,13 @@
package com.raytheon.uf.viz.image.export.handler;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Calendar;
import java.util.LinkedHashMap;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.swt.graphics.Rectangle;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.viz.core.IDisplayPane;
import com.raytheon.uf.viz.core.IDisplayPaneContainer;
import com.raytheon.uf.viz.core.IGraphicsTarget;
@ -53,6 +54,7 @@ import com.raytheon.viz.ui.editor.AbstractEditor;
* Date Ticket# Engineer Description
* ------------- -------- ----------- --------------------------
* Jan 20, 2014 2312 bsteffen Move to image export plugin.
* Dec 4, 2014 DR16713 jgerth Incorporate date and time
*
* </pre>
*
@ -61,11 +63,18 @@ import com.raytheon.viz.ui.editor.AbstractEditor;
*/
public abstract class AbstractImageCaptureHandler extends AbstractHandler {
protected BufferedImage captureCurrentFrames(AbstractEditor editor) {
return editor.screenshot();
protected LinkedHashMap<DataTime, BufferedImage> captureCurrentFrames(AbstractEditor editor) {
LinkedHashMap<DataTime, BufferedImage> dtbiHash = new LinkedHashMap<DataTime, BufferedImage>();
DataTime[] dataTimes = editor.getActiveDisplayPane().getDescriptor().getFramesInfo().getFrameTimes();
if (dataTimes == null || dataTimes.length == 0) {
dtbiHash.put(buildFakeTime(0), editor.screenshot());
} else {
dtbiHash.put(dataTimes[editor.getActiveDisplayPane().getDescriptor().getFramesInfo().getFrameIndex()], editor.screenshot());
}
return dtbiHash;
}
protected List<BufferedImage> captureAllFrames(AbstractEditor editor)
protected LinkedHashMap<DataTime, BufferedImage> captureAllFrames(AbstractEditor editor)
throws VizException {
int startIndex = 0;
int endIndex = editor.getActiveDisplayPane().getDescriptor()
@ -76,28 +85,31 @@ public abstract class AbstractImageCaptureHandler extends AbstractHandler {
return captureFrames(editor, startIndex, endIndex);
}
protected List<BufferedImage> captureFrames(AbstractEditor editor,
protected LinkedHashMap<DataTime, BufferedImage> captureFrames(AbstractEditor editor,
int startIndex, int endIndex) throws VizException {
LinkedHashMap<DataTime, BufferedImage> dtbiHash = new LinkedHashMap<DataTime, BufferedImage>();
if (startIndex < 0) {
startIndex = 0;
}
List<BufferedImage> images = new ArrayList<BufferedImage>(endIndex
- startIndex);
int origIndex = editor.getActiveDisplayPane().getDescriptor()
.getFramesInfo().getFrameIndex();
int origIndex = editor.getActiveDisplayPane().getDescriptor().getFramesInfo().getFrameIndex();
DataTime[] dataTimes = editor.getActiveDisplayPane().getDescriptor().getFramesInfo().getFrameTimes();
for (int i = startIndex; i < endIndex; i++) {
for (IDisplayPane pane : editor.getDisplayPanes()) {
setFrameIndex(pane.getDescriptor(), i);
pane.refresh();
renderPane(pane, editor.getLoopProperties());
}
images.add(editor.screenshot());
if (dataTimes != null && dataTimes.length > 0) {
dtbiHash.put(dataTimes[i], editor.screenshot());
} else {
dtbiHash.put(buildFakeTime(i), editor.screenshot());
}
}
for (IDisplayPane pane : editor.getDisplayPanes()) {
setFrameIndex(pane.getDescriptor(), origIndex);
pane.refresh();
}
return images;
return dtbiHash;
}
private void setFrameIndex(IDescriptor desc, int index) {
@ -136,6 +148,20 @@ public abstract class AbstractImageCaptureHandler extends AbstractHandler {
}
}
/**
* Build a fake time when a time is not associated with a frame. The fake
* time is the number of milliseconds since the Epoch based on the integer
* frame number.
*
* @param the frame number
* @return the fake DataTime based on the frame number
*/
protected DataTime buildFakeTime(int i) {
Calendar c = TimeUtil.newGmtCalendar();
c.setTimeInMillis(i);
return new DataTime(c);
}
@Override
public void setEnabled(Object obj) {
IDisplayPaneContainer container = EditorUtil.getActiveVizContainer();

View file

@ -23,9 +23,15 @@ package com.raytheon.uf.viz.image.export.handler;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
@ -53,9 +59,11 @@ import org.w3c.dom.Node;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.time.DataTime;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.image.export.dialog.ImageExportDialog;
import com.raytheon.uf.viz.image.export.options.ImageExportOptions;
import com.raytheon.uf.viz.image.export.options.ImageExportOptions.DateTimeSelection;
import com.raytheon.uf.viz.image.export.options.ImageExportOptions.FrameSelection;
import com.raytheon.uf.viz.image.export.options.ImageExportOptions.ImageFormat;
import com.raytheon.viz.ui.EditorUtil;
@ -70,6 +78,7 @@ import com.raytheon.viz.ui.editor.AbstractEditor;
* ------------- -------- ----------- --------------------------
* Jul 26, 2006 chammack Initial Creation.
* Jan 20, 2014 2312 bsteffen Move to image export plugin, animation.
* Dec 4, 2014 DR16713 jgerth Support for date and time in file name
*
* </pre>
*
@ -80,6 +89,8 @@ public class ExportImageHandler extends AbstractImageCaptureHandler {
private static final transient IUFStatusHandler statusHandler = UFStatus
.getHandler(ExportImageHandler.class);
private static final String DATE_TIME_FORMAT = "yyyyMMdd_HHmmss";
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
IEditorPart part = EditorUtil.getActiveEditor();
@ -138,17 +149,17 @@ public class ExportImageHandler extends AbstractImageCaptureHandler {
}
}
List<BufferedImage> images = null;
LinkedHashMap<DataTime, BufferedImage> dtbiHash = new LinkedHashMap<DataTime, BufferedImage>();
try {
switch (options.getFrameSelection()) {
case CURRENT:
images = Arrays.asList(captureCurrentFrames(editor));
dtbiHash = captureCurrentFrames(editor);
break;
case ALL:
images = captureAllFrames(editor);
dtbiHash = captureAllFrames(editor);
break;
case USER:
images = captureFrames(editor, options.getFirstFrameIndex(),
dtbiHash = captureFrames(editor, options.getFirstFrameIndex(),
options.getLastFrameIndex());
break;
}
@ -158,8 +169,8 @@ public class ExportImageHandler extends AbstractImageCaptureHandler {
return null;
}
if (!images.isEmpty()) {
new SaveImageJob(options, images);
if (!dtbiHash.isEmpty()) {
new SaveImageJob(options, dtbiHash);
}
return null;
}
@ -175,10 +186,14 @@ public class ExportImageHandler extends AbstractImageCaptureHandler {
}
public void saveImages(IProgressMonitor monitor,
ImageExportOptions options, List<BufferedImage> images) {
monitor.beginTask("Saving Images", images.size());
ImageExportOptions options, Map<DataTime, BufferedImage> dtbiHash) {
monitor.beginTask("Saving Images", dtbiHash.size());
String path = options.getFileLocation().getAbsolutePath();
String ppath = path;
SimpleDateFormat sdf = new SimpleDateFormat(DATE_TIME_FORMAT);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
NumberFormat twoDigit = new DecimalFormat("00");
String suffix = path.substring(path.lastIndexOf('.') + 1);
String basePath = path.substring(0, path.lastIndexOf('.'));
@ -192,33 +207,47 @@ public class ExportImageHandler extends AbstractImageCaptureHandler {
FileImageOutputStream stream = null;
try {
if (images.size() == 1) {
stream = new FileImageOutputStream(options.getFileLocation());
writer.setOutput(stream);
writer.write(images.get(0));
stream.close();
stream = null;
monitor.worked(1);
} else if (options.getImageFormat() == ImageFormat.SEQUENCE) {
for (int i = 0; i < images.size(); i++) {
BufferedImage bi = images.get(i);
/* Allow GC to collect image after write. */
images.set(i, null);
path = basePath + "-" + (i + 1) + "." + suffix;
if (options.getImageFormat() == ImageFormat.SEQUENCE) {
int i = 0;
for (Map.Entry<DataTime, BufferedImage> entry : dtbiHash.entrySet()) {
i++;
BufferedImage bi = entry.getValue();
if (options.getDateTimeSelection() == DateTimeSelection.DATETIME) {
DataTime key = entry.getKey();
Date validTime = key.getValidTimeAsDate();
if (validTime != null && !isFakeTime(key)) {
path = basePath + "-" + sdf.format(validTime) + "." + suffix;
if (path.equals(ppath)) {
path = basePath + "-" + sdf.format(validTime) + "-" + twoDigit.format(i).toString() + "." + suffix;
}
} else {
path = basePath + "-" + twoDigit.format(i).toString() + "." + suffix;
}
} else if (dtbiHash.size() > 1) {
path = basePath + "-" + twoDigit.format(i).toString() + "." + suffix;
} else {
path = basePath + "." + suffix;
}
ppath = path;
stream = new FileImageOutputStream(new File(path));
writer.setOutput(stream);
writer.write(bi);
stream.close();
stream = null;
if (monitor.isCanceled()) {
dtbiHash.clear();
break;
}
monitor.worked(1);
}
dtbiHash.clear();
} else if (options.getImageFormat() == ImageFormat.ANIMATION) {
stream = new FileImageOutputStream(options.getFileLocation());
writer.setOutput(stream);
writer.prepareWriteSequence(null);
List<BufferedImage> images = new ArrayList<BufferedImage>();
images.addAll(dtbiHash.values());
dtbiHash.clear();
for (int i = 0; i < images.size(); i++) {
BufferedImage bi = images.get(i);
/* Allow GC to collect image after write. */
@ -229,14 +258,12 @@ public class ExportImageHandler extends AbstractImageCaptureHandler {
if (i == 0) {
configureAnimation(metadata,
options.getFirstFrameDwell(), true);
} else if (i == images.size() - 1) {
configureAnimation(metadata,
options.getLastFrameDwell(), false);
} else {
configureAnimation(metadata, options.getFrameDelay(),
false);
}
IIOImage ii = new IIOImage(bi, null, metadata);
writer.writeToSequence(ii, null);
@ -313,23 +340,36 @@ public class ExportImageHandler extends AbstractImageCaptureHandler {
}
/**
* There may be cases in which a valid time is not associated with a frame.
* In such cases, a valid time is set to a number of milliseconds from the
* Epoch time based on the frame number. Here we check if that is one of
* those such cases.
*
* @param a DataTime
* @return true if the DataTime is close to the Epoch time
*/
public boolean isFakeTime(DataTime dt) {
return dt.getValidTime().getTimeInMillis() < 1000;
}
protected class SaveImageJob extends Job {
protected final ImageExportOptions options;
protected final List<BufferedImage> images;
protected final LinkedHashMap<DataTime, BufferedImage> dtbiHash;
protected SaveImageJob(ImageExportOptions options,
List<BufferedImage> images) {
LinkedHashMap<DataTime, BufferedImage> dtbiHash) {
super("Saving image");
this.options = options;
this.images = images;
this.dtbiHash = dtbiHash;
this.schedule();
}
@Override
protected IStatus run(IProgressMonitor monitor) {
saveImages(monitor, options, images);
saveImages(monitor, options, dtbiHash);
return Status.OK_STATUS;
}

View file

@ -61,6 +61,7 @@ import com.raytheon.viz.ui.editor.AbstractEditor;
* Aug 08, 2008 703 randerso fixed bug, changed to scale to fit paper
* and rotate if necessary
* Jan 20, 2014 2312 bsteffen Move to image export plugin.
* Dec 4, 2014 DR16713 jgerth Support for date and time in file name
*
* </pre>
*
@ -116,7 +117,7 @@ public class PrintImageCaptureHandler extends AbstractImageCaptureHandler {
switch (pd.getScope()) {
case PrinterData.ALL_PAGES: {
try {
for (BufferedImage bi : captureAllFrames(editor)) {
for (BufferedImage bi : captureAllFrames(editor).values()) {
printImage(printer, display, bi);
}
} catch (VizException e) {
@ -128,7 +129,7 @@ public class PrintImageCaptureHandler extends AbstractImageCaptureHandler {
case PrinterData.PAGE_RANGE: {
try {
for (BufferedImage bi : captureFrames(editor,
pd.getStartPage() - 1, pd.getEndPage())) {
pd.getStartPage() - 1, pd.getEndPage()).values()) {
printImage(printer, display, bi);
}
} catch (VizException e) {

View file

@ -37,6 +37,7 @@ import com.raytheon.uf.viz.core.datastructure.LoopProperties;
* ------------- -------- ----------- --------------------------
* Jan 20, 2014 2312 bsteffen Initial creation
* Mar 10, 2014 2867 bsteffen Better frame range validation.
* Dec 4, 2014 DR16713 jgerth Support for date/time selection
*
* </pre>
*
@ -46,6 +47,10 @@ import com.raytheon.uf.viz.core.datastructure.LoopProperties;
public class ImageExportOptions {
public static enum DateTimeSelection {
DATETIME, SEQUENTIAL;
}
public static enum FrameSelection {
ALL, CURRENT, USER;
}
@ -85,6 +90,8 @@ public class ImageExportOptions {
private FrameSelection frameSelection = FrameSelection.CURRENT;
private DateTimeSelection dateTimeSelection = DateTimeSelection.SEQUENTIAL;
private int firstFrameIndex = 0;
private int lastFrameIndex = 0;
@ -118,6 +125,14 @@ public class ImageExportOptions {
this.imageFormat = imageFormat;
}
public DateTimeSelection getDateTimeSelection() {
return dateTimeSelection;
}
public void setDateTimeSelection(DateTimeSelection dts) {
this.dateTimeSelection = dts;
}
public FrameSelection getFrameSelection() {
return frameSelection;
}