// // $Id: PictureFileData.java 287 2007-06-17 09:07:04 +0000 (dim., 17 juin 2007) // felfert $ // // jupload - A file upload applet. // Copyright 2007 The JUpload Team // // Created: 2006-05-09 // Creator: etienne_sf // Last modified: $Date: 2010-06-21 10:05:43 -0300 (Seg, 21 Jun 2010) $ // // This program is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software // Foundation; either version 2 of the License, or (at your option) any later // version. This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more // details. You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software Foundation, Inc., // 675 Mass Ave, Cambridge, MA 02139, USA. package wjhk.jupload2.filedata; import java.awt.Canvas; import java.awt.Image; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.metadata.IIOMetadata; import javax.imageio.stream.FileImageInputStream; import javax.swing.ImageIcon; import javax.swing.JOptionPane; import wjhk.jupload2.exception.JUploadException; import wjhk.jupload2.exception.JUploadIOException; import wjhk.jupload2.filedata.helper.ImageHelper; import wjhk.jupload2.filedata.helper.ImageReaderWriterHelper; import wjhk.jupload2.policies.PictureUploadPolicy; import wjhk.jupload2.policies.UploadPolicy; /** * This class contains all data about files to upload as a picture. It adds the * following elements to the {@link wjhk.jupload2.filedata.FileData} class :
* * * @author etienne_sf * @version $Revision: 1355 $ */ public class PictureFileData extends DefaultFileData { /** * Indicates if this file is a picture or not. This is bases on the return * of ImageIO.getImageReadersByFormatName(). */ boolean isPicture = false; /** * This picture is precalculated, and stored to avoid to calculate it each * time the user select this picture again, or each time the use switch from * an application to another. */ Image offscreenImage = null; /** * quarterRotation contains the current rotation that will be applied to the * picture. Its value should be one of 0, 1, 2, 3. It is controled by the * {@link #addRotation(int)} method. * */ int quarterRotation = 0; /** * Width of the original picture. The width is taken from the first image of * the file. We expect that all pictures in a file are of the same size (for * instance, for animated gif). Calculated in the * {@link #PictureFileData(File, File, PictureUploadPolicy)} constructor. */ int originalWidth = -1; /** * Same as {@link #originalWidth}, for the height of the first image in the * picture file. */ int originalHeight = -1; /** * transformedPictureFile contains the reference to the temporary file that * stored the transformed picture, during upload. It is created by * {@link #getInputStream()} and freed by {@link #afterUpload()}. */ File transformedPictureFile = null; /** * uploadLength contains the uploadLength, which is :
* - The size of the original file, if no transformation is needed.
* - The size of the transformed file, if a transformation were made.
*
* It is set to -1 whenever its calculation is to be done again (for * instance, when the user ask for a rotation, which is currently the only * action that need to recalculate the picture). */ long uploadLength = -1; /** * Contains the reference to a copy of the original picture files. * Originally created because a SUN bug would prevent picture to be * correctly resized if the original picture filename contains accents (or * any non-ASCII characters). */ File workingCopyTempFile = null; /** * will be set if in {@link #createTranformedPictureFile(ImageHelper)}, if * an image-transformation has occured */ String targetPictureFormat; /** * Standard constructor: needs a PictureFileDataPolicy. * * @param file * The files which data are to be handled by this instance. * @param root * The root directory, to calculate the relative dir (see * {@link #getRelativeDir()}. * @param uploadPolicy * The current upload policy * @throws JUploadIOException * Encapsulation of the IOException, if any would occurs. */ public PictureFileData(File file, File root, PictureUploadPolicy uploadPolicy) throws JUploadIOException { super(file, root, uploadPolicy); String fileExtension = getFileExtension(); // Is it a picture? this.uploadPolicy.displayDebug("Looking for iterator of extension '" + file + "'", 80); this.isPicture = isFileAPicture(file); // Let's log the test result this.uploadPolicy.displayDebug("isPicture=" + this.isPicture + " (" + file.getName() + "), extension=" + fileExtension, 50); // If it's a picture, we override the default mime type: if (this.isPicture) { setMimeTypeByExtension(fileExtension); } } /** * Free any available memory. This method is called very often here, to be * sure that we don't use too much memory. But we still run out of memory in * some case. * * @param caller * Indicate the method or treatment from which this method is * called. * @param uploadPolicy * The current upload policy is not available, to this static * method... */ public static void freeMemory(String caller, UploadPolicy uploadPolicy) { Runtime rt = Runtime.getRuntime(); rt.runFinalization(); rt.gc(); if (uploadPolicy.getDebugLevel() >= 50) { uploadPolicy.displayDebug("freeMemory (after " + caller + ") : " + rt.freeMemory() + " (maxMemory: " + rt.maxMemory() + ", totalMemory: " + rt.totalMemory() + ")", 50); } } /** * If this pictures needs transformation, a temporary file is created. This * can occurs if the original picture is bigger than the maxWidth or * maxHeight, of if it has to be rotated. This temporary file contains the * transformed picture.
* The call to this method is optional, if the caller calls * {@link #getUploadLength()}. This method calls beforeUpload() if the * uploadLength is unknown. */ @Override public void beforeUpload() throws JUploadException { this.uploadPolicy.displayDebug(this.hashCode() + "|Entering PictureFileData.beforeUpload()", 95); if (!this.preparedForUpload) { if (this.uploadLength < 0) { try { // Picture management is a big work. Let's try to free some // memory. freeMemory( "Picture manabeforeUpload(): before initTransformedPictureFile", this.uploadPolicy); // Get the transformed picture file, if needed. initTransformedPictureFile(); // More debug output, to understand where the applet // freezes. this.uploadPolicy .displayDebug( this.getClass().getName() + ".beforeUpload(): after call to initTransformedPictureFile()", 100); } catch (OutOfMemoryError e) { // Oups ! My EOS 20D has too big pictures to handle more // than // two pictures in a navigator applet !!!!! // :-( // // We don't transform it. We clean the file, if it has been // created. // More debug output, to understand where the applet // freezes. this.uploadPolicy.displayDebug(this.getClass().getName() + ".beforeUpload(): OutOfMemoryError", 30); deleteTransformedPictureFile(); deleteWorkingCopyPictureFile(); // Let's try to free some memory. freeMemory("beforeUpload(): in OutOfMemoryError", this.uploadPolicy); tooBigPicture(); } // If the transformed picture is correctly created, we'll upload // it. // Else we upload the original file. synchronized (this) { if (this.transformedPictureFile != null) { this.uploadLength = this.transformedPictureFile .length(); setMimeTypeByExtension(this.targetPictureFormat); } else { this.uploadLength = getFile().length(); } } } } // Let's check that everything is Ok // More debug output, to understand where the applet freezes. this.uploadPolicy.displayDebug(this.getClass().getName() + ".beforeUpload(): before call to super.beforeUpload()", 100); super.beforeUpload(); // Let's check that everything is Ok // More debug output, to understand where the applet freezes. this.uploadPolicy.displayDebug(this.getClass().getName() + ".beforeUpload(): after call to super.beforeUpload()", 100); } /** * Returns the number of bytes, for this upload. If needed, that is, if * uploadlength is unknown, {@link #beforeUpload()} is called. * * @return The length of upload. In this class, this is ... the size of the * original file, or the transformed file! */ @Override public long getUploadLength() { // Just for debug, to be removed before release. if (!this.preparedForUpload) { throw new IllegalStateException("The file " + getFileName() + " is not prepared for upload"); } return this.uploadLength; } /** * This function create an input stream for this file. The caller is * responsible for closing this input stream.
* This function assumes that the {@link #getUploadLength()} method has * already be called : it is responsible for creating the temporary file (if * needed). If not called, the original file will be sent. * * @return An inputStream */ @Override public synchronized InputStream getInputStream() throws JUploadException { this.uploadPolicy.displayDebug(this.hashCode() + "|Entering PictureFileData.getInputStream()", 95); if (!this.preparedForUpload) { throw new IllegalStateException("The file " + getFileName() + " is not prepared for upload"); } // Do we have to transform the picture ? if (this.transformedPictureFile != null) { try { return new FileInputStream(this.transformedPictureFile); } catch (FileNotFoundException e) { throw new JUploadIOException(e); } } // Otherwise : we read the file, in the standard way. return super.getInputStream(); } /** * Cleaning of the temporary file on the hard drive, if any.
* Note: if the debugLevel is 100 (or more) this temporary file is * not removed. This allow control of this created file. */ @Override public void afterUpload() { // Free the temporary file ... if any. deleteTransformedPictureFile(); deleteWorkingCopyPictureFile(); this.uploadLength = -1; super.afterUpload(); } /** * This method creates a new Image, from the current picture. The resulting * width and height will be less or equal than the given maximum width and * height. The scale is maintained. Thus the width or height may be inferior * than the given values. * * @param canvas * The canvas on which the picture will be displayed. * @param shadow * True if the pictureFileData should store this picture. False * if the pictureFileData instance should not store this picture. * Store this picture avoid calculating the image each time the * user selects it in the file panel. * @return The rescaled image. * @throws JUploadException * Encapsulation of the Exception, if any would occurs. */ public Image getImage(Canvas canvas, boolean shadow) throws JUploadException { Image localImage = null; // //////////////////////////////////////////////////////////////////////// // ////////////// Some preliminary tests. // //////////////////////////////////////////////////////////////////////// if (canvas == null) { throw new JUploadException( "canvas null in PictureFileData.getImage"); } if (shadow && this.offscreenImage != null) { return this.offscreenImage; } int canvasWidth = canvas.getWidth(); int canvasHeight = canvas.getHeight(); if (canvasWidth <= 0 || canvasHeight <= 0) { this.uploadPolicy .displayDebug( "canvas width and/or height null in PictureFileData.getImage()", 1); return null; } if (!this.isPicture) { this.uploadPolicy .displayWarn("canvas width and/or height null in PictureFileData.getImage(). PictureFileData.getImage will return null"); return null; } // //////////////////////////////////////////////////////////////////////// // ////////////// End of preliminary tests: let's work. // //////////////////////////////////////////////////////////////////////// try { // First: load the picture. ImageReaderWriterHelper irwh = new ImageReaderWriterHelper( (PictureUploadPolicy) this.uploadPolicy, this); BufferedImage sourceImage = irwh.readImage(0); irwh.dispose(); irwh = null; ImageHelper ih = new ImageHelper( (PictureUploadPolicy) this.uploadPolicy, this, canvasWidth, canvasHeight, this.quarterRotation); localImage = ih.getBufferedImage( ((PictureUploadPolicy) this.uploadPolicy) .getHighQualityPreview(), sourceImage); // We free memory ASAP. sourceImage.flush(); sourceImage = null; } catch (OutOfMemoryError e) { // Too bad localImage = null; tooBigPicture(); } // We store it, if asked to. if (shadow) { this.offscreenImage = localImage; } freeMemory("end of " + this.getClass().getName() + ".getImage()", this.uploadPolicy); // The picture is now loaded. We clear the progressBar this.uploadPolicy.getContext().getUploadPanel() .getPreparationProgressBar().setValue(0); return localImage; }// getImage /** * This function is used to rotate the picture. The current rotation state * is kept in the quarterRotation private attribute. * * @param quarter * Number of quarters (90 degrees) the picture should rotate. 1 * means rotating of 90 degrees clockwise. Can be negative. */ public void addRotation(int quarter) { this.quarterRotation += quarter; // We'll have to recalculate the upload length, as the resulting file is // different. // If any file has been prepared, they must be deleted deleteWorkingCopyPictureFile(); deleteTransformedPictureFile(); this.uploadLength = -1; // We keep the 'quarter' in the segment [0;4[ while (this.quarterRotation < 0) { this.quarterRotation += 4; } while (this.quarterRotation >= 4) { this.quarterRotation -= 4; } // We need to change the precalculated picture, if any if (this.offscreenImage != null) { this.offscreenImage.flush(); this.offscreenImage = null; } } /** * Indicates if this file is actually a picture or not. * * @return the isPicture flag. */ public boolean isPicture() { return this.isPicture; } /** @see FileData#getMimeType() */ @Override public String getMimeType() { return this.mimeType; } // /////////////////////////////////////////////////////////////////////////////////////////// // /////////////////////////// private METHODS // /////////////////////////////////////////////////////////////////////////////////////////// /** * File.deleteOnExit() is pretty unreliable, especially in applets. * Therefore the applet provides a callback which is executed during applet * termination. This method performs the actual cleanup. */ public synchronized void deleteTransformedPictureFile() { this.uploadPolicy.displayDebug(this.hashCode() + "|Entering PictureFileData.deleteTransformedPictureFile()", 95); // Free the temporary file ... if any. if (null != this.transformedPictureFile && this.uploadPolicy.getDebugLevel() <= 100) { if (!this.transformedPictureFile.delete()) { this.uploadPolicy.displayWarn("Unable to delete " + this.transformedPictureFile.getName()); } this.transformedPictureFile = null; } } /** * Creation of a temporary file, that contains the transformed picture. For * instance, it can be resized or rotated. This method doesn't throw * exception when there is an IOException within its procedure. If an * exception occurs while building the temporary file, the exception is * caught, a warning is displayed, the temporary file is deleted (if it was * created), and the upload will go on with the original file.
* Note: any JUploadException thrown by a method called within * getTransformedPictureFile() will be thrown within this method. */ void initTransformedPictureFile() throws JUploadException { this.uploadPolicy.displayDebug(this.hashCode() + "|Entering PictureFileData.initTransformedPictureFile()", 95); int targetMaxWidth; int targetMaxHeight; // If the image is rotated, we compare to realMaxWidth and // realMaxHeight, instead of maxWidth and maxHeight. This allows // to have a different picture size for rotated and not rotated // pictures. See the UploadPolicy javadoc for details ... and a // good reason ! ;-) if (this.quarterRotation == 0) { targetMaxWidth = ((PictureUploadPolicy) this.uploadPolicy) .getMaxWidth(); targetMaxHeight = ((PictureUploadPolicy) this.uploadPolicy) .getMaxHeight(); } else { targetMaxWidth = ((PictureUploadPolicy) this.uploadPolicy) .getRealMaxWidth(); targetMaxHeight = ((PictureUploadPolicy) this.uploadPolicy) .getRealMaxHeight(); } // Some Helper will .. help us ! // I like useful comment :-) ImageHelper imageHelper = new ImageHelper( (PictureUploadPolicy) this.uploadPolicy, this, targetMaxWidth, targetMaxHeight, this.quarterRotation); // Should transform the file, and do we already created the transformed // file ? synchronized (this) { if (imageHelper.hasToTransformPicture() && this.transformedPictureFile == null) { // We have to create a resized or rotated picture file, and all // needed information. // ...let's do it try { createTranformedPictureFile(imageHelper); } catch (JUploadException e) { // Hum, too bad. // if any file was created, we remove it. deleteTransformedPictureFile(); throw e; } } } }// end of initTransformedPictureFile /** * Creates a transformed picture file of the given max width and max height. * If the {@link #transformedPictureFile} attribute is not set before * calling this method, it will be set. If set before, the existing * {@link #transformedPictureFile} is replaced by the newly transformed * picture file. It is cleared if an error occured.
* * @param imageHelper * The {@link ImageHelper} that was initialized with current * parameters. */ synchronized void createTranformedPictureFile(ImageHelper imageHelper) throws JUploadException { this.uploadPolicy.displayDebug(this.hashCode() + "|Entering PictureFileData.createTransformedPictureFile()", 95); IIOMetadata metadata = null; IIOImage iioImage = null; BufferedImage originalImage = null; BufferedImage transformedImage = null; ImageReaderWriterHelper imageWriterHelper = new ImageReaderWriterHelper( (PictureUploadPolicy) this.uploadPolicy, this); boolean transmitMetadata = ((PictureUploadPolicy) this.uploadPolicy) .getPictureTransmitMetadata(); // Creation of the transformed picture file. createTransformedTempFile(); this.targetPictureFormat = imageWriterHelper.getTargetPictureFormat(); imageWriterHelper.setOutput(this.transformedPictureFile); // How many picture should we read from the input file. // Default number of pictures is one. int nbPictures = 1; // For gif file, we put a max to MAX_VALUE, and we check the // IndexOutOfBoundsException to identify when we've read all pictures if (getExtension(getFile()).equalsIgnoreCase("gif")) { nbPictures = Integer.MAX_VALUE; } this.uploadPolicy.displayDebug( "Reading image with imageWriterHelper.readImage(i)", 50); // Now, we have to read each picture from the original file, apply // the calculated transformation, and write each transformed picture // to the writer. // As indicated in javadoc for ImageReader.getNumImages(), we go // through pictures, until we get an IndexOutOfBoundsException. try { for (int i = 0; i < nbPictures; i += 1) { originalImage = imageWriterHelper.readImage(i); transformedImage = imageHelper.getBufferedImage(true, originalImage); // If necessary, we load the metadata for the current // picture if (transmitMetadata) { metadata = imageWriterHelper.getImageMetadata(i); } iioImage = new IIOImage(transformedImage, null, metadata); imageWriterHelper.write(iioImage); // Let's clear picture, to force getBufferedImage to read a new // one, // in the next loop. if (originalImage != null) { originalImage.flush(); originalImage = null; } }// for } catch (IndexOutOfBoundsException e) { // Was sent by imageWriterHelper.readImage(i) // Ok, no more picture to read. We just want to go out of // the loop. No error. this.uploadPolicy.displayDebug( "IndexOutOfBoundsException catched: end of reading for file " + getFileName(), 10); } if (originalImage != null) { originalImage.flush(); originalImage = null; } // Let's free any used resource. imageWriterHelper.dispose(); } /** * This method is called when an OutOfMemoryError occurs. This can easily * happen within the navigator, with big pictures: I've put a lot of * freeMemory calls within the code, but they don't seem to work very well. * When running from eclipse, the memory is freed Ok ! */ void tooBigPicture() { String msg = this.uploadPolicy.getLocalizedString("tooBigPicture", getFileName()); this.uploadPolicy.displayWarn(msg); JOptionPane.showMessageDialog(null, msg, "Warning", JOptionPane.WARNING_MESSAGE); } /** * This methods set the {@link DefaultFileData#mimeType} to the image mime * type, that should be associate with the picture. */ void setMimeTypeByExtension(String fileExtension) { String ext = fileExtension.toLowerCase(); if (ext.equals("jpg")) { ext = "jpeg"; } this.mimeType = "image/" + ext; } /** * If {@link #transformedPictureFile} is null, create a new temporary file, * and assign it to {@link #transformedPictureFile}. Otherwise, no action. * * @throws IOException */ synchronized void createTransformedTempFile() throws JUploadIOException { this.uploadPolicy.displayDebug(this.hashCode() + "|Entering PictureFileData.createTransformedTempFile()", 95); if (this.transformedPictureFile == null) { try { this.transformedPictureFile = File.createTempFile("jupload_", ".tmp"); } catch (IOException e) { throw new JUploadIOException( "PictureFileData.createTransformedTempFile()", e); } this.uploadPolicy.getContext().registerUnload(this, "deleteTransformedPictureFile"); this.uploadPolicy.displayDebug("Using transformed temp file " + this.transformedPictureFile.getAbsolutePath() + " for " + getFileName(), 30); } } /** * This method loads the picture width and height of the picture. It's * called by the current instance when necessary. * * @throws JUploadIOException * @see #getOriginalHeight() * @see #getOriginalWidth() */ void initWidthAndHeight() throws JUploadIOException { // Is it a picture? if (this.isPicture && (this.originalHeight < 0 || this.originalWidth < 0)) { // Ok: it's a picture and is original width and height have not been // loaded yet. // In the windows world, file extension may be in upper case, which // is not compatible with the core Java API. Iterator iter = ImageIO .getImageReadersByFormatName(getFileExtension() .toLowerCase()); if (iter.hasNext()) { // It's a picture: we store its original width and height, for // further calculation (rescaling and rotation). try { FileImageInputStream fiis = new FileImageInputStream( getFile()); ImageReader ir = iter.next(); ir.setInput(fiis); this.originalHeight = ir.getHeight(0); this.originalWidth = ir.getWidth(0); ir.dispose(); fiis.close(); } catch (IOException e) { throw new JUploadIOException("PictureFileData()", e); } } } } /** * If {@link #workingCopyTempFile} is null, create a new temporary file, and * assign it to {@link #transformedPictureFile}. Otherwise, no action. * * @throws IOException */ synchronized void createWorkingCopyTempFile() throws IOException { this.uploadPolicy.displayDebug(this.hashCode() + "|Entering PictureFileData.createWorkingCopyTempFile()", 95); if (this.workingCopyTempFile == null) { // The temporary file must have the correct extension, so that // native Java method works on it. this.workingCopyTempFile = File.createTempFile("jupload_", ".tmp." + DefaultFileData.getExtension(getFile())); this.uploadPolicy.getContext().registerUnload(this, "deleteWorkingCopyPictureFile"); this.uploadPolicy.displayDebug("Using working copy temp file " + this.workingCopyTempFile.getAbsolutePath() + " for " + getFileName(), 30); } } /** * File.deleteOnExit() is pretty unreliable, especially in applets. * Therefore the applet provides a callback which is executed during applet * termination. This method performs the actual cleanup. */ public synchronized void deleteWorkingCopyPictureFile() { // for debug : if the debugLevel is enough, we keep the temporary // file (for check). if (null != this.workingCopyTempFile && this.uploadPolicy.getDebugLevel() <= 100) { if (!this.workingCopyTempFile.delete()) { this.uploadPolicy.displayWarn("Unable to delete " + this.workingCopyTempFile.getName()); } this.workingCopyTempFile = null; } } /** * Get the file that contains the original picture. This is used as a * workaround for the following JVM bug: once in the navigator, it can't * transform picture read from a file whose name contains non-ASCII * characters, like French accents. * * @return The file that contains the original picture, as the source for * picture transformation * @throws JUploadIOException */ public synchronized File getWorkingSourceFile() throws JUploadIOException { if (this.workingCopyTempFile == null) { this.uploadPolicy.displayDebug( "[getWorkingSourceFile] Creating a copy of " + getFileName() + " as a source working target.", 30); FileInputStream is = null; FileOutputStream os = null; try { createWorkingCopyTempFile(); is = new FileInputStream(getFile()); os = new FileOutputStream(this.workingCopyTempFile); byte b[] = new byte[1024]; int l; while ((l = is.read(b)) > 0) { os.write(b, 0, l); } } catch (IOException e) { throw new JUploadIOException( "ImageReaderWriterHelper.getWorkingSourceFile()", e); } finally { if (is != null) { try { is.close(); } catch (IOException e) { this.uploadPolicy .displayWarn(e.getClass().getName() + " while trying to close FileInputStream, in PictureUploadPolicy.copyOriginalToWorkingCopyTempFile."); } finally { is = null; } } if (os != null) { try { os.close(); } catch (IOException e) { this.uploadPolicy .displayWarn(e.getClass().getName() + " while trying to close FileOutputStream, in PictureUploadPolicy.copyOriginalToWorkingCopyTempFile."); } finally { os = null; } } } } return this.workingCopyTempFile; }// getWorkingSourceFile() /** * @return the originalWidth of the picture * @throws JUploadIOException */ public int getOriginalWidth() throws JUploadIOException { initWidthAndHeight(); return this.originalWidth; } /** * @return the originalHeight of the picture * @throws JUploadIOException */ public int getOriginalHeight() throws JUploadIOException { initWidthAndHeight(); return this.originalHeight; } // //////////////////////////////////////////////////////////////////////////////////////////////////// // /////////////////////// static methods // //////////////////////////////////////////////////////////////////////////////////////////////////// /** * Returns an ImageIcon for the given file, resized according to the given * dimensions. If the original file contains a pictures smaller than these * width and height, the picture is returned as is (nor resized). * * @param pictureFile * The file, containing a picture, from which the user wants to * extract a static picture. * @param maxWidth * The maximum allowed width for the static picture to generate. * @param maxHeight * The maximum allowed height for the static picture to generate. * @return The created static picture, or null if the file is null. * @throws JUploadException * If the ImageIcon can not be loaded. */ public static ImageIcon getImageIcon(File pictureFile, int maxWidth, int maxHeight) throws JUploadException { ImageIcon thumbnail = null; if (pictureFile != null) { ImageIcon tmpIcon; try { tmpIcon = new ImageIcon(ImageIO.read(pictureFile)); } catch (IOException e) { throw new JUploadIOException( "An error occured while loading the image icon for " + pictureFile.getAbsolutePath(), e); } if (tmpIcon != null) { // Let's calculate the asked icon. double scaleWidth = ((double) maxWidth) / tmpIcon.getIconWidth(); double scaleHeight = ((double) maxHeight) / tmpIcon.getIconHeight(); double scale = Math.min(scaleWidth, scaleHeight); if (scale < 1) { thumbnail = new ImageIcon(tmpIcon.getImage() .getScaledInstance( (int) (scale * tmpIcon.getIconWidth()), (int) (scale * tmpIcon.getIconHeight()), Image.SCALE_FAST)); } else { // no need to miniaturize thumbnail = tmpIcon; } } } return thumbnail; } /** * Indicates whether a file is a picture or not. The information is based on * the fact the an ImageRead is found, or not, for this file. This test uses * the core Java API. As in the windows world, file extension may be in * uppercase, the test is based on the lowercase value for the given file * extension. * * @param file * @return true if the file can be opened as a picture, false otherwise. */ public static boolean isFileAPicture(File file) { // In the windows world, file extension may be in uppercase, which is // not compatible with the core Java API. Iterator iter = ImageIO .getImageReadersByFormatName(DefaultFileData.getExtension(file) .toLowerCase()); return iter.hasNext(); } }