package viewer.hoese; import java.awt.Rectangle; import java.awt.Graphics2D; import java.awt.Color; import java.awt.image.BufferedImage; import java.io.File; import java.util.LinkedList; import java.util.Properties; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import javax.swing.JComponent; import sj.lang.ListExpr; import tools.Reporter; /** * This class implements a Background showing a scalable image. * @author Christian Duentgen * */ public class ImageBackground extends Background { /** * Generated VersionUID for serialization */ private static final long serialVersionUID = -9060443805324796816L; /** * Constructs an undefined Background. */ public ImageBackground() { name = "ImageBackground (no image)"; license = ""; useforbbox = false; listeners = new LinkedList(); } /** * Constructs an ImageBackground by interaction with the user. * * @param parent * The parent component for the used dialog. */ public ImageBackground(JComponent parent) { name = "ImageBackground (no image)"; license = ""; useforbbox = false; listeners = new LinkedList(); showConfigDialog(parent); } /** * Creates an ImageBackground from a nested list and a data path. * * @param l * The nested list to read from. * @param datapath * The directory with the background image file. */ public ImageBackground(ListExpr l, String datapath) { name = "ImageBackground"; license = ""; useforbbox = false; listeners = new LinkedList(); readFromList(l, datapath); } /** * Constructs an ImageBackground from a suitable Properties object. * * @param p * The Properties to restore from. * @param datafilepath * Path of the directory holding the nackground image file. */ public ImageBackground(Properties p, String datafilepath) { name = "ImageBackground"; license = ""; useforbbox = false; listeners = new LinkedList(); setConfiguration(p, datafilepath); } /** * Display a dialog for importing a background image from a file and * locating it to the world (i.e. setting its bounds). Inform all listeners, * if this was successful. * * @see viewer.hoese.Background#showConfigDialog(javax.swing.JComponent) * @param parent * This parameter is ignored. */ @Override public void showConfigDialog(JComponent parent) { if (listeners == null) { listeners = new LinkedList(); } if (bgi == null ) { bgi = new ImageBackgroundDialog(null); } bgi.readFrom(this); bgi.setVisible(true); readFrom(bgi); } /** reads the content of this background from an dialog **/ private void readFrom(ImageBackgroundDialog bgi){ BufferedImage bi = bgi.getImage(); if (bi != null) { img = bi; bbox = bgi.getBBox(); name = "ImageBackground"; license = ""; useforbbox = bgi.useForBoundingBox(); backgroundColor = bgi.getBackgroundColor(); backgroundColorChanged = true; BackgroundChangedEvent evt = new BackgroundChangedEvent() { public Object getSource() { return ImageBackground.this; } }; informListeners(evt); } computeTransform(); } /** * Use the parameter as the new background image * @param img The image to be used as new backgrund */ public void setImage(BufferedImage newimage) { img = newimage; computeTransform(); } /** Returns the currently used image of this background **/ public BufferedImage getImage(){ return img; } /** * Paint method * * @see viewer.hoese.Background#paint(java.awt.Graphics) * @param g * Graphic to which the Background is drawn. */ @Override public void paint(JComponent parent,Graphics2D g, AffineTransform at, Rectangle2D clipRect) { if(parent!=null){ if(backgroundColorChanged){ backgroundColorChanged=false; parent.setBackground(backgroundColor); } } if (img != null) { if(at_img2wc==null){ computeTransform(); } AffineTransform at_img2screen = new AffineTransform(at_img2wc); at_img2screen.preConcatenate(at); //at_img2screen.concatenate(at); g.drawImage(img,at_img2screen, null); } } /** * This might be useful for automatically changing background images, but as * these are not yet implemented, this method has an empty implementation. * * @see viewer.hoese.Background#handleBackgroundDataChangedEvent() */ @Override public void handleBackgroundDataChangedEvent(BackgroundChangedEvent evt) { // empty implementation } /** * Set up the Background with parameters given as a Properties object. Can * be used to restore the Background settings, e.g. from a file. All * registered Listeners are informed. * * @param backgrounddatapath * Path, where data files are stored. * @param p * The Background settings to restore. */ @Override public void setConfiguration(Properties p, String backgrounddatapath) { if (listeners == null) { listeners = new LinkedList(); } super.setConfiguration(p, backgrounddatapath); // TODO restore the image itself from a file stored as a property String filename = p.getProperty(KEY_BGIMAGE); if (filename == null) { // no image stored Reporter.showError("No stored background image available."); return; } // try to open the file if (!backgrounddatapath.endsWith(File.separator)) backgrounddatapath += File.separator; File f = new File(backgrounddatapath + filename); BufferedImage bi = null; if (!f.exists()) { Reporter.showError("Background image \"" + backgrounddatapath + filename + "\" not found."); bi = null; } else { // file exists: read the image try { bi = javax.imageio.ImageIO.read(f); } catch (Exception e) { Reporter.showError("Error while loading the background image."); bi = null; } } if (bi != null) { // assign the image, update bboxes img = bi; } // inform listeners BackgroundChangedEvent evt = new BackgroundChangedEvent() { public Object getSource() { return ImageBackground.this; } }; computeTransform(); informListeners(evt); } public void setConfiguration(BufferedImage img, double x, double y, double w, double h, boolean useForBBox, Color BGColor) { if (listeners == null) { listeners = new LinkedList(); } this.img = img; setBBox(new Rectangle2D.Double(x,y,w,h)); setUseForBoundingBox(useForBBox); setBackgroundColor(BGColor); } /** * Return the Background's settings as a Properties object. The Properties * can be used to save Background settings for later reference. Additional * data may be stored to files rooted at the given path. * * @param backgrounddatapath * Path, where to store data files. * @return The Background's settings as a Properties object. */ @Override public Properties getConfiguration(String backgrounddatapath) { Properties p = super.getConfiguration(backgrounddatapath); // TODO store the image itself to a file and pass the filename as a // property String filename = null; try {// select a non-existent fileName for the image File f = new File(backgrounddatapath); if (!f.exists()) { Reporter.showError("Storing the background image failed:\n" + " directory \"" + backgrounddatapath + "\" doesn't exists"); } else if (!f.isDirectory()) { Reporter.showError("Storing the background image failed:\n\"" + backgrounddatapath + "is not a directory"); } else { if (!backgrounddatapath.endsWith(File.separator)) backgrounddatapath += File.separator; filename = ".background"; int bgnumber = -1; do { bgnumber++; f = new File(backgrounddatapath + filename + bgnumber + ".png"); } while (f.exists()); javax.imageio.ImageIO.write(img, "png", f); filename = filename + bgnumber + ".png"; } } catch (Exception e) { Reporter.showError("Storing the background image failed!"); Reporter.debug(e); filename = null; } if (filename != null) { p.setProperty(KEY_BGIMAGE, filename); } return p; } public String toString(){ return getClass().getName()+"["+super.toString()+", img = "+ img+ ", at_img2wc = " + at_img2wc+"]"; } /** computes the affine transformation to map the image to the current bounding box **/ private void computeTransform(){ if(img==null || bbox == null){ at_img2wc=null; return; } double img_w = img.getWidth(); double img_h = img.getHeight(); if(img_w<=0 || img_h<=0){ at_img2wc=null; return; } double wc_x = bbox.getX(); double wc_y = bbox.getY(); double wc_w = bbox.getWidth(); double wc_h = bbox.getHeight(); if(wc_w<=0 || wc_h <=0){ at_img2wc=null; return; } double scale_x = wc_w/img_w; double scale_y = wc_h/img_h * -1.0; at_img2wc = AffineTransform.getTranslateInstance(wc_x, wc_y + wc_h); at_img2wc.scale(scale_x, scale_y); } /** sets the color outside the image **/ public void setBackgroundColor(Color c){ backgroundColor = c; backgroundColorChanged = true; } /** returns the colors used outside the image **/ public Color getBackgroundColor(){ return backgroundColor; } /** * The image that is used for the background. */ private BufferedImage img = null; /** Dialog for user interaction. **/ private static ImageBackgroundDialog bgi = null; /** Transformation from image to bbox world coordinates*/ private AffineTransform at_img2wc = null; /** Used backgroundcolor outside the image **/ private Color backgroundColor = null; /** flag indicating a changed background color **/ private boolean backgroundColorChanged = true; /** * String constant used as key for the background image within Property */ public static final String KEY_BGIMAGE = "backgroundimage"; }