package cn.jeesoft.core.utils;
import javax.imageio.ImageIO;
import cn.jeesoft.core.exception.FileIOException;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* JDiy图片操作工具类.
* 此类封装简化了图片大小获取/缩放调整,水印等常用功能.
* @author 子秋(ziquee) http://www.jdiy.org
*/
@SuppressWarnings({"unused"})
public final class Pic{
private int width = 0;
private int height = 0;
private File file;
private BufferedImage image;
private int opacityType =1;
private Pic() {
}
/**
* 以给定的文件物理路径构造图片处理对象.
* @param file 要处理的图片文件.
*/
public Pic(File file){
this.file = file;
if (!this.file.exists()) throw new FileIOException("要操作的文件不存在或不是一个文件."+file.getPath());
if (this.file.isDirectory()) throw new FileIOException("无法创建实例化,构造方法传入的参数需要是一个文件而非文件夹。");
String fn = file.getName().toLowerCase();
opacityType = fn.endsWith(".png") || fn.endsWith("gif") ?
BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB;
Image src;
try {
src = ImageIO.read(this.file);
} catch (IllegalArgumentException e) {
throw new FileIOException("无法使用嵌入的ICC配置文件,因为ICC文件头己损坏。这是由于您指定的图片文件格式不正确而造成的错误。");
} catch (IOException e) {
throw new FileIOException(e.fillInStackTrace());
}
width = src.getWidth(null);
height = src.getHeight(null);
image = new BufferedImage(width, height, opacityType);
Graphics g = image.createGraphics();
g.drawImage(src, 0, 0, width, height, null);
g.dispose();
}
/**
* 将指定的图片加入到当前图片中的指定位置. 即向图片中打水印.
* @param file 要添加的图片文件。
* @param position 要添加的图片在当前图片中的位置. <br />
* 其取值范围为1-9之间的整数(默认为9)。分别代表:左上、上中、右上、左中、正中、右中、左下、中下、右下
* @return Pic 当前的Pic对象本身.
*/
public Pic add(File file, int position) {
Image src;
try {
src = ImageIO.read(file);
} catch (IllegalArgumentException e) {
throw new FileIOException("无法使用嵌入的ICC配置文件,因为ICC文件头己损坏。这是由于您指定的图片文件格式不正确而造成的错误。");
} catch (IOException e) {
throw new FileIOException(e.fillInStackTrace());
}
int ww = src.getWidth(null);
int hh = src.getHeight(null);
int WW, HH;
switch (position) {
case 1:
WW = 0;
HH = 0;
break;
case 2:
WW = (width - ww) / 2;
HH = 0;
break;
case 3:
WW = width - ww;
HH = 0;
break;
case 4:
WW = 0;
HH = (height - hh) / 2;
break;
case 5:
WW = (width - ww) / 2;
HH = (height - hh) / 2;
break;
case 6:
WW = width - ww;
HH = (height - hh) / 2;
break;
case 7:
WW = 0;
HH = height - hh;
break;
case 8:
WW = (width - ww) / 2;
HH = height - hh;
break;
default:
WW = width - ww;
HH = height - hh;
}
Graphics g = image.createGraphics();
g.drawImage(src, WW, HH, ww, hh, null);
g.dispose();
return this;
}
/**
* 返回当前图片的高度.
* @return int 当前图片的高度值
*/
public int getHeight() {
return height;
}
/**
* 返回当前图片的宽度.
* @return int 当前图片的宽度值
*/
public int getWidth() {
return width;
}
/**
* 将图片等比缩放. (缩放后的图片与原图成等比.) <br />
* <strong>说明:</strong>
* <ol><li>如果参数w和h的值都不为0, 程序会将图片等比缩放,使图片处于最大宽为w,或者最大高为h的限定范围之内.
* 也就是说,由于图片自身的长宽比,和w/h参数的比例可能并不一致,缩放后的图片的宽高并不一定都与w/h参数值相等.</li>
* <li>如果参数w和h中有且只有一个值为0,程序将只以非0的那个边(宽或高)作为参照,将图片等比缩放至指定大小.</li>
* <li>如果两个参数都为0,或者w/h参数与当前图片的尺寸相等,程序将不作任何处理.</li></ol>
* @param w 缩放后的图片宽度(或最大宽度).
* @param h 缩放后的图片高度(或最大高度).
* @return Pic 当前的Pic对象本身.
* @see #resizeBy(int, int, java.awt.Color)
* @see #resizeTo(int, int)
*/
public Pic resizeBy(int w, int h){
if (w == 0 && h == 0 || w==width && h==height) {
return this;
}
int w1 = w, h1 = h;
if (w1 > h1) {
h1 = ((height * w1) / width);
} else {
w1 = ((width * h1) / height);
}
if (w != 0 && h != 0) {
if (w1 > w) {
h1 = (w * h1 / w1);
w1 = w;
} else if (h1 > h) {
w1 = (h * w1 / h1);
h1 = h;
}
}
return resizeTo(w1, h1);
}
/**
* 将图片等比缩放至w,h限定的范围之内,此范围之内空的区域以指定的颜色进行填充.
* 与{@link #resizeBy(int, int)}不同的是,该方法缩小后的图片(为了自尺寸与原图等比)长宽并不一定会等于w,h的值,
* 而此方法缩放后的图片,其长度一定等于w, 宽度一定等于h,但是图片的显示画面仍然与原图保持等比,中间空出来的地方,将会用指定的颜色填充.
* @param w 缩小后的图片宽度
* @param h 缩小后的图片高度
* @param c 空的区域所要填充的颜色.
* @return Pic 当前的Pic对象本身.
* @see #resizeBy(int, int)
* @see #resizeTo(int, int)
*/
public Pic resizeBy(int w, int h, Color c) {
if(w==width && h==height)return this;
resizeBy(w, h);
int L = ((w - width) / 2);
int T = ((h - height) / 2);
BufferedImage image1 = new BufferedImage(w, h, opacityType);
Graphics g = image1.createGraphics();
g.setColor(c);
g.fillRect(0, 0, w, h);
try {
g.drawImage(image, L, T, width, height, null);
image=image1;
width=w;
height=h;
} catch (IllegalArgumentException e) {
throw new FileIOException("无法使用嵌入的ICC配置文件,因为ICC文件头己损坏。这是由于您指定的图片文件格式不正确而造成的错误。");
}
return this;
}
/**
* 将图片收缩或放大至指定尺寸.
* 此方法不保证等比,如果图片原尺寸的比例和传入的参数w/h不成比例,图片将被拉伸变形.
* @param w 缩放后的图片宽度
* @param h 缩放后的图片高度
* @return Pic 当前的Pic对象本身.
* @see #resizeBy(int, int)
* @see #resizeBy(int, int, java.awt.Color)
*/
public Pic resizeTo(int w, int h) {
if(w==width && h==height)return this;
if (w == 0 || h == 0) return resizeBy(w, h);
BufferedImage image1 = new BufferedImage(w, h, opacityType);
Graphics g = image1.createGraphics();
try {
g.drawImage(image, 0, 0, w, h, null);
image=image1;
} catch (IllegalArgumentException e) {
throw new FileIOException("无法使用嵌入的ICC配置文件,因为ICC文件头己损坏。这是由于您指定的图片文件格式不正确而造成的错误。");
}
width = w;
height = h;
return this;
}
/**
* 将处理过的图片另存为文件.
* @param file 要另存成的文件.
*/
public void saveAs(File file){
String path = file.getAbsolutePath();
String ext = path.substring(path.lastIndexOf(".") + 1).toUpperCase();
if (!ext.equals("PNG") && !ext.equals("GIF")) {
ext = "JPEG";
}
try {
FileOutputStream out = new FileOutputStream(file);
ImageIO.write(image, ext, out);
out.close();
} catch (IOException e) {
throw new FileIOException(e.fillInStackTrace());
}
}
/**
* 将处理过的图片保存.
*/
public void save(){
saveAs(file);
}
}