1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package wjhk.jupload2.filedata.helper;
27
28 import java.awt.Image;
29 import java.awt.geom.AffineTransform;
30 import java.awt.image.AffineTransformOp;
31 import java.awt.image.BufferedImage;
32 import java.awt.image.ImageObserver;
33
34 import wjhk.jupload2.exception.JUploadException;
35 import wjhk.jupload2.exception.JUploadIOException;
36 import wjhk.jupload2.filedata.DefaultFileData;
37 import wjhk.jupload2.filedata.PictureFileData;
38 import wjhk.jupload2.policies.PictureUploadPolicy;
39
40
41
42
43
44
45 public class ImageHelper implements ImageObserver {
46
47
48
49
50
51
52
53
54 private Boolean hasToTransformPicture = null;
55
56
57
58
59 private PictureFileData pictureFileData;
60
61
62
63
64
65
66 private int quarterRotation;
67
68
69
70
71 private int maxWidth;
72
73
74
75
76 private int maxHeight;
77
78
79
80
81
82
83
84 private int nbPixelsTotal = -1;
85
86
87
88
89
90
91
92 private int nbPixelsRead = 0;
93
94
95
96
97
98
99
100 private int scaledNonRotatedWidth = -1;
101
102
103
104
105 private int scaledNonRotatedHeight = -1;
106
107
108
109
110
111
112 private int progressBarBaseValue = 0;
113
114
115
116
117
118
119 private double scale = 1;
120
121
122
123
124
125
126
127
128 private int scaledRotatedWidth = -1;
129
130
131
132
133 private int scaledRotatedHeight = -1;
134
135
136
137
138 PictureUploadPolicy uploadPolicy;
139
140
141
142
143
144
145
146
147
148
149
150 public ImageHelper(PictureUploadPolicy uploadPolicy, PictureFileData pictureFileData, int targetMaxWidth,
151 int targetMaxHeight, int quarterRotation) throws JUploadIOException {
152 this.uploadPolicy = uploadPolicy;
153 this.pictureFileData = pictureFileData;
154 this.maxWidth = targetMaxWidth;
155 this.maxHeight = targetMaxHeight;
156 this.quarterRotation = quarterRotation;
157
158
159
160 initScale();
161 }
162
163
164
165
166
167 private void initScale() throws JUploadIOException {
168 double theta = Math.toRadians(90 * this.quarterRotation);
169
170
171
172
173 int nonScaledRotatedWidth = this.pictureFileData.getOriginalWidth();
174 int nonScaledRotatedHeight = this.pictureFileData.getOriginalHeight();
175 if (this.quarterRotation % 2 != 0) {
176
177
178 nonScaledRotatedWidth = this.pictureFileData.getOriginalHeight();
179 nonScaledRotatedHeight = this.pictureFileData.getOriginalWidth();
180 }
181
182
183 double scaleWidth = ((this.maxWidth < 0) ? 1 : ((double) this.maxWidth) / nonScaledRotatedWidth);
184 double scaleHeight = ((this.maxHeight < 0) ? 1 : ((double) this.maxHeight) / nonScaledRotatedHeight);
185 this.scale = Math.min(scaleWidth, scaleHeight);
186 if (this.scale < 1) {
187
188
189 if ((this.maxWidth > 0 && this.maxWidth < (int) (this.scale * Math.cos(theta) * nonScaledRotatedWidth))
190 || (this.maxHeight > 0 && this.maxHeight < (int) (this.scale * Math.cos(theta) * nonScaledRotatedHeight))) {
191 scaleWidth = ((this.maxWidth < 0) ? 1 : ((double) this.maxWidth - 1) / (nonScaledRotatedWidth));
192 scaleHeight = ((this.maxHeight < 0) ? 1 : ((double) this.maxHeight - 1) / (nonScaledRotatedHeight));
193 this.scale = Math.min(scaleWidth, scaleHeight);
194 }
195 }
196
197
198
199 this.scaledRotatedWidth = nonScaledRotatedWidth;
200 this.scaledRotatedHeight = nonScaledRotatedHeight;
201
202
203
204 if (this.scale < 1) {
205 this.scaledRotatedWidth *= this.scale;
206 this.scaledRotatedHeight *= this.scale;
207 this.uploadPolicy.displayDebug("Resizing factor (scale): " + this.scale, 30);
208 } else {
209 this.uploadPolicy.displayDebug("Resizing factor (scale): no resizing (calculated scale was " + this.scale
210 + ")", 30);
211 }
212
213
214
215 if (this.scaledRotatedWidth > this.maxWidth) {
216 this.uploadPolicy.displayDebug("Correcting rounded width: " + this.scaledRotatedWidth + " to "
217 + this.maxWidth, 50);
218 this.scaledRotatedWidth = this.maxWidth;
219 }
220 if (this.scaledRotatedHeight > this.maxHeight) {
221 this.uploadPolicy.displayDebug("Correcting rounded height: " + this.scaledRotatedHeight + " to "
222 + this.maxHeight, 50);
223 this.scaledRotatedHeight = this.maxHeight;
224 }
225
226
227 if (this.quarterRotation % 2 == 0) {
228 this.scaledNonRotatedWidth = this.scaledRotatedWidth;
229 this.scaledNonRotatedHeight = this.scaledRotatedHeight;
230 } else {
231 this.scaledNonRotatedWidth = this.scaledRotatedHeight;
232 this.scaledNonRotatedHeight = this.scaledRotatedWidth;
233 }
234 }
235
236
237
238
239
240
241
242
243 public boolean hasToTransformPicture() throws JUploadException {
244
245
246 if (DefaultFileData.getExtension(this.pictureFileData.getFileName()).equalsIgnoreCase("gif")) {
247
248
249 ImageReaderWriterHelper irwh = new ImageReaderWriterHelper(this.uploadPolicy, this.pictureFileData);
250 int nbImages = irwh.getNumImages(true);
251 irwh.dispose();
252 irwh = null;
253 if (nbImages > 1) {
254
255 this.hasToTransformPicture = Boolean.FALSE;
256 this.uploadPolicy
257 .displayWarn("No transformation for gif picture file, that contain several pictures. (see JUpload documentation for details)");
258 }
259 }
260
261
262 if (this.hasToTransformPicture == null) {
263
264
265 if (this.hasToTransformPicture == null && !(this.uploadPolicy).getPictureTransmitMetadata()) {
266 this.hasToTransformPicture = Boolean.TRUE;
267 this.uploadPolicy.displayDebug(this.pictureFileData.getFileName()
268 + " : hasToTransformPicture=true (pictureTransmitMetadata is false)", 80);
269 }
270
271 if (this.hasToTransformPicture == null && this.quarterRotation != 0) {
272 this.uploadPolicy.displayDebug(this.pictureFileData.getFileName()
273 + " : hasToTransformPicture = true (quarterRotation != 0)", 10);
274 this.hasToTransformPicture = Boolean.TRUE;
275 }
276
277
278 String targetFormat = this.uploadPolicy.getImageFileConversionInfo().getTargetFormatOrNull(
279 this.pictureFileData.getFileExtension());
280 if (this.hasToTransformPicture == null && targetFormat != null) {
281 this.uploadPolicy.displayDebug(this.pictureFileData.getFileName()
282 + " : hasToTransformPicture = true (targetPictureFormat)", 10);
283 this.hasToTransformPicture = Boolean.TRUE;
284 }
285
286
287 if (this.hasToTransformPicture == null && this.scale < 1) {
288 this.uploadPolicy.displayDebug(this.pictureFileData.getFileName()
289 + " : hasToTransformPicture = true (scale < 1)", 10);
290 this.hasToTransformPicture = Boolean.TRUE;
291 }
292
293
294
295 if (this.hasToTransformPicture == null) {
296 this.uploadPolicy.displayDebug(this.pictureFileData.getFileName() + " : hasToTransformPicture = false",
297 10);
298 this.hasToTransformPicture = Boolean.FALSE;
299 this.uploadPolicy.displayDebug(this.pictureFileData.getFileName() + " : hasToTransformPicture = false",
300 10);
301 }
302 }
303
304 return this.hasToTransformPicture.booleanValue();
305 }
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325 public BufferedImage getBufferedImage(boolean highquality, BufferedImage sourceBufferedImage)
326 throws JUploadException {
327 long msGetBufferedImage = System.currentTimeMillis();
328 double theta = Math.toRadians(90 * this.quarterRotation);
329
330 BufferedImage returnedBufferedImage = null;
331
332 this.uploadPolicy.displayDebug("getBufferedImage: start", 10);
333
334 try {
335 AffineTransform transform = new AffineTransform();
336
337 if (this.quarterRotation != 0) {
338 double translationX = 0, translationY = 0;
339 this.uploadPolicy.displayDebug("getBufferedImage: quarter: " + this.quarterRotation, 50);
340
341
342
343 switch (this.quarterRotation) {
344 case 1:
345 translationX = 0;
346 translationY = -this.scaledRotatedWidth;
347 break;
348 case 2:
349 translationX = -this.scaledRotatedWidth;
350 translationY = -this.scaledRotatedHeight;
351 break;
352 case 3:
353 translationX = -this.scaledRotatedHeight;
354 translationY = 0;
355 break;
356 default:
357 this.uploadPolicy.displayWarn("Invalid quarterRotation : " + this.quarterRotation);
358 this.quarterRotation = 0;
359 theta = 0;
360 }
361 transform.rotate(theta);
362 transform.translate(translationX, translationY);
363 }
364
365
366 if (this.scale < 1) {
367 if (highquality) {
368 this.uploadPolicy
369 .displayDebug("getBufferedImage: Resizing picture(using high quality picture)", 30);
370
371
372
373
374 Image img = sourceBufferedImage.getScaledInstance(this.scaledNonRotatedWidth,
375 this.scaledNonRotatedHeight, Image.SCALE_AREA_AVERAGING);
376
377
378 int localImageType = sourceBufferedImage.getType();
379 if (localImageType == BufferedImage.TYPE_CUSTOM) {
380 localImageType = BufferedImage.TYPE_INT_BGR;
381 }
382
383 BufferedImage tempBufferedImage = new BufferedImage(this.scaledNonRotatedWidth,
384 this.scaledNonRotatedHeight, localImageType);
385
386
387
388 this.nbPixelsTotal = this.scaledNonRotatedWidth * this.scaledNonRotatedHeight;
389 this.nbPixelsRead = 0;
390
391
392 this.uploadPolicy.displayDebug("getBufferedImage: Before drawImage", 50);
393 tempBufferedImage.getGraphics().drawImage(img, 0, 0, this);
394 this.uploadPolicy.displayDebug("getBufferedImage: After drawImage", 50);
395
396 tempBufferedImage.flush();
397
398 img.flush();
399 img = null;
400 PictureFileData.freeMemory("ImageHelper.getBufferedImage()", this.uploadPolicy);
401
402
403
404 sourceBufferedImage = tempBufferedImage;
405 tempBufferedImage = null;
406 } else {
407
408
409
410
411 this.uploadPolicy.displayDebug(
412 "getBufferedImage: Resizing picture(using standard quality picture)", 50);
413 transform.scale(this.scale, this.scale);
414 }
415 }
416
417 if (transform.isIdentity()) {
418 returnedBufferedImage = sourceBufferedImage;
419 } else {
420 AffineTransformOp affineTransformOp = null;
421
422 affineTransformOp = new AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
423 returnedBufferedImage = affineTransformOp.createCompatibleDestImage(sourceBufferedImage, null);
424
425
426
427 this.uploadPolicy.displayDebug("getBufferedImage: returnedBufferedImage.getColorModel(): "
428 + sourceBufferedImage.getColorModel().toString(), 50);
429 this.uploadPolicy.displayDebug("getBufferedImage: returnedBufferedImage.getColorModel(): "
430 + sourceBufferedImage.getColorModel().toString(), 50);
431 affineTransformOp.filter(sourceBufferedImage, returnedBufferedImage);
432 affineTransformOp = null;
433
434 returnedBufferedImage.flush();
435 }
436 } catch (Exception e) {
437 throw new JUploadException(e.getClass().getName() + " (" + this.getClass().getName()
438 + ".getBufferedImage()) : " + e.getMessage());
439 }
440
441 if (returnedBufferedImage != null && this.uploadPolicy.getDebugLevel() >= 50) {
442 this.uploadPolicy.displayDebug("getBufferedImage: " + returnedBufferedImage, 50);
443 this.uploadPolicy.displayDebug("getBufferedImage: MinX=" + returnedBufferedImage.getMinX(), 50);
444 this.uploadPolicy.displayDebug("getBufferedImage: MinY=" + returnedBufferedImage.getMinY(), 50);
445 }
446
447 this.uploadPolicy.displayDebug("getBufferedImage: was " + (System.currentTimeMillis() - msGetBufferedImage)
448 + " ms long", 50);
449 PictureFileData.freeMemory("ImageHelper.getBufferedImage()", this.uploadPolicy);
450 return returnedBufferedImage;
451 }
452
453
454
455
456
457
458
459
460
461 BufferedImage getBufferedImage2(boolean highquality, BufferedImage sourceBufferedImage) throws JUploadException {
462 long msGetBufferedImage = System.currentTimeMillis();
463 BufferedImage dest = null;
464
465
466 this.uploadPolicy.displayDebug("getBufferedImage: quarter: " + this.quarterRotation, 50);
467
468
469 @SuppressWarnings("unused")
470 int maxWidthBeforeRotation, maxHeigthBeforeRotation, widthBeforeRotation, heigthBeforeRotation, widthAfterRotation, heigthAfterRotation;
471 @SuppressWarnings("unused")
472 double theta = Math.toRadians(90 * this.quarterRotation);
473 switch (this.quarterRotation) {
474 case 0:
475 case 2:
476 maxWidthBeforeRotation = this.uploadPolicy.getMaxWidth();
477 maxHeigthBeforeRotation = this.uploadPolicy.getMaxHeight();
478 widthBeforeRotation = sourceBufferedImage.getWidth();
479 heigthBeforeRotation = sourceBufferedImage.getHeight();
480 widthAfterRotation = sourceBufferedImage.getWidth();
481 heigthAfterRotation = sourceBufferedImage.getHeight();
482 break;
483 case 1:
484 case 3:
485 maxWidthBeforeRotation = this.uploadPolicy.getMaxHeight();
486 maxHeigthBeforeRotation = this.uploadPolicy.getMaxWidth();
487 widthBeforeRotation = sourceBufferedImage.getHeight();
488 heigthBeforeRotation = sourceBufferedImage.getWidth();
489 widthAfterRotation = sourceBufferedImage.getHeight();
490 heigthAfterRotation = sourceBufferedImage.getWidth();
491 break;
492 default:
493 throw new JUploadException("Invalid quarter rotation: <" + this.quarterRotation + ">");
494 }
495 double scaleWidthBeforeRotation = widthBeforeRotation / maxWidthBeforeRotation;
496 double scaleHeigthBeforeRotation = heigthBeforeRotation / maxHeigthBeforeRotation;
497 double scale = Math.min(scaleWidthBeforeRotation, scaleHeigthBeforeRotation);
498
499
500 @SuppressWarnings("unused")
501 Image scaledPicture = sourceBufferedImage;
502 if (scale < 1) {
503 int targetWidthBeforeRotation, targetHeigthBeforeRotation;
504 if (scaleWidthBeforeRotation < scaleHeigthBeforeRotation) {
505
506 targetWidthBeforeRotation = maxWidthBeforeRotation;
507 targetHeigthBeforeRotation = (int) (heigthBeforeRotation * scale);
508 } else {
509
510 targetHeigthBeforeRotation = maxHeigthBeforeRotation;
511 targetWidthBeforeRotation = (int) (widthBeforeRotation * scale);
512 }
513 int scale_xxx = highquality ? Image.SCALE_SMOOTH : Image.SCALE_FAST;
514 scaledPicture = sourceBufferedImage.getScaledInstance(targetWidthBeforeRotation,
515 targetHeigthBeforeRotation, scale_xxx);
516 }
517
518
519 if (this.quarterRotation != 0) {
520 @SuppressWarnings("unused")
521 AffineTransform rotationTransform;
522 switch (this.quarterRotation) {
523 case 0:
524 case 2:
525 maxWidthBeforeRotation = this.uploadPolicy.getMaxWidth();
526 maxHeigthBeforeRotation = this.uploadPolicy.getMaxHeight();
527 widthBeforeRotation = sourceBufferedImage.getWidth();
528 heigthBeforeRotation = sourceBufferedImage.getHeight();
529 widthAfterRotation = sourceBufferedImage.getWidth();
530 heigthAfterRotation = sourceBufferedImage.getHeight();
531 break;
532 case 1:
533 case 3:
534 maxWidthBeforeRotation = this.uploadPolicy.getMaxHeight();
535 maxHeigthBeforeRotation = this.uploadPolicy.getMaxWidth();
536 widthBeforeRotation = sourceBufferedImage.getHeight();
537 heigthBeforeRotation = sourceBufferedImage.getWidth();
538 widthAfterRotation = sourceBufferedImage.getHeight();
539 heigthAfterRotation = sourceBufferedImage.getWidth();
540 break;
541 default:
542 throw new JUploadException("Invalid quarter rotation: <" + this.quarterRotation + ">");
543 }
544
545
546
547
548
549 this.uploadPolicy.displayDebug("getBufferedImage: was " + (System.currentTimeMillis() - msGetBufferedImage)
550 + " ms long", 50);
551 }
552 return dest;
553 }
554
555
556
557
558
559
560
561
562
563
564
565
566
567 public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {
568 if ((infoflags & ImageObserver.WIDTH) == ImageObserver.WIDTH) {
569 this.progressBarBaseValue = this.uploadPolicy.getContext().getUploadPanel().getPreparationProgressBar()
570 .getValue();
571 this.uploadPolicy.displayDebug(" imageUpdate (start of), progressBar geValue: "
572 + this.progressBarBaseValue, 50);
573 int max = this.uploadPolicy.getContext().getUploadPanel().getPreparationProgressBar().getMaximum();
574 this.uploadPolicy.displayDebug(" imageUpdate (start of), progressBar maximum: " + max, 50);
575 } else if ((infoflags & ImageObserver.SOMEBITS) == ImageObserver.SOMEBITS) {
576 this.nbPixelsRead += width * height;
577 int percentage = (int) ((long) this.nbPixelsRead * 100 / this.nbPixelsTotal);
578 this.uploadPolicy.getContext().getUploadPanel().getPreparationProgressBar()
579 .setValue(this.progressBarBaseValue + percentage);
580
581
582
583
584
585 this.uploadPolicy.getContext().getUploadPanel().getPreparationProgressBar().repaint();
586 } else if ((infoflags & ImageObserver.ALLBITS) == ImageObserver.ALLBITS) {
587 this.uploadPolicy.displayDebug(" imageUpdate, total number of pixels: " + this.nbPixelsRead + " read", 50);
588 }
589
590
591 return true;
592 }
593 }