/*
* regain/Thumbnailer - A file search engine providing plenty of formats (Plugin)
* Copyright (C) 2011 Come_IN Computerclubs (University of Siegen)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact: Come_IN-Team <come_in-team@listserv.uni-siegen.de>
*/
package de.uni_siegen.wineme.come_in.thumbnailer.util;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
import org.apache.log4j.Logger;
import de.uni_siegen.wineme.come_in.thumbnailer.UnsupportedInputFileFormatException;
/**
* Resize an image.
*
* @author Benjamin
* @TODO Comment. Refactor?? (3 lines of code per generation)
*/
public class ResizeImage {
/** The logger for this class */
private static final Logger mLog = Logger.getLogger(ResizeImage.class);
BufferedImage inputImage;
private boolean isProcessed = false;
BufferedImage outputImage;
private int imageWidth;
private int imageHeight;
private int thumbWidth;
private int thumbHeight;
private double resizeRatio = 1.0;
/**
* Scale input image so that width and height is equal (or smaller) to the output size.
* The other dimension will be smaller or equal than the output size.
*/
public static final int RESIZE_FIT_BOTH_DIMENSIONS = 2;
/**
* Scale input image so that width or height is equal to the output size.
* The other dimension will be bigger or equal than the output size.
*/
public static final int RESIZE_FIT_ONE_DIMENSION = 3;
/**
* Do not resize the image. Instead, crop the image (if smaller) or center it (if bigger)
*/
public static final int NO_RESIZE_ONLY_CROP = 4;
/**
* Do not try to scale the image up, only down. If bigger, center it.
*/
public static final int DO_NOT_SCALE_UP = 16;
/**
* If output image is bigger than input image, allow the output to be smaller than expected (the size of the input image)
*/
public static final int ALLOW_SMALLER = 32;
public int resizeMethod = RESIZE_FIT_ONE_DIMENSION;
public int extraOptions = DO_NOT_SCALE_UP;
private int scaledWidth;
private int scaledHeight;
private int offsetX;
private int offsetY;
public ResizeImage(int thumbWidth, int thumbHeight)
{
this.thumbWidth = thumbWidth;
this.thumbHeight = thumbHeight;
}
public void setInputImage(File input) throws IOException
{
BufferedImage image = ImageIO.read(input);
setInputImage(image);
}
public void setInputImage(InputStream input) throws IOException
{
BufferedImage image = ImageIO.read(input);
setInputImage(image);
}
public void setInputImage(BufferedImage input) throws UnsupportedInputFileFormatException
{
if (input == null)
throw new UnsupportedInputFileFormatException("The image reader could not open the file.");
this.inputImage = input;
isProcessed = false;
imageWidth = inputImage.getWidth(null);
imageHeight = inputImage.getHeight(null);
}
public void writeOutput(File output) throws IOException
{
writeOutput(output, "PNG");
}
public void writeOutput(File output, String format) throws IOException
{
if (!isProcessed)
process();
ImageIO.write(outputImage, format, output);
}
private void process()
{
if (imageWidth == thumbWidth && imageHeight == thumbHeight)
outputImage = inputImage;
else
{
calcDimensions(resizeMethod);
paint();
}
isProcessed = true;
}
private void calcDimensions(int resizeMethod)
{
switch (resizeMethod)
{
case RESIZE_FIT_BOTH_DIMENSIONS:
resizeRatio = Math.min(((double) thumbWidth) / imageWidth, ((double) thumbHeight) / imageHeight);
break;
case RESIZE_FIT_ONE_DIMENSION:
resizeRatio = Math.max(((double) thumbWidth) / imageWidth, ((double) thumbHeight) / imageHeight);
break;
case NO_RESIZE_ONLY_CROP:
resizeRatio = 1.0;
break;
}
if ((extraOptions & DO_NOT_SCALE_UP) > 0)
if (resizeRatio > 1.0)
resizeRatio = 1.0;
scaledWidth = (int) Math.round(imageWidth * resizeRatio);
scaledHeight = (int) Math.round(imageHeight * resizeRatio);
if ((extraOptions & ALLOW_SMALLER) > 0) {
if (scaledWidth < thumbWidth && scaledHeight < thumbHeight)
{
thumbWidth = scaledWidth;
thumbHeight = scaledHeight;
}
}
// Center if smaller.
if (scaledWidth < thumbWidth)
offsetX = (thumbWidth - scaledWidth) / 2;
else
offsetX = 0;
if (scaledHeight < thumbHeight)
offsetY = (thumbHeight - scaledHeight) / 2;
else
offsetY = 0;
}
private void paint()
{
outputImage = new BufferedImage(thumbWidth, thumbHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics2D = outputImage.createGraphics();
// Fill background with white color
graphics2D.setBackground(Color.WHITE);
graphics2D.setPaint(Color.WHITE);
graphics2D.fillRect(0, 0, thumbWidth, thumbHeight);
// Enable smooth, high-quality resampling
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
ThumbnailReadyObserver observer = new ThumbnailReadyObserver(Thread.currentThread());
boolean scalingComplete = graphics2D.drawImage(inputImage, offsetX, offsetY, scaledWidth, scaledHeight, observer);
if (!scalingComplete && observer != null)
{
// ImageObserver must wait for ready
if (mLog.isDebugEnabled())
throw new RuntimeException("Scaling is not yet complete!");
else
{
mLog.warn("ResizeImage: Scaling is not yet complete!");
while(!observer.ready)
{
System.err.println("Waiting .4 sec...");
try {
Thread.sleep(400);
} catch (InterruptedException e) {
}
}
}
}
graphics2D.dispose();
}
}