Skip to content

Commit 7d39c7c

Browse files
author
Riyad Kalla
committed
Fixed issue where scaling of lesser or poorly supported file types in Java2D (e.g. GIF)
produce terrible-looking results. Now all scaled results look good. This was fixed for all quality levels by forcing all resultant images into either an RGB or RGBA image type.
1 parent 4ee80c5 commit 7d39c7c

File tree

1 file changed

+59
-4
lines changed

1 file changed

+59
-4
lines changed

src/main/java/com/thebuzzmedia/imgscalr/Scalr.java

+59-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
package com.thebuzzmedia.imgscalr;
1717

1818
import java.awt.Graphics2D;
19+
import java.awt.Image;
1920
import java.awt.RenderingHints;
21+
import java.awt.Transparency;
2022
import java.awt.image.BufferedImage;
2123

2224
/**
@@ -81,8 +83,30 @@
8183
* on any of the <em>source images</em> passed in by calling code; it is up to
8284
* the original caller to dispose of their source images when they are no longer
8385
* 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.
8493
* <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
86110
* {@link #log(String, Object...)} method. At this time logging is done directly
87111
* to <code>System.out</code> via the <code>printf</code> method. This allows
88112
* the logging to be light weight and easy to capture.
@@ -327,7 +351,7 @@ public static BufferedImage resize(BufferedImage src, Method scalingMethod,
327351
float ratio = ((float) currentHeight / (float) currentWidth);
328352

329353
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]",
331355
currentWidth, currentHeight,
332356
(ratio <= 1 ? "landscape/square" : "portrait"), ratio,
333357
targetWidth, targetHeight);
@@ -346,6 +370,10 @@ public static BufferedImage resize(BufferedImage src, Method scalingMethod,
346370
* mangling the result.
347371
*/
348372
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+
349377
// Save for detailed logging (this is cheap).
350378
int originalTargetHeight = targetHeight;
351379

@@ -360,6 +388,10 @@ public static BufferedImage resize(BufferedImage src, Method scalingMethod,
360388
log("Auto-Corrected targetHeight [from=%d to=%d] to honor image proportions",
361389
originalTargetHeight, targetHeight);
362390
} else {
391+
// First make sure we need to do any work in the first place
392+
if (targetHeight == src.getHeight())
393+
return src;
394+
363395
// Save for detailed logging (this is cheap).
364396
int originalTargetWidth = targetWidth;
365397

@@ -436,7 +468,7 @@ public static BufferedImage resize(BufferedImage src, Method scalingMethod,
436468

437469
if (DEBUG) {
438470
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)",
440472
currentWidth, currentHeight, targetWidth, targetHeight,
441473
elapsedTime, (double) elapsedTime / (double) 1000);
442474
}
@@ -548,9 +580,32 @@ else if (length <= BALANCED_SPEED_THRESHOLD_PX)
548580
*/
549581
protected static BufferedImage scaleImage(BufferedImage src,
550582
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+
551606
// Setup the rendering resources to match the source image's
552607
BufferedImage result = new BufferedImage(targetWidth, targetHeight,
553-
src.getType());
608+
imageType);
554609
Graphics2D resultGraphics = result.createGraphics();
555610

556611
// Scale the image to the new buffer using the specified rendering hint.

0 commit comments

Comments
 (0)