// // $Id$ // // jupload - A file upload applet. // // Copyright 2008 The JUpload Team // // Created: 12 f�vr. 08 // Creator: etienne_sf // Last modified: $Date$ // // 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.helper; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.Iterator; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.metadata.IIOMetadata; import javax.imageio.plugins.jpeg.JPEGImageWriteParam; import javax.imageio.stream.FileImageInputStream; import javax.imageio.stream.FileImageOutputStream; import wjhk.jupload2.exception.JUploadIOException; import wjhk.jupload2.filedata.DefaultFileData; import wjhk.jupload2.filedata.PictureFileData; import wjhk.jupload2.policies.PictureUploadPolicy; /** * * This package provides low level methods, for picture management. It is used * by {@link PictureFileData} to simplify its processing. * * @author etienne_sf * */ public class ImageReaderWriterHelper { /** * File input, from which the original picture should be read. */ FileImageInputStream fileImageInputStream = null; /** * File output stream for the current transformation. */ FileImageOutputStream fileImageOutputStream; /** * The {@link PictureFileData} that this helper will have to help. */ PictureFileData pictureFileData; /** * Current ImageReader. Initialized by {@link #initImageReader()} */ ImageReader imageReader = null; /** * Current ImageWriter. Initialized by {@link #initImageWriter()} */ ImageWriter imageWriter = null; /** * Current ImageWriter. Initialized by {@link #initImageWriter()} */ ImageWriteParam imageWriterParam = null; /** * Contains the target picture format: GIF, JPG... It is used to find an * ImageWriter, and to define the target filename. */ String targetPictureFormat; /** * The current upload policy must be a {@link PictureUploadPolicy} */ PictureUploadPolicy uploadPolicy; // //////////////////////////////////////////////////////////////////// // //////////////////// CONSTRUCTOR // //////////////////////////////////////////////////////////////////// /** * Standard constructor. * * @param uploadPolicy The current upload policy. * @param pictureFileData The file data to be 'helped'. */ public ImageReaderWriterHelper(PictureUploadPolicy uploadPolicy, PictureFileData pictureFileData) { this.uploadPolicy = uploadPolicy; this.pictureFileData = pictureFileData; // localPictureFormat is currently only used to define the correct // image writer. There is no transformation between to different // picture format (like JPG to GIF) if (this.uploadPolicy.getTargetPictureFormat() == null) { targetPictureFormat = pictureFileData.getFileExtension(); } else { targetPictureFormat = this.uploadPolicy.getTargetPictureFormat(); } } // //////////////////////////////////////////////////////////////////// // //////////////////// PUBLIC METHODS // //////////////////////////////////////////////////////////////////// /** * Creates a FileImageOutputStream, and assign it as the output to the * imageWriter. * * @param file The file where the output stream must write. * @throws JUploadIOException Any error... */ public void setOutput(File file) throws JUploadIOException { // We first initialize internal variable. initImageWriter(); try { fileImageOutputStream = new FileImageOutputStream(file); } catch (IOException e) { throw new JUploadIOException("ImageReaderWriterHelper.setOutput()", e); } imageWriter.setOutput(fileImageOutputStream); } /** * Free all reserved resource by this helper. Includes closing of any input * or output stream. * * @throws JUploadIOException Any IO Exception */ public void dispose() throws JUploadIOException { // First: let's free any resource used by ImageWriter. if (imageWriter != null) { // An imageWriter was initialized. Let's free it. imageWriter.dispose(); if (fileImageOutputStream != null) { try { fileImageOutputStream.close(); } catch (IOException e) { throw new JUploadIOException( "ImageReaderWriterHelper.dispose() [fileImageOutputStream]", e); } } imageWriter = null; fileImageOutputStream = null; } // Then, all about ImageReader if (imageReader != null) { // An imageReader was initialized. Let's free it. imageReader.dispose(); try { fileImageInputStream.close(); } catch (IOException e) { throw new JUploadIOException( "ImageReaderWriterHelper.dispose() [fileImageInputStream]", e); } imageReader = null; fileImageInputStream = null; } } /** * Call to imageReader.getNumImages(boolean). Caution: may be long, for big * files. * * @param allowSearch * @return The number of image into this file. * @throws JUploadIOException */ public int getNumImages(boolean allowSearch) throws JUploadIOException { initImageReader(); try { return imageReader.getNumImages(allowSearch); } catch (IOException e) { throw new JUploadIOException( "ImageReaderWriterHelper.getNumImages() [fileImageInputStream]", e); } } /** * Call to ImageIO.read(fileImageInputStream). * * @return The BufferedImage read * @throws JUploadIOException */ public BufferedImage imageIORead() throws JUploadIOException { try { return ImageIO.read(pictureFileData.getWorkingSourceFile()); } catch (IOException e) { throw new JUploadIOException( "ImageReaderWriterHelper.ImageIORead()", e); } } /** * Read an image, from the pictureFileData. * * @param imageIndex The index number of the picture, in the file. 0 for the * first picture (only valid value for picture containing one * picture) * @return The image corresponding to this index, in the picture file. * @throws JUploadIOException * @throws IndexOutOfBoundsException Occurs when the imageIndex is wrong. */ public BufferedImage readImage(int imageIndex) throws JUploadIOException, IndexOutOfBoundsException { initImageReader(); try { uploadPolicy.displayDebug( "ImageReaderWriterHelper: reading picture number " + imageIndex + " of file " + pictureFileData.getFileName(), 50); return imageReader.read(imageIndex); } catch (IndexOutOfBoundsException e) { // The IndexOutOfBoundsException is transmitted to the caller. It // indicates that the index is out of bound. It's the good way for // the caller to stop the loop through available pictures. throw e; } catch (IOException e) { throw new JUploadIOException("ImageReaderWriterHelper.readImage(" + imageIndex + ")", e); } } /** * Read an image, from the pictureFileData. * * @param imageIndex The index number of the picture, in the file. 0 for the * first picture (only valid value for picture containing one * picture) * @return The full image data for this index * @throws JUploadIOException * @throws IndexOutOfBoundsException Occurs when the imageIndex is wrong. */ public IIOImage readAll(int imageIndex) throws JUploadIOException, IndexOutOfBoundsException { initImageReader(); try { uploadPolicy.displayDebug( "ImageReaderWriterHelper: reading picture number " + imageIndex + " of file " + pictureFileData.getFileName(), 50); return imageReader.readAll(imageIndex, imageReader .getDefaultReadParam()); } catch (IndexOutOfBoundsException e) { // The IndexOutOfBoundsException is transmitted to the caller. It // indicates that the index is out of bound. It's the good way for // the caller to stop the loop through available pictures. throw e; } catch (IOException e) { throw new JUploadIOException("ImageReaderWriterHelper.readAll(" + imageIndex + ")", e); } } /** * Load the metadata associated with one picture in the picture file. * * @param imageIndex * @return The metadata loaded * @throws JUploadIOException Any IOException is encapsulated in this * exception */ public IIOMetadata getImageMetadata(int imageIndex) throws JUploadIOException { // We must have the reader initialized initImageReader(); // Ok, let's go try { uploadPolicy.displayDebug( "ImageReaderWriterHelper: reading metadata for picture number " + imageIndex + " of file " + pictureFileData.getFileName(), 50); return imageReader.getImageMetadata(imageIndex); } catch (IOException e) { throw new JUploadIOException( "ImageReaderWriterHelper.getImageMetadata()", e); } } /** * Write a picture in the output picture file. Called just before an upload. * * @param numIndex The index of the image in the transformed picture file. * @param iioImage The image to write. * @param iwp The parameter to use to write this image. * @throws JUploadIOException */ public void writeInsert(int numIndex, IIOImage iioImage, ImageWriteParam iwp) throws JUploadIOException { initImageWriter(); try { imageWriter.writeInsert(numIndex, iioImage, iwp); } catch (IOException e) { throw new JUploadIOException( "ImageReaderWriterHelper.writeInsert()", e); } } /** * Write a picture in the output picture file. Called just before an upload. * * @param iioImage The image to write. * @throws JUploadIOException */ public void write(IIOImage iioImage) throws JUploadIOException { initImageWriter(); try { imageWriter.write(null, iioImage, imageWriterParam); } catch (IOException e) { throw new JUploadIOException("ImageReaderWriterHelper.write()", e); } } // //////////////////////////////////////////////////////////////////// // //////////////////// PRIVATE METHODS // //////////////////////////////////////////////////////////////////// /** * Initialize the ImageWriter and the ImageWriteParam for the current * picture helper. * * @throws JUploadIOException */ private void initImageWriter() throws JUploadIOException { if (imageWriter == null) { // Get the writer (to choose the compression quality) Iterator<ImageWriter> iter = ImageIO .getImageWritersByFormatName(targetPictureFormat); if (!iter.hasNext()) { // Too bad: no writer for the selected picture format throw new JUploadIOException("No writer for the '" + this.targetPictureFormat + "' picture format."); } else { imageWriter = iter.next(); imageWriterParam = imageWriter.getDefaultWriteParam(); // For jpeg pictures, we force the compression level. if (targetPictureFormat.equalsIgnoreCase("jpg") || targetPictureFormat.equalsIgnoreCase("jpeg")) { imageWriterParam .setCompressionMode(ImageWriteParam.MODE_EXPLICIT); // Let's select a good compromise between picture size // and quality. imageWriterParam .setCompressionQuality(((PictureUploadPolicy) this.uploadPolicy) .getPictureCompressionQuality()); // In some case, we need to force the Huffman tables: ((JPEGImageWriteParam) imageWriterParam) .setOptimizeHuffmanTables(true); } // try { this.uploadPolicy.displayDebug( "ImageWriter1 (used), CompressionQuality=" + imageWriterParam.getCompressionQuality(), 95); } catch (Exception e2) { // If we come here, compression is not supported for // this picture format, or parameters are not explicit // mode, or ... (etc). May trigger several different // errors. We just ignore them: this par of code is only // to write some debug info. } } } }// initImageWriter /** * Initialize the ImageReader for the current helper. * * @throws JUploadIOException */ private void initImageReader() throws JUploadIOException { // First: we open a ImageInputStream try { fileImageInputStream = new FileImageInputStream(pictureFileData .getWorkingSourceFile()); } catch (IOException e) { throw new JUploadIOException( "ImageReaderWriterHelper.initImageReader()", e); } // Then: we create an ImageReader, and assign the ImageInputStream to // it. if (imageReader == null) { String ext = DefaultFileData .getExtension(pictureFileData.getFile()); Iterator<ImageReader> iterator = ImageIO .getImageReadersBySuffix(ext); if (iterator.hasNext()) { imageReader = iterator.next(); imageReader.setInput(fileImageInputStream); uploadPolicy.displayDebug("Foud one reader for " + ext + " extension", 80); }// while // Did we find our reader ? if (imageReader == null) { uploadPolicy.displayErr("Found no reader for " + ext + " extension"); } else if (uploadPolicy.getDebugLevel() > 50) { // This call may be long, so we do it only if useful. try { uploadPolicy.displayDebug("Nb images in " + pictureFileData.getFileName() + ": " + imageReader.getNumImages(true), 50); } catch (IOException e) { // We mask the error, was just for debug... } } } } }