/*
* 创建日期 2006-1-14
*/
package com.aggrepoint.utils;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.Random;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.stream.MemoryCacheImageOutputStream;
import org.imgscalr.Scalr;
/**
* @author Yang Jiang Ming
*
* 图片处理功能集合
*/
public class ImageUtils {
private static char[] m_chars = { '3', '4', '5', '6', '7', '8', '9', 'A',
'B', 'C', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'R',
'S', 'T', 'V', 'W', 'X', 'Y' };
private static double PI2 = java.lang.Math.PI * 2;
private static Random m_ran = new Random();
public static double getRandomDouble(double lo, double hi) {
return lo + ((hi - lo + 1) * m_ran.nextFloat());
}
public static int getRandomInt(int lo, int hi) {
return lo + (int) ((hi - lo + 1) * m_ran.nextFloat());
}
public static String getRandomNumber(int len) {
StringBuffer sb = new StringBuffer();
int p;
for (int i = 0; i < len; i++) {
p = getRandomInt(0, m_chars.length);
if (p < 0)
p = 0;
if (p >= m_chars.length)
p = m_chars.length - 1;
sb.append(m_chars[p]);
}
return sb.toString();
}
public static BufferedImage readImage(File file) throws IOException {
try {
return ImageIO.read(file);
} catch (IOException e) {
String name = file.getName().toUpperCase();
if (name.endsWith(".JPG") || name.endsWith(".JPEG")) { // 可能是CMYK,转换为RGB
// 使用这个简单的方案,但是转换结果颜色不对:
// http://stackoverflow.com/questions/2408613/problem-reading-jpeg-image-using-imageio-readfile-file
// 这个方案看起来更完整,有点复杂暂时不用:
// http://stackoverflow.com/questions/3123574/how-to-convert-from-cmyk-to-rgb-in-java-correctly
// Find a suitable ImageReader
Iterator<ImageReader> readers = ImageIO
.getImageReadersByFormatName("JPEG");
ImageReader reader = null;
while (readers.hasNext()) {
reader = (ImageReader) readers.next();
if (reader.canReadRaster()) {
break;
}
}
// Stream the image file (the original CMYK image)
ImageInputStream input = ImageIO.createImageInputStream(file);
reader.setInput(input);
// Read the image raster
Raster raster = reader.readRaster(0, null);
// Create a new RGB image
BufferedImage bi = new BufferedImage(raster.getWidth(),
raster.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
// Fill the new image with the old raster
bi.getRaster().setRect(raster);
return bi;
}
throw e;
}
}
public static int writeImage(String dest, BufferedImage bufferedImage,
float quality) throws IOException {
// extracts extension of output file
String formatName = dest.substring(dest.lastIndexOf(".") + 1);
File output = new File(dest);
if (formatName.equalsIgnoreCase("jpg")
|| formatName.equalsIgnoreCase("jpeg")) {
FileOutputStream fos = new FileOutputStream(output);
Iterator<ImageWriter> iterator = ImageIO
.getImageWritersByFormatName(formatName);
ImageWriter imageWriter = iterator.next();
ImageWriteParam imageWriteParam = imageWriter
.getDefaultWriteParam();
imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
imageWriteParam.setCompressionQuality(quality);
ImageOutputStream imageOutputStream = new MemoryCacheImageOutputStream(
fos);
imageWriter.setOutput(imageOutputStream);
IIOImage iioimage = new IIOImage(bufferedImage, null, null);
imageWriter.write(null, iioimage, imageWriteParam);
imageOutputStream.flush();
} else {
ImageIO.write(bufferedImage, formatName, output);
}
return (int) output.length();
}
/**
* 将源图片缩放为指定的尺寸大小
*
* @param src
* @param dest
* @param width
* @param height
* @throws IOException
*/
public static int resizeImage(BufferedImage inputImage, String dest,
int width, int height, float quality) throws IOException {
BufferedImage outputImage = Scalr.resize(inputImage,
Scalr.Method.QUALITY, Scalr.Mode.AUTOMATIC, width, height,
Scalr.OP_ANTIALIAS);
return writeImage(dest, outputImage, 0.9f);
}
public static int resizeImage(BufferedImage inputImage, String dest,
int width, int height) throws IOException {
return resizeImage(inputImage, dest, width, height, 0.9f);
}
public static int resizeImage(String src, String dest, int width, int height)
throws Exception {
return resizeImage(readImage(new File(src)), dest, width, height);
}
/**
* 将源图片按比例缩放为指定的尺寸大小
*
* @param srcImg
* @param dest
* @param width
* @param height
* @throws IOException
*/
public static int[] shrinkImage(BufferedImage srcImg, String dest,
int width, int height) throws IOException {
int w = srcImg.getWidth(null);
int h = srcImg.getHeight(null);
if (w <= width && h <= height) {
width = w;
height = h;
} else {
double r1 = (double) width / (double) w;
double r2 = (double) height / (double) h;
if (r1 > r2) {
width = (int) (w * r2);
height = (int) (h * r2);
} else {
width = (int) (w * r1);
height = (int) (h * r1);
}
if (width <= 0)
width = 1;
if (height <= 0)
height = 1;
}
int size = resizeImage(srcImg, dest, width, height);
return new int[] { width, height, size };
}
public static int[] shrinkImage(String src, String dest, int width,
int height) throws IOException {
return shrinkImage(readImage(new File(src)), dest, width, height);
}
/**
* 扭曲图片
*
* @param srcBmp
* @param bXDir
* @return
*/
public static BufferedImage twistImage(BufferedImage srcBmp, int width,
int height, boolean bXDir) {
double dMultValue = getRandomDouble(1, 3);
double dPhase = getRandomDouble(0, PI2);
if (width > srcBmp.getWidth())
width = srcBmp.getWidth();
if (height > srcBmp.getHeight())
height = srcBmp.getHeight();
BufferedImage destBmp = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics g = destBmp.getGraphics();
// 设定背景色
g.setColor(Color.white);
g.fillRect(0, 0, width, height);
// 画边框
g.setColor(Color.black);
g.drawRect(0, 0, width - 1, height - 1);
g.dispose();
double dBaseAxisLen = bXDir ? (double) height : (double) width;
for (int i = 1; i < width - 1; i++) {
for (int j = 1; j < height - 1; j++) {
double dx = 0;
dx = bXDir ? (PI2 * (double) j) / dBaseAxisLen
: (PI2 * (double) i) / dBaseAxisLen;
dx += dPhase;
double dy = Math.sin(dx);
// 取得当前点的颜色
int nOldX = 0, nOldY = 0;
nOldX = bXDir ? i + (int) (dy * dMultValue) : i;
nOldY = bXDir ? j : j + (int) (dy * dMultValue);
int color = srcBmp.getRGB(i, j);
if (nOldX >= 1 && nOldX < width - 1 && nOldY >= 1
&& nOldY < height - 1) {
destBmp.setRGB(nOldX, nOldY, color);
}
}
}
return destBmp;
}
/**
* 生成验证码图片
*
* @param rand
* @param size
* @return
*/
public static BufferedImage genRandomImage(String rand, int size) {
BufferedImage image = new BufferedImage(100, 100,
BufferedImage.TYPE_INT_RGB);
Font font = new Font("Courier New", Font.BOLD, size);
// 获取图形上下文
Graphics2D g = image.createGraphics();
Rectangle2D rect = font.getStringBounds(rand, g.getFontRenderContext());
// 设定背景色
g.setColor(Color.white);
g.fillRect(0, 0, image.getWidth(), image.getHeight());
// 将验证码显示到图象中
g.setColor(Color.black);
g.setFont(font);
g.drawString(rand, 2, (int) rect.getHeight() - 2);
// 图象生效
g.dispose();
// 随机产生干扰点
for (int i = 0; i < 500; i++)
image.setRGB(m_ran.nextInt(image.getWidth()),
m_ran.nextInt(image.getWidth()), 0);
return twistImage(image, (int) rect.getWidth() + 4,
(int) rect.getHeight() + 4, true);
}
/**
* 将图片顺时针旋转90度
*
* @param src
* @return
*/
public static BufferedImage roate90(BufferedImage src) {
int width = src.getWidth();
int height = src.getHeight();
BufferedImage bRotate = new BufferedImage(height, width, src.getType());
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
bRotate.setRGB(height - 1 - y, x, src.getRGB(x, y));
return bRotate;
}
}