//
// $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 :
*
* - Ability to define a target format (to convert pictures to JPG before
* upload, for instance)
*
- Optional definition of a maximal width and/or height.
*
- Ability to rotate a picture, with {@link #addRotation(int)}
*
- Ability to store a picture into a BufferedImage. This is actualy a bad
* idea within an applet (should run within a java application) : the applet
* runs very quickly out of memory. With pictures from my Canon EOS20D (3,5M), I
* can only display two pictures. The third one generates an out of memory
* error, despite the System.finalize and System.gc I've put everywhere in the
* code!
*
*
* @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.
*
* - 0 means no rotation.
*
- 1 means a rotation of 90� clockwise (word = Ok ??).
*
- 2 means a rotation of 180�.
*
- 3 means a rotation of 900 counterclockwise (word = Ok ??).
*
*/
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();
}
}