/*************************************************** * * cismet GmbH, Saarbruecken, Germany * * ... and it just works. * ****************************************************/ package de.cismet.cismap.commons.tools; import org.apache.log4j.Logger; import org.openide.util.Cancellable; import org.openide.util.NbBundle; import java.awt.Color; import java.awt.Component; import java.awt.Graphics2D; import java.awt.Image; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.HashSet; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import javax.imageio.ImageIO; import javax.swing.JOptionPane; import de.cismet.cismap.commons.ErroneousRetrievalServiceProvider; import de.cismet.cismap.commons.interaction.CismapBroker; import de.cismet.cismap.commons.retrieval.RetrievalService; import de.cismet.tools.gui.downloadmanager.AbstractDownload; /** * A Download which can be added to the DownloadManager and saves an image from a Future<Image> to a file. If the * image should be saved as jpeg then the transparency of the image gets removed. * * @author Gilles Baatz * @version $Revision$, $Date$ */ public class FutureImageDownload extends AbstractDownload implements Cancellable { //~ Static fields/initializers --------------------------------------------- private static final Logger LOG = Logger.getLogger(FutureImageDownload.class); //~ Instance fields -------------------------------------------------------- String extension; Future<Image> futureImage; int futureImageHash; //~ Constructors ----------------------------------------------------------- /** * Creates a new ImageDownload object. * * @param filename DOCUMENT ME! * @param extension DOCUMENT ME! * @param title DOCUMENT ME! * @param fileToSaveTo DOCUMENT ME! * @param futureImage DOCUMENT ME! */ public FutureImageDownload( final String filename, final String extension, final String title, final File fileToSaveTo, final Future<Image> futureImage) { this.extension = extension; this.futureImage = futureImage; this.futureImageHash = futureImage.hashCode(); this.title = title; status = State.WAITING; this.fileToSaveTo = fileToSaveTo; } //~ Methods ---------------------------------------------------------------- @Override public void run() { if (status != State.WAITING) { releaseMemory(); return; } status = State.RUNNING; stateChanged(); Image image = null; if (futureImage != null) { try { if (!Thread.interrupted()) { image = (Image)futureImage.get(); if (futureImage instanceof ErroneousRetrievalServiceProvider) { final ErroneousRetrievalServiceProvider p = (ErroneousRetrievalServiceProvider)futureImage; final HashSet<RetrievalService> layers = p.getErroneousLayer(); if ((layers != null) && !layers.isEmpty()) { String layersWithErrors = null; for (final RetrievalService service : layers) { if (layersWithErrors == null) { layersWithErrors = service.toString(); } else { layersWithErrors += "\n" + service.toString(); } } final Component parent = CismapBroker.getInstance().getMappingComponent(); JOptionPane.showMessageDialog( parent, NbBundle.getMessage( FutureImageDownload.class, "FutureImageDownload.run().cannotLoadLayer.message", layersWithErrors), NbBundle.getMessage( FutureImageDownload.class, "FutureImageDownload.run().cannotLoadLayer.title"), JOptionPane.WARNING_MESSAGE); } } } else { deleteFile(); } } catch (InterruptedException ex) { deleteFile(); releaseMemory(); return; } catch (ExecutionException ex) { LOG.error("Error while getting the image.", ex); status = State.COMPLETED_WITH_ERROR; stateChanged(); deleteFile(); releaseMemory(); return; } } if ((image != null) && !Thread.interrupted()) { try { ImageIO.write(prepareImage(image), extension, fileToSaveTo); } catch (IOException ex) { LOG.error("Error while saving the image", ex); status = State.COMPLETED_WITH_ERROR; stateChanged(); deleteFile(); releaseMemory(); return; } } else { status = State.COMPLETED_WITH_ERROR; stateChanged(); deleteFile(); releaseMemory(); return; } if (status == State.RUNNING) { status = State.COMPLETED; stateChanged(); } releaseMemory(); } /** * Set the futureImage to null. Otherwise, the FutureImageDownload will take much memory until it is removed from * the DownloadManager. */ private void releaseMemory() { futureImage = null; } /** * DOCUMENT ME! * * @param image DOCUMENT ME! * * @return DOCUMENT ME! */ private BufferedImage prepareImage(final Image image) { if (extension.endsWith("jpg") || extension.endsWith("jpeg")) { return removeTransparency(image); } else if (image instanceof BufferedImage) { return (BufferedImage)image; } else { // Convert the image to a buffered image // Create a buffered image with transparency final BufferedImage bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB); // Draw the image on to the buffered image final Graphics2D bGr = bimage.createGraphics(); bGr.drawImage(image, 0, 0, null); bGr.dispose(); // Return the buffered image return bimage; } } /** * Removes the transparency from an image and returns an opaque image. This method is needed as the image should be * saved as jpg, which is unable to handle transparency. The transparent image is copied to another opaque image * with a white background, which is returned. * * @param transparentImage DOCUMENT ME! * * @return DOCUMENT ME! */ private BufferedImage removeTransparency(final Image transparentImage) { final BufferedImage whiteBackgroundImage = new BufferedImage(transparentImage.getWidth(null), transparentImage.getHeight(null), BufferedImage.TYPE_INT_RGB); Graphics2D g2 = null; try { g2 = whiteBackgroundImage.createGraphics(); g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); g2.setColor(Color.WHITE); g2.fillRect(0, 0, whiteBackgroundImage.getWidth(), whiteBackgroundImage.getHeight()); g2.drawImage( transparentImage, 0, 0, whiteBackgroundImage.getWidth(), whiteBackgroundImage.getHeight(), null); } finally { if (g2 != null) { g2.dispose(); } } return whiteBackgroundImage; } @Override public boolean cancel() { boolean cancelled = true; if (downloadFuture != null) { cancelled = downloadFuture.cancel(true); } if (cancelled) { status = State.ABORTED; stateChanged(); releaseMemory(); } return cancelled; } /** * DOCUMENT ME! */ private void deleteFile() { if (fileToSaveTo.exists() && fileToSaveTo.isFile()) { fileToSaveTo.delete(); } } @Override public int hashCode() { int hash = 3; hash = (37 * hash) + this.futureImageHash; hash = (37 * hash) + ((this.title != null) ? this.title.hashCode() : 0); hash = (37 * hash) + ((this.fileToSaveTo != null) ? this.fileToSaveTo.hashCode() : 0); return hash; } @Override public boolean equals(final Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final FutureImageDownload other = (FutureImageDownload)obj; if (this.futureImageHash != other.futureImageHash) { return false; } if ((this.title == null) ? (other.title != null) : (!this.title.equals(other.title))) { return false; } if ((this.fileToSaveTo != other.fileToSaveTo) && ((this.fileToSaveTo == null) || !this.fileToSaveTo.equals(other.fileToSaveTo))) { return false; } return true; } }