1 | //
|
---|
2 | // $Id$
|
---|
3 | //
|
---|
4 | // jupload - A file upload applet.
|
---|
5 | //
|
---|
6 | // Copyright 2008 The JUpload Team
|
---|
7 | //
|
---|
8 | // Created: 12 feb. 08
|
---|
9 | // Creator: etienne_sf
|
---|
10 | // Last modified: $Date$
|
---|
11 | //
|
---|
12 | // This program is free software; you can redistribute it and/or modify
|
---|
13 | // it under the terms of the GNU General Public License as published by
|
---|
14 | // the Free Software Foundation; either version 2 of the License, or
|
---|
15 | // (at your option) any later version.
|
---|
16 | //
|
---|
17 | // This program is distributed in the hope that it will be useful,
|
---|
18 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
19 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
20 | // GNU General Public License for more details.
|
---|
21 | //
|
---|
22 | // You should have received a copy of the GNU General Public License
|
---|
23 | // along with this program; if not, write to the Free Software
|
---|
24 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
25 |
|
---|
26 | package wjhk.jupload2.filedata.helper;
|
---|
27 |
|
---|
28 | import java.awt.image.BufferedImage;
|
---|
29 | import java.io.File;
|
---|
30 | import java.io.IOException;
|
---|
31 | import java.util.Iterator;
|
---|
32 |
|
---|
33 | import javax.imageio.IIOImage;
|
---|
34 | import javax.imageio.ImageIO;
|
---|
35 | import javax.imageio.ImageReader;
|
---|
36 | import javax.imageio.ImageWriteParam;
|
---|
37 | import javax.imageio.ImageWriter;
|
---|
38 | import javax.imageio.metadata.IIOMetadata;
|
---|
39 | import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
|
---|
40 | import javax.imageio.stream.FileImageInputStream;
|
---|
41 | import javax.imageio.stream.FileImageOutputStream;
|
---|
42 |
|
---|
43 | import wjhk.jupload2.exception.JUploadIOException;
|
---|
44 | import wjhk.jupload2.filedata.DefaultFileData;
|
---|
45 | import wjhk.jupload2.filedata.PictureFileData;
|
---|
46 | import wjhk.jupload2.policies.PictureUploadPolicy;
|
---|
47 |
|
---|
48 | /**
|
---|
49 | *
|
---|
50 | * This package provides low level methods, for picture management. It is used
|
---|
51 | * by {@link PictureFileData} to simplify its processing.
|
---|
52 | *
|
---|
53 | * @author etienne_sf
|
---|
54 | *
|
---|
55 | */
|
---|
56 | public class ImageReaderWriterHelper {
|
---|
57 |
|
---|
58 | /**
|
---|
59 | * File input, from which the original picture should be read.
|
---|
60 | */
|
---|
61 | FileImageInputStream fileImageInputStream = null;
|
---|
62 |
|
---|
63 | /**
|
---|
64 | * File output stream for the current transformation.
|
---|
65 | */
|
---|
66 | FileImageOutputStream fileImageOutputStream;
|
---|
67 |
|
---|
68 | /**
|
---|
69 | * The {@link PictureFileData} that this helper will have to help.
|
---|
70 | */
|
---|
71 | PictureFileData pictureFileData;
|
---|
72 |
|
---|
73 | /**
|
---|
74 | * Current ImageReader. Initialized by {@link #initImageReader()}
|
---|
75 | */
|
---|
76 | ImageReader imageReader = null;
|
---|
77 |
|
---|
78 | /**
|
---|
79 | * Current ImageWriter. Initialized by {@link #initImageWriter()}
|
---|
80 | */
|
---|
81 | ImageWriter imageWriter = null;
|
---|
82 |
|
---|
83 | /**
|
---|
84 | * Current ImageWriter. Initialized by {@link #initImageWriter()}
|
---|
85 | */
|
---|
86 | ImageWriteParam imageWriterParam = null;
|
---|
87 |
|
---|
88 | /**
|
---|
89 | * Contains the target picture format (in lowercase): gif, jpg... It is used
|
---|
90 | * to find an ImageWriter, and to define the target filename.
|
---|
91 | */
|
---|
92 | String targetPictureFormat;
|
---|
93 |
|
---|
94 | /**
|
---|
95 | * The current upload policy must be a {@link PictureUploadPolicy}
|
---|
96 | */
|
---|
97 | PictureUploadPolicy uploadPolicy;
|
---|
98 |
|
---|
99 | // ////////////////////////////////////////////////////////////////////
|
---|
100 | // //////////////////// CONSTRUCTOR
|
---|
101 | // ////////////////////////////////////////////////////////////////////
|
---|
102 |
|
---|
103 | /**
|
---|
104 | * Standard constructor.
|
---|
105 | *
|
---|
106 | * @param uploadPolicy The current upload policy.
|
---|
107 | * @param pictureFileData The file data to be 'helped'.
|
---|
108 | */
|
---|
109 | public ImageReaderWriterHelper(PictureUploadPolicy uploadPolicy,
|
---|
110 | PictureFileData pictureFileData) {
|
---|
111 | this.uploadPolicy = uploadPolicy;
|
---|
112 | this.pictureFileData = pictureFileData;
|
---|
113 |
|
---|
114 | this.targetPictureFormat = uploadPolicy.getImageFileConversionInfo()
|
---|
115 | .getTargetFormat(pictureFileData.getFileExtension());
|
---|
116 | }
|
---|
117 |
|
---|
118 | // ////////////////////////////////////////////////////////////////////
|
---|
119 | // //////////////////// PUBLIC METHODS
|
---|
120 | // ////////////////////////////////////////////////////////////////////
|
---|
121 |
|
---|
122 | /**
|
---|
123 | * returns the target picture format (lowercase, may be the same as the file
|
---|
124 | * extension)
|
---|
125 | *
|
---|
126 | * @return the target picture format (lowercase, may be the same as the file
|
---|
127 | * extension)
|
---|
128 | */
|
---|
129 | public String getTargetPictureFormat() {
|
---|
130 | return this.targetPictureFormat;
|
---|
131 | }
|
---|
132 |
|
---|
133 | /**
|
---|
134 | * Creates a FileImageOutputStream, and assign it as the output to the
|
---|
135 | * imageWriter.
|
---|
136 | *
|
---|
137 | * @param file The file where the output stream must write.
|
---|
138 | * @throws JUploadIOException Any error...
|
---|
139 | */
|
---|
140 | public void setOutput(File file) throws JUploadIOException {
|
---|
141 | // We first initialize internal variable.
|
---|
142 | initImageWriter();
|
---|
143 |
|
---|
144 | try {
|
---|
145 | this.fileImageOutputStream = new FileImageOutputStream(file);
|
---|
146 | } catch (IOException e) {
|
---|
147 | throw new JUploadIOException("ImageReaderWriterHelper.setOutput()",
|
---|
148 | e);
|
---|
149 | }
|
---|
150 | this.imageWriter.setOutput(this.fileImageOutputStream);
|
---|
151 | }
|
---|
152 |
|
---|
153 | /**
|
---|
154 | * Free all reserved resource by this helper. Includes closing of any input
|
---|
155 | * or output stream.
|
---|
156 | *
|
---|
157 | * @throws JUploadIOException Any IO Exception
|
---|
158 | */
|
---|
159 | public void dispose() throws JUploadIOException {
|
---|
160 | // First: let's free any resource used by ImageWriter.
|
---|
161 | if (this.imageWriter != null) {
|
---|
162 | // An imageWriter was initialized. Let's free it.
|
---|
163 | this.imageWriter.dispose();
|
---|
164 | if (this.fileImageOutputStream != null) {
|
---|
165 | try {
|
---|
166 | this.fileImageOutputStream.close();
|
---|
167 | } catch (IOException e) {
|
---|
168 | throw new JUploadIOException(
|
---|
169 | "ImageReaderWriterHelper.dispose() [fileImageOutputStream]",
|
---|
170 | e);
|
---|
171 | }
|
---|
172 | }
|
---|
173 | this.imageWriter = null;
|
---|
174 | this.fileImageOutputStream = null;
|
---|
175 | }
|
---|
176 |
|
---|
177 | // Then, all about ImageReader
|
---|
178 | if (this.imageReader != null) {
|
---|
179 | // An imageReader was initialized. Let's free it.
|
---|
180 | this.imageReader.dispose();
|
---|
181 | try {
|
---|
182 | this.fileImageInputStream.close();
|
---|
183 | } catch (IOException e) {
|
---|
184 | throw new JUploadIOException(
|
---|
185 | "ImageReaderWriterHelper.dispose() [fileImageInputStream]",
|
---|
186 | e);
|
---|
187 | }
|
---|
188 | this.imageReader = null;
|
---|
189 | this.fileImageInputStream = null;
|
---|
190 | }
|
---|
191 | }
|
---|
192 |
|
---|
193 | /**
|
---|
194 | * Call to imageReader.getNumImages(boolean). Caution: may be long, for big
|
---|
195 | * files.
|
---|
196 | *
|
---|
197 | * @param allowSearch
|
---|
198 | * @return The number of image into this file.
|
---|
199 | * @throws JUploadIOException
|
---|
200 | */
|
---|
201 | public int getNumImages(boolean allowSearch) throws JUploadIOException {
|
---|
202 | initImageReader();
|
---|
203 | try {
|
---|
204 | return this.imageReader.getNumImages(allowSearch);
|
---|
205 | } catch (IOException e) {
|
---|
206 | throw new JUploadIOException(
|
---|
207 | "ImageReaderWriterHelper.getNumImages() [fileImageInputStream]",
|
---|
208 | e);
|
---|
209 | }
|
---|
210 | }
|
---|
211 |
|
---|
212 | /**
|
---|
213 | * Call to ImageIO.read(fileImageInputStream).
|
---|
214 | *
|
---|
215 | * @return The BufferedImage read
|
---|
216 | * @throws JUploadIOException
|
---|
217 | *
|
---|
218 | public BufferedImage imageIORead() throws JUploadIOException {
|
---|
219 | try {
|
---|
220 | return ImageIO.read(this.pictureFileData.getWorkingSourceFile());
|
---|
221 | } catch (IOException e) {
|
---|
222 | throw new JUploadIOException(
|
---|
223 | "ImageReaderWriterHelper.ImageIORead()", e);
|
---|
224 | }
|
---|
225 |
|
---|
226 | }
|
---|
227 | */
|
---|
228 |
|
---|
229 | /**
|
---|
230 | * Read an image, from the pictureFileData.
|
---|
231 | *
|
---|
232 | * @param imageIndex The index number of the picture, in the file. 0 for the
|
---|
233 | * first picture (only valid value for picture containing one
|
---|
234 | * picture)
|
---|
235 | * @return The image corresponding to this index, in the picture file.
|
---|
236 | * @throws JUploadIOException
|
---|
237 | * @throws IndexOutOfBoundsException Occurs when the imageIndex is wrong.
|
---|
238 | */
|
---|
239 | public BufferedImage readImage(int imageIndex) throws JUploadIOException,
|
---|
240 | IndexOutOfBoundsException {
|
---|
241 | initImageReader();
|
---|
242 | try {
|
---|
243 | this.uploadPolicy.displayDebug(
|
---|
244 | "ImageReaderWriterHelper: reading picture number "
|
---|
245 | + imageIndex + " of file "
|
---|
246 | + this.pictureFileData.getFileName(), 30);
|
---|
247 | return this.imageReader.read(imageIndex);
|
---|
248 | } catch (IndexOutOfBoundsException e) {
|
---|
249 | // The IndexOutOfBoundsException is transmitted to the caller. It
|
---|
250 | // indicates that the index is out of bound. It's the good way for
|
---|
251 | // the caller to stop the loop through available pictures.
|
---|
252 | throw e;
|
---|
253 | } catch (IOException e) {
|
---|
254 | throw new JUploadIOException("ImageReaderWriterHelper.readImage("
|
---|
255 | + imageIndex + ")", e);
|
---|
256 | }
|
---|
257 | }
|
---|
258 |
|
---|
259 | /**
|
---|
260 | * Read an image, from the pictureFileData.
|
---|
261 | *
|
---|
262 | * @param imageIndex The index number of the picture, in the file. 0 for the
|
---|
263 | * first picture (only valid value for picture containing one
|
---|
264 | * picture)
|
---|
265 | * @return The full image data for this index
|
---|
266 | * @throws JUploadIOException
|
---|
267 | * @throws IndexOutOfBoundsException Occurs when the imageIndex is wrong.
|
---|
268 | */
|
---|
269 | public IIOImage readAll(int imageIndex) throws JUploadIOException,
|
---|
270 | IndexOutOfBoundsException {
|
---|
271 | initImageReader();
|
---|
272 | try {
|
---|
273 | this.uploadPolicy.displayDebug(
|
---|
274 | "ImageReaderWriterHelper: reading picture number "
|
---|
275 | + imageIndex + " of file "
|
---|
276 | + this.pictureFileData.getFileName(), 30);
|
---|
277 | return this.imageReader.readAll(imageIndex, this.imageReader
|
---|
278 | .getDefaultReadParam());
|
---|
279 | } catch (IndexOutOfBoundsException e) {
|
---|
280 | // The IndexOutOfBoundsException is transmitted to the caller. It
|
---|
281 | // indicates that the index is out of bound. It's the good way for
|
---|
282 | // the caller to stop the loop through available pictures.
|
---|
283 | throw e;
|
---|
284 | } catch (IOException e) {
|
---|
285 | throw new JUploadIOException("ImageReaderWriterHelper.readAll("
|
---|
286 | + imageIndex + ")", e);
|
---|
287 | }
|
---|
288 | }
|
---|
289 |
|
---|
290 | /**
|
---|
291 | * Load the metadata associated with one picture in the picture file.
|
---|
292 | *
|
---|
293 | * @param imageIndex
|
---|
294 | * @return The metadata loaded
|
---|
295 | * @throws JUploadIOException Any IOException is encapsulated in this
|
---|
296 | * exception
|
---|
297 | */
|
---|
298 | public IIOMetadata getImageMetadata(int imageIndex)
|
---|
299 | throws JUploadIOException {
|
---|
300 | // We must have the reader initialized
|
---|
301 | initImageReader();
|
---|
302 |
|
---|
303 | // Ok, let's go
|
---|
304 | try {
|
---|
305 | this.uploadPolicy.displayDebug(
|
---|
306 | "ImageReaderWriterHelper: reading metadata for picture number "
|
---|
307 | + imageIndex + " of file "
|
---|
308 | + this.pictureFileData.getFileName(), 30);
|
---|
309 | return this.imageReader.getImageMetadata(imageIndex);
|
---|
310 | } catch (IOException e) {
|
---|
311 | throw new JUploadIOException(
|
---|
312 | "ImageReaderWriterHelper.getImageMetadata()", e);
|
---|
313 | }
|
---|
314 | }
|
---|
315 |
|
---|
316 | /**
|
---|
317 | * Write a picture in the output picture file. Called just before an upload.
|
---|
318 | *
|
---|
319 | * @param numIndex The index of the image in the transformed picture file.
|
---|
320 | * @param iioImage The image to write.
|
---|
321 | * @param iwp The parameter to use to write this image.
|
---|
322 | * @throws JUploadIOException
|
---|
323 | */
|
---|
324 | public void writeInsert(int numIndex, IIOImage iioImage, ImageWriteParam iwp)
|
---|
325 | throws JUploadIOException {
|
---|
326 | initImageWriter();
|
---|
327 | try {
|
---|
328 | this.imageWriter.writeInsert(numIndex, iioImage, iwp);
|
---|
329 | } catch (IOException e) {
|
---|
330 | throw new JUploadIOException(
|
---|
331 | "ImageReaderWriterHelper.writeInsert()", e);
|
---|
332 | }
|
---|
333 | }
|
---|
334 |
|
---|
335 | /**
|
---|
336 | * Write a picture in the output picture file. Called just before an upload.
|
---|
337 | *
|
---|
338 | * @param iioImage The image to write.
|
---|
339 | * @throws JUploadIOException
|
---|
340 | */
|
---|
341 | public void write(IIOImage iioImage) throws JUploadIOException {
|
---|
342 | initImageWriter();
|
---|
343 | try {
|
---|
344 | this.imageWriter.write(null, iioImage, this.imageWriterParam);
|
---|
345 | } catch (IOException e) {
|
---|
346 | throw new JUploadIOException("ImageReaderWriterHelper.write()", e);
|
---|
347 | }
|
---|
348 | }
|
---|
349 |
|
---|
350 | // ////////////////////////////////////////////////////////////////////
|
---|
351 | // //////////////////// PRIVATE METHODS
|
---|
352 | // ////////////////////////////////////////////////////////////////////
|
---|
353 |
|
---|
354 | /**
|
---|
355 | * Initialize the ImageWriter and the ImageWriteParam for the current
|
---|
356 | * picture helper.
|
---|
357 | *
|
---|
358 | * @throws JUploadIOException
|
---|
359 | */
|
---|
360 | private void initImageWriter() throws JUploadIOException {
|
---|
361 | if (this.imageWriter == null) {
|
---|
362 | // Get the writer (to choose the compression quality)
|
---|
363 | // In the windows world, file extension may be in uppercase, which
|
---|
364 | // is not compatible with the core Java API.
|
---|
365 | Iterator<ImageWriter> iter = ImageIO
|
---|
366 | .getImageWritersByFormatName(this.targetPictureFormat);
|
---|
367 | if (!iter.hasNext()) {
|
---|
368 | // Too bad: no writer for the selected picture format
|
---|
369 |
|
---|
370 | // A particular case: no gif support in JRE 1.5. A JRE upgrade
|
---|
371 | // must be done.
|
---|
372 | if (this.targetPictureFormat.equals("gif")
|
---|
373 | && System.getProperty("java.version").startsWith("1.5")) {
|
---|
374 | throw new JUploadIOException(
|
---|
375 | "gif pictures are not supported in Java 1.5. Please switch to JRE 1.6.");
|
---|
376 | }
|
---|
377 |
|
---|
378 | throw new JUploadIOException("No writer for the '"
|
---|
379 | + this.targetPictureFormat + "' picture format.");
|
---|
380 | } else {
|
---|
381 | this.imageWriter = iter.next();
|
---|
382 | this.imageWriterParam = this.imageWriter.getDefaultWriteParam();
|
---|
383 |
|
---|
384 | // For jpeg pictures, we force the compression level.
|
---|
385 | if (this.targetPictureFormat.equalsIgnoreCase("jpg")
|
---|
386 | || this.targetPictureFormat.equalsIgnoreCase("jpeg")) {
|
---|
387 | this.imageWriterParam
|
---|
388 | .setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
---|
389 | // Let's select a good compromise between picture size
|
---|
390 | // and quality.
|
---|
391 | this.imageWriterParam
|
---|
392 | .setCompressionQuality(this.uploadPolicy
|
---|
393 | .getPictureCompressionQuality());
|
---|
394 | // In some case, we need to force the Huffman tables:
|
---|
395 | ((JPEGImageWriteParam) this.imageWriterParam)
|
---|
396 | .setOptimizeHuffmanTables(true);
|
---|
397 | }
|
---|
398 |
|
---|
399 | //
|
---|
400 | try {
|
---|
401 | this.uploadPolicy.displayDebug(
|
---|
402 | "ImageWriter1 (used), CompressionQuality="
|
---|
403 | + this.imageWriterParam
|
---|
404 | .getCompressionQuality(), 50);
|
---|
405 | } catch (Exception e2) {
|
---|
406 | // If we come here, compression is not supported for
|
---|
407 | // this picture format, or parameters are not explicit
|
---|
408 | // mode, or ... (etc). May trigger several different
|
---|
409 | // errors. We just ignore them: this par of code is only
|
---|
410 | // to write some debug info.
|
---|
411 | this.uploadPolicy.displayWarn(e2.getClass().getName()
|
---|
412 | + " in ImageReaderWriterHelper.java");
|
---|
413 | }
|
---|
414 | }
|
---|
415 | }
|
---|
416 | }// initImageWriter
|
---|
417 |
|
---|
418 | /**
|
---|
419 | * Initialize the ImageReader for the current helper.
|
---|
420 | *
|
---|
421 | * @throws JUploadIOException
|
---|
422 | */
|
---|
423 | private void initImageReader() throws JUploadIOException {
|
---|
424 | // First: we open a ImageInputStream
|
---|
425 | try {
|
---|
426 | this.fileImageInputStream = new FileImageInputStream(
|
---|
427 | this.pictureFileData.getWorkingSourceFile());
|
---|
428 | } catch (IOException e) {
|
---|
429 | throw new JUploadIOException(
|
---|
430 | "ImageReaderWriterHelper.initImageReader()", e);
|
---|
431 | }
|
---|
432 |
|
---|
433 | // Then: we create an ImageReader, and assign the ImageInputStream to
|
---|
434 | // it.
|
---|
435 | if (this.imageReader == null) {
|
---|
436 | String ext = DefaultFileData.getExtension(this.pictureFileData
|
---|
437 | .getFile());
|
---|
438 | Iterator<ImageReader> iterator = ImageIO
|
---|
439 | .getImageReadersBySuffix(ext);
|
---|
440 | if (iterator.hasNext()) {
|
---|
441 | this.imageReader = iterator.next();
|
---|
442 | this.imageReader.setInput(this.fileImageInputStream);
|
---|
443 | this.uploadPolicy.displayDebug("Foud one reader for " + ext
|
---|
444 | + " extension", 50);
|
---|
445 | }// while
|
---|
446 |
|
---|
447 | // Did we find our reader ?
|
---|
448 | if (this.imageReader == null) {
|
---|
449 | this.uploadPolicy.displayErr("Found no reader for " + ext
|
---|
450 | + " extension");
|
---|
451 | } else if (this.uploadPolicy.getDebugLevel() >= 50) {
|
---|
452 | // This call may be long, so we do it only if useful.
|
---|
453 | try {
|
---|
454 | this.uploadPolicy.displayDebug("Nb images in "
|
---|
455 | + this.pictureFileData.getFileName() + ": "
|
---|
456 | + this.imageReader.getNumImages(true), 50);
|
---|
457 | } catch (IOException e) {
|
---|
458 | // We mask the error, was just for debug...
|
---|
459 | }
|
---|
460 | }
|
---|
461 | }
|
---|
462 | }
|
---|
463 | }
|
---|