16
16
package com .thebuzzmedia .imgscalr ;
17
17
18
18
import java .awt .Graphics2D ;
19
+ import java .awt .Image ;
19
20
import java .awt .RenderingHints ;
21
+ import java .awt .Transparency ;
20
22
import java .awt .image .BufferedImage ;
21
23
22
24
/**
81
83
* on any of the <em>source images</em> passed in by calling code; it is up to
82
84
* the original caller to dispose of their source images when they are no longer
83
85
* needed so the VM can most efficiently GC them.
86
+ * <h3>Generated Image Types</h3>
87
+ * Java2D provides support for a number of different image types defined as
88
+ * <code>BufferedImage.TYPE_*</code> variables, unfortunately not all image
89
+ * types are supported equally in Java2D. Some more obscure image types either
90
+ * have poor or no support, leading to severely degraded quality when an attempt
91
+ * is made by imgscalr to create a scaled instance <em>of the same type</em> as
92
+ * the source image.
84
93
* <p/>
85
- * <strong>Logging</strong>: This class implements all its debug logging via the
94
+ * To avoid imgscalr generating significantly worse-looking results than
95
+ * alternative scaling approaches (e.g.
96
+ * {@link Image#getScaledInstance(int, int, int)}), all resultant images
97
+ * generated by imgscalr are of one of two types:
98
+ * <ol>
99
+ * <li>{@link BufferedImage#TYPE_INT_RGB}</li>
100
+ * <li>{@link BufferedImage#TYPE_INT_ARGB}</li>
101
+ * </ol>
102
+ * depending on if the source image utilizes transparency or not.
103
+ * <p/>
104
+ * This is a recommended approach by the Java2D team for dealing with poorly (or
105
+ * non) supported image types. More can be read about this issue <a href=
106
+ * "http://www.mail-archive.com/java2d-interest@capra.eng.sun.com/msg05621.html"
107
+ * >here</a>.
108
+ * <h3>Logging</h3>
109
+ * This class implements all its debug logging via the
86
110
* {@link #log(String, Object...)} method. At this time logging is done directly
87
111
* to <code>System.out</code> via the <code>printf</code> method. This allows
88
112
* the logging to be light weight and easy to capture.
@@ -327,7 +351,7 @@ public static BufferedImage resize(BufferedImage src, Method scalingMethod,
327
351
float ratio = ((float ) currentHeight / (float ) currentWidth );
328
352
329
353
if (DEBUG )
330
- log ("Resizing Source Image [size=%dx%d, orientation=%s, ratio(H/W)=%f] to [targetSize=%dx%d]" ,
354
+ log ("START Resizing Source Image [size=%dx%d, orientation=%s, ratio(H/W)=%f] to [targetSize=%dx%d]" ,
331
355
currentWidth , currentHeight ,
332
356
(ratio <= 1 ? "landscape/square" : "portrait" ), ratio ,
333
357
targetWidth , targetHeight );
@@ -346,6 +370,10 @@ public static BufferedImage resize(BufferedImage src, Method scalingMethod,
346
370
* mangling the result.
347
371
*/
348
372
if (ratio <= 1 ) {
373
+ // First make sure we need to do any work in the first place
374
+ if (targetWidth == src .getWidth ())
375
+ return src ;
376
+
349
377
// Save for detailed logging (this is cheap).
350
378
int originalTargetHeight = targetHeight ;
351
379
@@ -360,6 +388,10 @@ public static BufferedImage resize(BufferedImage src, Method scalingMethod,
360
388
log ("Auto-Corrected targetHeight [from=%d to=%d] to honor image proportions" ,
361
389
originalTargetHeight , targetHeight );
362
390
} else {
391
+ // First make sure we need to do any work in the first place
392
+ if (targetHeight == src .getHeight ())
393
+ return src ;
394
+
363
395
// Save for detailed logging (this is cheap).
364
396
int originalTargetWidth = targetWidth ;
365
397
@@ -436,7 +468,7 @@ public static BufferedImage resize(BufferedImage src, Method scalingMethod,
436
468
437
469
if (DEBUG ) {
438
470
long elapsedTime = System .currentTimeMillis () - startTime ;
439
- log ("Source Image Scaled from [%dx%d] to [%dx%d] in %d ms (approx %f seconds)" ,
471
+ log ("END Source Image Scaled from [%dx%d] to [%dx%d] in %d ms (approx %f seconds)" ,
440
472
currentWidth , currentHeight , targetWidth , targetHeight ,
441
473
elapsedTime , (double ) elapsedTime / (double ) 1000 );
442
474
}
@@ -548,9 +580,32 @@ else if (length <= BALANCED_SPEED_THRESHOLD_PX)
548
580
*/
549
581
protected static BufferedImage scaleImage (BufferedImage src ,
550
582
int targetWidth , int targetHeight , Object interpolationHintValue ) {
583
+ /*
584
+ * Determine the TYPE of image (plain RGB or RGB + Alpha) that we want
585
+ * to render the scaled instance into. We force all rendering results
586
+ * into one of these two types, avoiding the case where a source image
587
+ * is of an unsupported (or poorly supported) format by Java2D and the
588
+ * written results, when attempting to re-create and write out that
589
+ * format, is garbage.
590
+ *
591
+ * Originally reported by Magnus Kvalheim from Movellas when scaling
592
+ * certain GIF and PNG images.
593
+ *
594
+ * More information about Java2D and poorly supported image types:
595
+ * http:/
596
+ * /www.mail-archive.com/java2d-interest@capra.eng.sun.com/msg05621.html
597
+ *
598
+ * Thanks to Morten Nobel for the implementation hint:
599
+ * http://code.google
600
+ * .com/p/java-image-scaling/source/browse/trunk/src/main
601
+ * /java/com/mortennobel/imagescaling/MultiStepRescaleOp.java
602
+ */
603
+ int imageType = (src .getTransparency () == Transparency .OPAQUE ? BufferedImage .TYPE_INT_RGB
604
+ : BufferedImage .TYPE_INT_ARGB );
605
+
551
606
// Setup the rendering resources to match the source image's
552
607
BufferedImage result = new BufferedImage (targetWidth , targetHeight ,
553
- src . getType () );
608
+ imageType );
554
609
Graphics2D resultGraphics = result .createGraphics ();
555
610
556
611
// Scale the image to the new buffer using the specified rendering hint.
0 commit comments