package message.utils;
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifDirectory;
import com.drew.metadata.exif.ExifReader;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import com.sun.jimi.core.Jimi;
import com.sun.jimi.core.JimiWriter;
import com.sun.jimi.core.options.JPGOptions;
import org.apache.commons.lang.exception.NestableRuntimeException;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.*;
import java.io.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* 图片处理工具类(需要整理)
*
* @author sunhao(sunhao.java@gmail.com)
* @version V1.0
* @createTime 2012-3-17 上午03:06:14
*/
public class ImageUtils {
/**
* EXIF版本
*/
public static final String EXIF_VERSION = "exif_version";
/**
* 相机品牌
*/
public static final String CAMERA_PRODUCT = "camera_product";
/**
* 相机型号
*/
public static final String CAMERA_VERSION = "camera_version";
/**
* 光 圈 值
*/
public static final String APERTURE_VALUE = "aperture_value";
/**
* 快门
*/
public static final String SHUTTER = "shutter";
/**
* 感 光 度
*/
public static final String PHOTOSENSITIVE_DEGREE = "photosensitive_degree";
/**
* 软件
*/
public static final String SOFTWARE_VERSION = "software_version";
/**
* 原始拍摄时间
*/
public static final String ORIGINAL_TIME_TAKEN = "original_time_taken";
/**
* 数字化时间
*/
public static final String DIGITIZED_TIME = "digitized_time";
/**
* 方向
*/
public static final String CAMERA_ORIENTATION = "camera_orientation";
/**
* 宽度
*/
public static final String PHOTO_WIDTH = "photo_width";
/**
* 高度
*/
public static final String PHOTO_HEIGHT = "photo_height";
/**
* 水平分辨率
*/
public static final String X_RESOLUTION = "x_resolution";
/**
* 垂直分辨率
*/
public static final String Y_RESOLUTION = "y_resolution";
/**
* 曝光偏差
*/
public static final String EXPOSURE_BIAS = "exposure_bias";
/**
* 私有化构造器
*/
private ImageUtils(){}
/**
* 按宽的比例更改图片的大小
*
* @param filePath 图片路径
* @param width 需要改变图片的宽度
* @param destPath 目标路径
* @return
* @throws Exception
*/
public static File getRatioWidth(String filePath, int width, String destPath) throws Exception {
File f = new File(filePath);
BufferedImage bi = ImageIO.read(f);
double wRatio = (new Integer(width)).doubleValue() / bi.getWidth(); // 宽度的比例
int height = (int) (wRatio * bi.getHeight()); // 图片转换后的高度
Image image = bi.getScaledInstance(width, height, Image.SCALE_SMOOTH); // 设置图像的缩放大小
AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(wRatio, wRatio), null); // 设置图像的缩放比例
image = op.filter(bi, null);
File zoomFile = new File(destPath);
File file = null;
try {
ImageIO.write((BufferedImage) image, "jpg", zoomFile);
file = new File(zoomFile.getPath());
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
/**
* 按高的比例更改图片大小
*
* @param filePath 图片路径
* @param height 需要改变图片的高度
* @param destPath 目标路径
* @return
* @throws Exception
*/
public static File getRatioHeight(String filePath, int height, String destPath) throws Exception {
File f = new File(filePath);
BufferedImage bi = ImageIO.read(f);
double hRatio = (new Integer(height)).doubleValue() / bi.getHeight(); // 高度的比例
int width = (int) (hRatio * bi.getWidth()); // 图片转换后的高度
Image image = bi.getScaledInstance(width, height, Image.SCALE_SMOOTH); // 设置图像的缩放大小
AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(hRatio, hRatio), null); // 设置图像的缩放比例
image = op.filter(bi, null);
File zoomFile = new File(destPath);
File file = null;
try {
ImageIO.write((BufferedImage) image, "jpg", zoomFile);
file = new File(zoomFile.getPath());
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
/**
* 按输入的任意宽高改变图片的大小
*
* @param filePath 图片路径
* @param width 需要改变图片的宽度
* @param height 需要改变图片的高度
* @param destPath 目标路径
* @return
* @throws Exception
*/
public static File getFixedIcon(String filePath, int width, int height, String destPath) throws Exception {
File f = new File(filePath);
BufferedImage bi = ImageIO.read(f);
double wRatio = (new Integer(width)).doubleValue() / bi.getWidth(); // 宽度的比例
double hRatio = (new Integer(height)).doubleValue() / bi.getHeight(); // 高度的比例
Image image = bi.getScaledInstance(width, height, Image.SCALE_SMOOTH); // 设置图像的缩放大小
AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(wRatio, hRatio), null); // 设置图像的缩放比例
image = op.filter(bi, null);
File zoomFile = new File(destPath);
File file = null;
try {
ImageIO.write((BufferedImage) image, "jpg", zoomFile);
file = new File(zoomFile.getPath());
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
/**
* 根据图像实际宽高和给定宽高,通过比例计算应该得到图像的宽高
*
* @param width 实际图像宽度
* @param height 实际图像高度
* @param destWidth 给定宽度
* @param destHeight 给定高度
* @return new int[]{应得图像宽度, 应得图像高度}
*/
public static int[] getSizeByPercent(int width, int height, int destWidth, int destHeight){
int w = 0;
int h = 0;
/**
* 目标图像宽与源图像宽的比例
* 目标图像高与源图像高的比例
*/
double wPercent = (double) destWidth / width;
double hPercent = (double) destHeight / height;
if (wPercent > hPercent) {
wPercent = hPercent;
w = (int) (wPercent * width);
h = destHeight;
} else {
hPercent = wPercent;
w = destWidth;
h = (int) (hPercent * height);
}
return new int[]{w, h};
}
/**
* 给图片添加文字水印
*
* @param filePath 需要添加水印的图片的路径
* @param markContent 水印的文字
* @param markContentColor 水印文字的颜色
* @param fontSize 字体大小
* @param location 位置(1、左上角;2、右上角;3、右下角;4、左下角;5、中间)
* @return 布尔类型
* @throws Exception
*/
public static boolean addStringMark(String filePath, String markContent, Color markContentColor, int fontSize,
int location) throws Exception {
ImageIcon imgIcon = new ImageIcon(filePath);
Image theImg = imgIcon.getImage();
int width = theImg.getWidth(null);
int height = theImg.getHeight(null);
BufferedImage bimage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = bimage.createGraphics();
g.setColor(markContentColor);
g.setBackground(Color.white);
g.drawImage(theImg, 0, 0, null);
g.setFont(new Font("楷体", Font.PLAIN, fontSize)); // 字体、字型、字号
int length = 0;
char[] tmp = markContent.toCharArray();
String en = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`~!@#$%^&*()-_+=[]{};:'\",.<>?0123456789";
String flag_cn = "·~!¥×()——『』【】;:‘“,。?《》";
for(char t : tmp){
if (org.apache.commons.lang.StringUtils.contains(en, t)) {
length += fontSize / 2;
} else if (org.apache.commons.lang.StringUtils.contains(flag_cn, t)) {
length += fontSize;
} else {
length += fontSize;
}
}
length += 10;
int w,h;
switch(location){
case 1:
w = 5;
h = fontSize;
break;
case 2:
w = width - length;
h = fontSize;
break;
case 3:
w = width - length;
h = height - 10;
break;
case 4:
w = 5;
h = height - 10;
break;
case 5:
w = (width - length) / 2;
h = (height - fontSize) / 2;
break;
default:
throw new Exception("没有位置!");
}
g.drawString(markContent, w, h); // 画文字
g.dispose();
try {
FileOutputStream out = new FileOutputStream(filePath); // 先用一个特定的输出文件名
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bimage);
param.setQuality(7, true);
encoder.encode(bimage, param);
out.close();
} catch (Exception e) {
return false;
}
return true;
}
/**
* 给图片添加图像水印
*
* @param filePath 需要添加水印的图片的路径
* @param markPath 水印图片路径
* @param location 位置(1、左上角;2、右上角;3、右下角;4、左下角;5、中间)
* @return 布尔类型
* @throws Exception
*/
public static boolean addImageMark(String filePath, String markPath, int location) throws Exception {
// 要处理的原始图片
ImageIcon icoInput = new ImageIcon(filePath);
Image imgInput = icoInput.getImage();
int width = imgInput.getWidth(null);
int height = imgInput.getHeight(null);
BufferedImage buffInput = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
// 要添加上来的水印
ImageIcon icoADD = new ImageIcon(markPath);
Image imgADD = icoADD.getImage();
int w = imgADD.getWidth(null);
int h = imgADD.getHeight(null);
// 绘图
Graphics2D g = buffInput.createGraphics();
g.drawImage(imgInput, 0, 0, null);
int x,y;
switch(location){
case 1:
x = 10;
y = 10;
break;
case 2:
x = width - w - 10;
y = 10;
break;
case 3:
x = width - w - 10;
y = height - h - 10;
break;
case 4:
x = 10;
y = height - h - 10;
break;
case 5:
x = (width - w) / 2;
y = (height - h) / 2;
break;
default:
throw new Exception("没有位置!");
}
// 下面代码的前面五个参数:图片,x坐标,y坐标,图片宽度,图片高度
g.drawImage(imgADD, x, y, w, h, null);
g.dispose();
try {
FileOutputStream out = new FileOutputStream(filePath);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder
.getDefaultJPEGEncodeParam(buffInput);
param.setQuality(7, true);
encoder.encode(buffInput, param);
out.close();
} catch (Exception e) {
return false;
}
return true;
}
/**
* 将颜色转换成RGB值
*
* @param color 必须是#123456这样的格式
* @return
*/
public static int[] converColorToRGB(String color){
if(StringUtils.isEmpty(color)){
return null;
}
if(color.startsWith("#")){
color = color.substring(1);
}
String r = color.substring(0, 2);
String g = color.substring(2, 4);
String b = color.substring(4, 6);
int red = NumberUtils.hex16To10(r);
int green = NumberUtils.hex16To10(g);
int blue = NumberUtils.hex16To10(b);
return new int[]{red, green, blue};
}
/**
* 将图片灰化
*
* @param filePath 需要灰化图片的路径
* @param destPath 目标路径
* @param destFileName 目标文件名
*/
public static void toGray(String filePath, String destPath, String destFileName) throws Exception {
File file = new File(filePath);
if(!file.exists()){
throw new FileNotFoundException("file is not exist!");
}
toGray(new FileInputStream(file), destPath, destFileName);
}
/**
* 将图片灰化
*
* @param is 文件流
* @param destPath 目标路径
* @param destFileName 目标文件名
* @throws Exception
*/
private static void toGray(InputStream is, String destPath, String destFileName) throws Exception {
if(is == null){
throw new FileNotFoundException("InputStream is null!");
}
File dest = new File(destPath);
if(!dest.isDirectory()){
throw new NestableRuntimeException("dest path '{" + destPath + "}' is not a folder!");
}
if(!dest.exists())
dest.mkdir();
Image image = ImageIO.read(is);
Image grayImage = getGrayImage(image);
JPGOptions options = new JPGOptions();
JimiWriter writer = Jimi.createJimiWriter(destPath + "/" + destFileName);
writer.setSource(grayImage);
writer.setOptions(options);
writer.putImage(destPath + "/" + destFileName);
}
/**
* 获取灰化后的图片
*
* @param image 原图片
* @return
*/
public static Image getGrayImage(Image image){
Image grayImage = null;
int w = image.getWidth(null);
int h = image.getHeight(null);
int[] pixels = new int[w * h];
getPixels(image, 0, 0, w, h, pixels);
grayImage = createImage(new MemoryImageSource(w, h, pixels, 0, w));
return grayImage;
}
/**
* 获取原图灰化后每个像素上的RGB值(核心灰化算法)
*
* @param image 原图
* @param x x轴
* @param y y轴
* @param w 宽度
* @param h 高度
* @param pixels RGB点阵
*/
private static void getPixels(Image image, int x, int y, int w, int h, int[] pixels) {
PixelGrabber pg = new PixelGrabber(image, x, y, w, h, pixels, 0, w);
try {
pg.grabPixels();
} catch (InterruptedException e) {
System.err.print("Interrupted waiting for pixels!");
e.printStackTrace();
return;
}
for (int i = 0; i < h; ++i)
for (int j = 0; j < w; ++j) {
int l = pixels[(i * w + j)];
if (l != 0) {
int gray = (int) ((l >> 16 & 0xFF) * 0.29999999999999999D);
gray += (int) ((l >> 8 & 0xFF) * 0.58999999999999997D);
gray += (int) ((l & 0xFF) * 0.11D);
pixels[(i * w + j)] = (0xFF000000 | gray << 16 | gray << 8 | gray);
} else {
pixels[(i * w + j)] = -65794;
}
}
}
/**
* Creates an image from the specified image producer.
* @param producer the image producer
* @return the image produced
* @since JDK1.0
*/
private static Image createImage(ImageProducer producer) {
return Toolkit.getDefaultToolkit().createImage(producer);
}
/**
* 获取图片的EXIF信息
*
* @param file 图片文件
* @return
*/
public static Map<String, Object> getImageEXIF(File file) throws FileNotFoundException, JpegProcessingException {
if(file == null || !file.exists()){
return Collections.emptyMap();
}
return getImageEXIF(new FileInputStream(file));
}
/**
* 获取图片的EXIF信息
*
* @param filePath 图片文件路径
* @return
*/
public static Map<String, Object> getImageEXIF(String filePath) throws FileNotFoundException, JpegProcessingException {
if(StringUtils.isEmpty(filePath)){
return Collections.emptyMap();
}
return getImageEXIF(new File(filePath));
}
/**
* 获取图片的EXIF信息(key值上在类头定义的)
*
* @param is 图片文件流
* @return
*/
public static Map<String, Object> getImageEXIF(InputStream is) throws JpegProcessingException {
if(is == null || !(is instanceof FileInputStream)){
return Collections.emptyMap();
}
ExifReader er = new ExifReader(is);
Metadata exif = er.extract();
Iterator itr = exif.getDirectoryIterator();
int i = 1;
Map<String, Object> parmas = new HashMap<String, Object>();
while (itr.hasNext() && i <= 1) {
Directory directory = (Directory) itr.next();
parmas.put(EXIF_VERSION, directory.getString(ExifDirectory.TAG_EXIF_VERSION));
parmas.put(CAMERA_PRODUCT, directory.getString(ExifDirectory.TAG_MAKE));
parmas.put(CAMERA_VERSION, directory.getString(ExifDirectory.TAG_MODEL));
parmas.put(APERTURE_VALUE, directory.getString(ExifDirectory.TAG_FNUMBER));
parmas.put(SHUTTER, directory.getString(ExifDirectory.TAG_EXPOSURE_TIME));
parmas.put(PHOTOSENSITIVE_DEGREE, directory.getString(ExifDirectory.TAG_ISO_EQUIVALENT));
parmas.put(SOFTWARE_VERSION, directory.getString(ExifDirectory.TAG_SOFTWARE));
parmas.put(ORIGINAL_TIME_TAKEN, directory.getString(ExifDirectory.TAG_DATETIME_ORIGINAL));
parmas.put(DIGITIZED_TIME, directory.getString(ExifDirectory.TAG_DATETIME_DIGITIZED));
parmas.put(CAMERA_ORIENTATION, directory.getString(ExifDirectory.TAG_ORIENTATION));
parmas.put(PHOTO_WIDTH, directory.getString(ExifDirectory.TAG_EXIF_IMAGE_WIDTH));
parmas.put(PHOTO_HEIGHT, directory.getString(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT));
parmas.put(X_RESOLUTION, directory.getString(ExifDirectory.TAG_X_RESOLUTION));
parmas.put(Y_RESOLUTION, directory.getString(ExifDirectory.TAG_Y_RESOLUTION));
parmas.put(EXPOSURE_BIAS, directory.getString(ExifDirectory.TAG_EXPOSURE_BIAS));
i++;
}
return parmas;
}
}