package net.coobird.thumbnailator.resizers; import java.awt.AlphaComposite; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.util.Collections; import java.util.Map; /** * A {@link Resizer} which performs resizing operations by using * progressive bilinear scaling. *
* The resizing technique used in this class is based on the technique * discussed in Chapter 4: Images of * Filthy Rich Clients * by Chet Haase and Romain Guy. *
* The actual implemenation of the technique is independent of the code which
* is provided in the book.
*
* @author coobird
*
*/
public class ProgressiveBilinearResizer extends AbstractResizer
{
/**
* Instantiates a {@link ProgressiveBilinearResizer} with default
* rendering hints.
*/
public ProgressiveBilinearResizer()
{
this(Collections.
* If the source and/or destination image is {@code null}, then a
* {@link NullPointerException} will be thrown.
*
* @param srcImage The source image.
* @param destImage The destination image.
*
* @throws NullPointerException When the source and/or the destination
* image is {@code null}.
*/
@Override
public void resize(BufferedImage srcImage, BufferedImage destImage)
throws NullPointerException
{
super.performChecks(srcImage, destImage);
int currentWidth = srcImage.getWidth();
int currentHeight = srcImage.getHeight();
final int targetWidth = destImage.getWidth();
final int targetHeight = destImage.getHeight();
// If multi-step downscaling is not required, perform one-step.
if ((targetWidth * 2 >= currentWidth) && (targetHeight * 2 >= currentHeight))
{
Graphics2D g = destImage.createGraphics();
g.drawImage(srcImage, 0, 0, targetWidth, targetHeight, null);
g.dispose();
return;
}
// Temporary image used for in-place resizing of image.
BufferedImage tempImage = new BufferedImage(
currentWidth,
currentHeight,
destImage.getType()
);
Graphics2D g = tempImage.createGraphics();
g.setRenderingHints(RENDERING_HINTS);
g.setComposite(AlphaComposite.Src);
/*
* Determine the size of the first resize step should be.
* 1) Beginning from the target size
* 2) Increase each dimension by 2
* 3) Until reaching the original size
*/
int startWidth = targetWidth;
int startHeight = targetHeight;
while (startWidth < currentWidth && startHeight < currentHeight)
{
startWidth *= 2;
startHeight *= 2;
}
currentWidth = startWidth / 2;
currentHeight = startHeight / 2;
// Perform first resize step.
g.drawImage(srcImage, 0, 0, currentWidth, currentHeight, null);
// Perform an in-place progressive bilinear resize.
while ( (currentWidth >= targetWidth * 2) && (currentHeight >= targetHeight * 2) )
{
currentWidth /= 2;
currentHeight /= 2;
if (currentWidth < targetWidth)
{
currentWidth = targetWidth;
}
if (currentHeight < targetHeight)
{
currentHeight = targetHeight;
}
g.drawImage(
tempImage,
0, 0, currentWidth, currentHeight,
0, 0, currentWidth * 2, currentHeight * 2,
null
);
}
g.dispose();
// Draw the resized image onto the destination image.
Graphics2D destg = destImage.createGraphics();
destg.drawImage(tempImage, 0, 0, targetWidth, targetHeight, 0, 0, currentWidth, currentHeight, null);
destg.dispose();
}
}