Monday, August 8, 2011

package com.softpower.utils;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Locale;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;


public class ImageUtils {
public static final int IMAGE_UNKNOWN = -1;
public static final int IMAGE_JPEG = 0;
public static final int IMAGE_PNG = 1;
public static final int IMAGE_GIF = 2;

/**
* Resizes an image
*
* @param imgName
* The image name to resize. Must be the complet path to the file
* @param type
* int
* @param maxWidth
* The image's max width
* @param maxHeight
* The image's max height
* @return A resized BufferedImage
*/
public static BufferedImage resizeImage(String imgName, int type, int maxWidth, int maxHeight) {
try {
return resizeImage(ImageIO.read(new File(imgName)), type, maxWidth, maxHeight);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}

/**
* Resizes an image.
*
* @param image
* The image to resize
* @param maxWidth
* The image's max width
* @param maxHeight
* The image's max height
* @return A resized BufferedImage
* @param type
* int
*/
public static BufferedImage resizeImage(BufferedImage image, int type, int maxWidth, int maxHeight) {
Dimension largestDimension = new Dimension(maxWidth, maxHeight);

// Original size
int imageWidth = image.getWidth(null);
int imageHeight = image.getHeight(null);

float aspectRatio = (float) imageWidth / imageHeight;

if (imageWidth > maxWidth || imageHeight > maxHeight) {
if ((float) largestDimension.width / largestDimension.height > aspectRatio) {
largestDimension.width = (int) Math.ceil(largestDimension.height * aspectRatio);
} else {
largestDimension.height = (int) Math.ceil(largestDimension.width / aspectRatio);
}

imageWidth = largestDimension.width;
imageHeight = largestDimension.height;
}

return createHeadlessSmoothBufferedImage(image, type, imageWidth, imageHeight);
}

/**
* Saves an image to the disk.
*
* @param image
* The image to save
* @param toFileName
* The filename to use
* @param type
* The image type. Use ImageUtils.IMAGE_JPEG to save as
* JPEG images, or ImageUtils.IMAGE_PNG to save as PNG.
* @return false if no appropriate writer is found
*/
public static boolean saveImage(BufferedImage image, String toFileName, int type) {
try {
return ImageIO.write(image, type == IMAGE_JPEG ? "jpg" : "png", new File(toFileName));
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
/**
* Saves an image to the disk.
*
* @param image
* The image to save
* @param toFileName
* The filename to use
* @param type
* The image type. Use ImageUtils.IMAGE_JPEG to save as
* JPEG images, or ImageUtils.IMAGE_PNG to save as PNG.
* @return false if no appropriate writer is found
*/
public static boolean saveImage(BufferedImage image, File toFileName, int type) {
try {
return ImageIO.write(image, type == IMAGE_JPEG ? "jpg" : "png", (toFileName));
} catch (IOException e) {
e.printStackTrace();
return false;
}
}

/**
* Compress and save an image to the disk. Currently this method only supports
* JPEG images.
*
* @param image
* The image to save
* @param toFileName
* The filename to use
* @param type
* The image type. Use ImageUtils.IMAGE_JPEG to save as
* JPEG images, or ImageUtils.IMAGE_PNG to save as PNG.
*/
public static void saveCompressedImage(BufferedImage image, String toFileName, int type) {
try {
if (type == IMAGE_PNG) {
throw new UnsupportedOperationException("PNG compression not implemented");
}

Iterator iter = ImageIO.getImageWritersByFormatName("jpg");
ImageWriter writer;
writer = (ImageWriter) iter.next();

ImageOutputStream ios = ImageIO.createImageOutputStream(new File(toFileName));
writer.setOutput(ios);

ImageWriteParam iwparam = new JPEGImageWriteParam(Locale.getDefault());

iwparam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwparam.setCompressionQuality(0.7F);

writer.write(null, new IIOImage(image, null, null), iwparam);

ios.flush();
writer.dispose();
ios.close();
} catch (IOException e) {
e.printStackTrace();
}
}

/**
* Creates a BufferedImage from an Image. This
* method can function on a completely headless system. This especially
* includes Linux and Unix systems that do not have the X11 libraries
* installed, which are required for the AWT subsystem to operate. This method
* uses nearest neighbor approximation, so it's quite fast. Unfortunately, the
* result is nowhere near as nice looking as the
* createHeadlessSmoothBufferedImage method.
*
* @param image
* The image to convert
* @param w
* The desired image width
* @param h
* The desired image height
* @return The converted image
* @param type
* int
*/
public static BufferedImage createHeadlessBufferedImage(BufferedImage image, int type, int width,
int height) {
if (type == ImageUtils.IMAGE_PNG && hasAlpha(image)) {
type = BufferedImage.TYPE_INT_ARGB;
} else {
type = BufferedImage.TYPE_INT_RGB;
}

BufferedImage bi = new BufferedImage(width, height, type);

for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
bi.setRGB(x, y, image.getRGB(x * image.getWidth() / width, y * image.getHeight() / height));
}
}

return bi;
}

/**
* Creates a BufferedImage from an Image. This
* method can function on a completely headless system. This especially
* includes Linux and Unix systems that do not have the X11 libraries
* installed, which are required for the AWT subsystem to operate. The
* resulting image will be smoothly scaled using bilinear filtering.
*
* @param source
* The image to convert
* @param w
* The desired image width
* @param h
* The desired image height
* @return The converted image
* @param type
* int
*/
public static BufferedImage createHeadlessSmoothBufferedImage(BufferedImage source, int type,
int width, int height) {
if (type == ImageUtils.IMAGE_PNG && hasAlpha(source)) {
type = BufferedImage.TYPE_INT_ARGB;
} else {
type = BufferedImage.TYPE_INT_RGB;
}

BufferedImage dest = new BufferedImage(width, height, type);

int sourcex;
int sourcey;

double scalex = (double) width / source.getWidth();
double scaley = (double) height / source.getHeight();

int x1;
int y1;

double xdiff;
double ydiff;

int rgb;
int rgb1;
int rgb2;

for (int y = 0; y < height; y++) {
sourcey = y * source.getHeight() / dest.getHeight();
ydiff = scale(y, scaley) - sourcey;

for (int x = 0; x < width; x++) {
sourcex = x * source.getWidth() / dest.getWidth();
xdiff = scale(x, scalex) - sourcex;

x1 = Math.min(source.getWidth() - 1, sourcex + 1);
y1 = Math.min(source.getHeight() - 1, sourcey + 1);

rgb1 = getRGBInterpolation(source.getRGB(sourcex, sourcey), source.getRGB(x1, sourcey),
xdiff);
rgb2 = getRGBInterpolation(source.getRGB(sourcex, y1), source.getRGB(x1, y1), xdiff);

rgb = getRGBInterpolation(rgb1, rgb2, ydiff);

dest.setRGB(x, y, rgb);
}
}

return dest;
}

private static double scale(int point, double scale) {
return point / scale;
}

private static int getRGBInterpolation(int value1, int value2, double distance) {
int alpha1 = (value1 & 0xFF000000) >>> 24;
int red1 = (value1 & 0x00FF0000) >> 16;
int green1 = (value1 & 0x0000FF00) >> 8;
int blue1 = (value1 & 0x000000FF);

int alpha2 = (value2 & 0xFF000000) >>> 24;
int red2 = (value2 & 0x00FF0000) >> 16;
int green2 = (value2 & 0x0000FF00) >> 8;
int blue2 = (value2 & 0x000000FF);

int rgb = ((int) (alpha1 * (1.0 - distance) + alpha2 * distance) << 24)
| ((int) (red1 * (1.0 - distance) + red2 * distance) << 16)
| ((int) (green1 * (1.0 - distance) + green2 * distance) << 8)
| (int) (blue1 * (1.0 - distance) + blue2 * distance);

return rgb;
}

/**
* Determines if the image has transparent pixels.
*
* @param image
* The image to check for transparent pixel.s
* @return true of false, according to the result
*/
public static boolean hasAlpha(Image image) {
try {
PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
pg.grabPixels();

return pg.getColorModel().hasAlpha();
} catch (InterruptedException e) {
return false;
}
}
}