package net.sf.jailer.ui.graphical_view;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.HashSet;
import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import prefuse.Display;
import prefuse.Visualization;
import prefuse.util.GraphicsLib;
import prefuse.util.io.IOLib;
import prefuse.util.io.SimpleFileFilter;
/**
* This class exports a prefuse.Display to a graphics file. The scalefactor will be 1.
*
*
* @version 1.0.0, 07.11.2008
* @author Marcus Ständer (<a href="mailto:webmaster@msdevelopment.org">webmaster@msdevelopment.org</a>)
*/
public class DisplayExporter {
/** The FileChooser to select the file to save to */
protected JFileChooser chooser = null;
//~--- Constructors -------------------------------------------------------
public DisplayExporter() {
}
//~--- Methods ------------------------------------------------------------
/**
* This method initiates the chooser components, detecting available image formats
*
*/
protected void init() {
// Initialize the chooser
chooser = new JFileChooser();
chooser.setDialogType(JFileChooser.SAVE_DIALOG);
chooser.setDialogTitle("Export graph as image");
chooser.setAcceptAllFileFilterUsed(false);
HashSet<String> availableFormats = new HashSet<String>();
String[] fmts = ImageIO.getWriterFormatNames();
for (int i = 0; i < fmts.length; i++) {
String s = fmts[i].toLowerCase();
if ((s.length() == 3) &&!availableFormats.contains(s)) {
availableFormats.add(s);
chooser.setFileFilter(new SimpleFileFilter(s, s.toUpperCase() + " Image (*." + s + ")"));
}
}
availableFormats.clear();
availableFormats = null;
}
/**
* This method lets the user select the target file and exports the <code>Display</code>
*
* @paran display the <code>Display</code> to export
*
*/
public void export(Display display) throws Exception {
// Initialize if needed
if (chooser == null) {
init();
}
// open image save dialog
File f = null;
int returnVal = chooser.showSaveDialog(display);
if (returnVal == JFileChooser.APPROVE_OPTION) {
f = chooser.getSelectedFile();
} else {
return;
}
String format = ((SimpleFileFilter) chooser.getFileFilter()).getExtension();
String ext = IOLib.getExtension(f);
if (!format.equals(ext)) {
f = new File(f.toString() + "." + format);
}
// Now save the image
OutputStream out = new BufferedOutputStream(new FileOutputStream(f));
exportImage(display, out, format);
out.flush();
out.close();
}
private boolean exportImage(Display display, OutputStream output, String format) throws Exception {
String m_group = Visualization.ALL_ITEMS;
try {
display.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// Now comes the nice part
// Get the bounding box
Rectangle2D bounds = display.getVisualization().getBounds(m_group);
// Some little extra spacing
GraphicsLib.expand(bounds, 10 + (int) (1 /* / display.getScale() */));
// Get a buffered image to draw into
BufferedImage img = getNewOffscreenBuffer(display, (int) (bounds.getWidth() * display.getScale()), (int) (bounds.getHeight() * display.getScale()));
Graphics2D g = (Graphics2D)img.getGraphics();
/*
* Set up the display, render, then revert to normal settings
*/
// The zoom point, zooming should not change anything else than the scale
// Point2D zoomPoint = new Point2D.Double(0, 0);
// Get and remember the current scaling
Double scale = display.getScale();
// Change scale to normal (1)
// display.zoom(zoomPoint, 1/scale);
boolean isHighQuality = display.isHighQuality();
display.setHighQuality(true);
// Remember the current point
Point2D currentPoint = new Point2D.Double(display.getDisplayX(), display.getDisplayY());
// Now pan so the most left element is at the left side of the display and
// the highest element is at the top.
display.panToAbs(new Point2D.Double(bounds.getMinX() + display.getWidth()/scale/2,
bounds.getMinY() + display.getHeight()/scale/2));
// Now lets prefuse to the actual painting
display.paintDisplay(g, new Dimension((int) (bounds.getWidth() * scale), (int) (bounds.getHeight() * scale)));
// Undo the panning, zooming and reset the quality mode
display.panToAbs(new Point2D.Double((currentPoint.getX() + display.getWidth()/2)/scale,
(currentPoint.getY() + display.getHeight()/2)/scale));
display.setHighQuality(isHighQuality);
// display.zoom(zoomPoint, scale); // also takes care of damage report
// Save the image and return
ImageIO.write(img, format, output);
return true;
} finally {
display.setCursor(Cursor.getDefaultCursor());
}
}
//~--- Get methods --------------------------------------------------------
// From Display
private BufferedImage getNewOffscreenBuffer(Display display, int width, int height) {
BufferedImage img = null;
if (!GraphicsEnvironment.isHeadless()) {
try {
img = (BufferedImage) display.createImage(width, height);
} catch (Exception e) {
img = null;
}
}
if (img == null) {
return new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
}
return img;
}
}