在做前前端项目的时候,由于业务图片是通过ftp资源进行管理,所以前端刚开始获取图片,都是在controller层调用service进行ftp图片资源访问,然后进行格式处理后,通过response返回图片资源。后来发现,这样太消耗系统的性能了,最好的方式就是传输的是网站图片的静态资源。所以,开始自己尝试着开发图片服务器的分离系统。
先说明一下我自己对于图片处理的一些业务需求想法:项目的网站是做一个拍卖交易平台,目前主要是书画方面。在后台进行管理,前端进行显示,前后段分离的。在前台,对于同一个书画,会有多个页面显示,每个页面是显示的图片大小,前台的设计人员设计的也都不一样,包括书画本身,高款也都是千奇百怪的。而我,有不想对于每一个页面,都在后台进行上传与它想匹配的图片,那样一来,不仅工作量庞大,而且开发起来的效率也低。于是我想到的是,在后台只上传一次图片,然后所有的网站(包括后台)都是在图片服务器进行图片的获取(也就是图片的网络地址为单独的域名与单独的服务器),然后传输不同的参数,服务器就对原图计算生成对应的缓存图片,并给定一个唯一的图片Url Hash文件名。然后返回生成的缓存文件,当有相同的规格的图片请求时,就可以直接返回已经缓存的静态图片资源(如image.xxx.com/images/xxx.png)。于是,便设计出如下的图片服务器架构:
为方便开发人员传输获取图片的格式条件,我提供一下的vo类与factory类ImageCondition
代码1:ImageCondition.java
import java.io.Serializable;
/**
* 获取图片的条件
*
* path :String 待获取的图像文件在FTP服务器上的全路径
* alpha : float 图片的透明度(0.0到1.0之间的float值,默认1.0)
* scale : int 对图像进行缩放处理,小于100为缩小,大于100为放大
* width : int 指定图像的输出宽度
* height : int 指定图像的输出高度
* sign : false:不添加版权水印 默认true (小于100 * 50 的不加水印)
* signAlpha : float 水印的透明度(0.0到1.0之间的float值,默认1.0)
*
* 注意:
* 1、width与height成对出现才会生效
* 2、如果指定了width和height,那么scale参数将会失效
*
* Copyright 2014-2015 the original BZTWT
* Created by QianLong on 2014/7/9 0009.
*/
public class ImageCondition implements Serializable {
private String path;
private float alpha;
private int scale;
private int width;
private int height;
private boolean sign;
private float signAlpha;
private boolean recommentSign;
public boolean isRecommentSign() {
return recommentSign;
}
public void setRecommentSign(boolean recommentSign) {
this.recommentSign = recommentSign;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public float getAlpha() {
return alpha;
}
public void setAlpha(float alpha) {
this.alpha = alpha;
}
public int getScale() {
return scale;
}
public void setScale(int scale) {
this.scale = scale;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public boolean isSign() {
return sign;
}
public void setSign(boolean sign) {
this.sign = sign;
}
public float getSignAlpha() {
return signAlpha;
}
public void setSignAlpha(float signAlpha) {
this.signAlpha = signAlpha;
}
}
代码2:ImageConditionFactory.java :
import com.cqcae.vo.ImageCondition;
/**
* 图片条件值类工厂
* 本工厂类返回常用的一些图片条件值类
* 若需要创建拥有透明度(图片透明度或版权水印透明度)的图片条件,
* 请手动新建ImageCondition实例
* Copyright 2014-2015 the original BZTWT
* Created by QianLong on 2014/7/9 0009.
*/
public class ImageConditionFactory {
/**
* 返回原图(默认带有版权水印)
* @param path
* @return
*/
public static ImageCondition getNativeImage(String path){
ImageCondition imageCondition = new ImageCondition();
imageCondition.setPath(path);
imageCondition.setSign(true);
return imageCondition;
}
/**
* 返回不带水印的原图
* @param path
* @return
*/
public static ImageCondition getNativeImageNoSign(String path){
ImageCondition imageCondition = new ImageCondition();
imageCondition.setPath(path);
imageCondition.setSign(false);
return imageCondition;
}
/**
* 返回指定高宽的图片条件(默认带有版权水印)
* @param path
* @param width
* @param height
* @return
*/
public static ImageCondition getImageCondition(String path,int width,int height){
ImageCondition imageCondition = new ImageCondition();
imageCondition.setPath(path);
imageCondition.setWidth(width);
imageCondition.setHeight(height);
imageCondition.setSign(true);
return imageCondition;
}
/**
* 返回没有版权水印的指定高宽的图片条件
* @param path
* @param width
* @param height
* @return
*/
public static ImageCondition getImageConditionNoSign(String path,int width,int height){
ImageCondition imageCondition = new ImageCondition();
imageCondition.setPath(path);
imageCondition.setWidth(width);
imageCondition.setHeight(height);
imageCondition.setSign(false);
return imageCondition;
}
/**
* 返回指定缩放比例的图片条件(默认带有版权水印)
* @param path
* @param scale
* @return
*/
public static ImageCondition getImageCondition(String path,int scale){
ImageCondition imageCondition = new ImageCondition();
imageCondition.setPath(path);
imageCondition.setScale(scale);
imageCondition.setSign(true);
return imageCondition;
}
/**
* 返回没有版权水印的指定缩放比例的图片条件
* @param path
* @param scale
* @return
*/
public static ImageCondition getImageConditionNoSign(String path,int scale){
ImageCondition imageCondition = new ImageCondition();
imageCondition.setPath(path);
imageCondition.setScale(scale);
imageCondition.setSign(false);
return imageCondition;
}
}
代码3:获取图片的静态资源请求的方法为:
/**
* 获取图片的静态资源地址
* @param imageCondition
* @return
* null : 返回失败
* String :返回的图片路径地址
*/
public String getImagePath(ImageCondition imageCondition) {
String url = baseUrl + "getImagePath?t=0";
if(imageCondition.getWidth() != 0 && imageCondition.getHeight() != 0){
url += "&width=" + imageCondition.getWidth() + "&height=" + imageCondition.getHeight();
}else if(imageCondition.getScale() != 0){
url += "&scale=" + imageCondition.getScale();
}
if(imageCondition.getPath() != null && !imageCondition.getPath().equals("")){
url += "&path=" + imageCondition.getPath();
}
if(imageCondition.getAlpha() != 0){
url += "&alpha=" + imageCondition.getAlpha();
}
if(imageCondition.getSignAlpha() != 0){
url += "&signAlpha=" + imageCondition.getSignAlpha();
}
url += "&recommentSign=" + imageCondition.isRecommentSign();
url += "&sign=" + imageCondition.isSign();
try {
return SendRequestUtil.request(url, RequestMethod.GET).replace("\n","").replace("\r","");
} catch (Exception e) {
RuntimeExceptionUtil.msgToFile(e);
return null;
}
}
至此,以上的三段代码都是在网站系统中。其中代码3中SendRequestUtil为自己开发的工具类,用于发送http请求,在这里,请求就发送给了图片服务器,图片服务器返回的数据,就是图片服务器已经处理好的图片缓存文件的静态地址,格式类似如:image.xxxx.com/images/xxx.png。然后网站系统再将这段静态资源的网址,插入到html的img的src路径中,就完成了图片服务器的分离。由于静态资源是最小消耗硬件性能的,也就实现了性能的提升。下面,就给出图片服务器开发的关键部分(由于项目代码较多,不能分享出所有的源码,但是会尽力给出能说明问题的代码,如果还有不明白,可私我或发表评论)。
首先是图片服务器中,接受请求并返回图片缓存文件的静态路径方法:
代码4:
/**
* 获取图片静态资源的hashUrl网址
* @param request
* @param response
*/
@RequestMapping(value = "getImagePath",method = RequestMethod.GET)
@ResponseBody
public void getImagepath(HttpServletRequest request,HttpServletResponse response){
log.debug(request.getRemoteAddr() + "获取图片的静态资源路径");
response.setCharacterEncoding("UTF-8");
PrintWriter out;
try {
out = response.getWriter();
} catch (IOException e) {
return;
}
String path = request.getParameter("path"),
scale_str = request.getParameter("scale"),
width_str = request.getParameter("width"),
height_str = request.getParameter("height"),
sign_str = request.getParameter("sign"),
signAlpha_str = request.getParameter("signAlpha"),
alpha_str = request.getParameter("alpha"),
recommentSign_str = request.getParameter("recommentSign");
float signAlpha = (float) 1;
float alpha = (float) 1;
boolean sign = true;
boolean recomment = false;
try {
sign = !sign_str.equals("false");
} catch (Exception ignored) { }
try {
recomment = recommentSign_str.equals("true");
} catch (Exception ignored) {
}
try {
if(signAlpha_str != null && !signAlpha_str.equals("")){
signAlpha = Float.parseFloat(signAlpha_str);
}else {
signAlpha = 1;
}
} catch (NumberFormatException ignored) {
}
try {
if(alpha_str != null && !alpha_str.equals("")){
alpha = Float.parseFloat(alpha_str);
}else {
alpha = 1;
}
} catch (NumberFormatException ignored) {}
//获取本图片系统对外的网站地址
URL url = ConfigSign.class.getResource("");
String p = url.getPath();
String pu = FileUtil.getTextFileContent(p + "locationWebURL.txt");
log.debug("获取图片系统对外的网站地址:" + pu);
String cacheFileName = "";
if(path != null && !path.trim().equals("") && path.lastIndexOf(".") != -1){
cacheFileName = ImageCatchUtil.getImageCachePathByFtpPath(path, sign,recomment, height_str, width_str, scale_str, signAlpha, alpha);
log.debug("获取图片静态资源的hash相对路径:" + cacheFileName);
String cacheFileName1 = cacheFileName;
//对平台的路径分隔符进行判断
if(File.separator.equals("\\")){
cacheFileName = cacheFileName.replace("/", "\\");
}
String webPath = ImageUtil.getWebPath(request);
log.debug("根据hash路径生成缓存文件绝对路径:" + webPath + cacheFileName);
File cacheFile = new File(webPath + cacheFileName);
if(cacheFile.exists()){
log.debug("缓存文件已生成,返回已存在的静态资源网址:" + pu + cacheFileName1);
out.write(pu + cacheFileName1);
}else {
log.debug("缓存文件不存在,正在生成缓存文件");
if(ftpImageToCacheService.imageToCache(request)){
log.debug("缓存文件生成成功,返回静态资源网址:" + pu + cacheFileName1);
out.write(pu + cacheFileName1);
}else {
log.warn("缓存文件生成失败,返回动态图片请求链接:" + pu + "image?path=");
out.write(pu + "image?path=");
}
}
}else {
out.write(pu + "image?path=");
log.warn("传入的path无效,返回动态图片请求链接:" + pu + "image?path=");
}
}
代码4中的ImageCatchUtil.getImageCachePathByFtpPath方法就是用与组建文件hash路径名。
秉着分享原则,下面给出代码4中,生成缓存文件的代码:
代码5:
/**
* 根据请求条件,将原图进行转换,并生成缓存文件
* @param request
* @return
*/
@Override
public boolean imageToCache(HttpServletRequest request) {
String path = request.getParameter("path"),
scale_str = request.getParameter("scale"),
width_str = request.getParameter("width"),
height_str = request.getParameter("height"),
sign_str = request.getParameter("sign"),
signAlpha_str = request.getParameter("signAlpha"),
alpha_str = request.getParameter("alpha"),
recommentSign_str = request.getParameter("recommentSign");
boolean sign = true;
boolean recomment = false;
try {
sign = !sign_str.equals("false");
} catch (Exception ignored) { }
try {
recomment = recommentSign_str.equals("true");
} catch (Exception ignored) {
}
try {
if(signAlpha_str != null && !signAlpha_str.equals("")){
signAlpha = Float.parseFloat(signAlpha_str);
}else {
signAlpha = 1;
}
} catch (NumberFormatException ignored) {
}
try {
if(alpha_str != null && !alpha_str.equals("")){
alpha = Float.parseFloat(alpha_str);
}else {
alpha = 1;
}
} catch (NumberFormatException ignored) {}
String cacheFileName = "";
if(path != null && !path.trim().equals("") && path.lastIndexOf(".") != -1){
cacheFileName = ImageCatchUtil.getImageCachePathByFtpPath(path, sign,recomment, height_str, width_str, scale_str, signAlpha, alpha);
log.debug("获取图片静态资源的hash相对路径:" + cacheFileName);
if(File.separator.equals("\\")){
cacheFileName = cacheFileName.replace("/",File.separator);
}
}else {
log.warn("ftp文件资源路径错误,返回false");
return false;
}
File cacheFile;
try {
if(path == null || path.equals("")){
return false;
}
String webPath = ImageUtil.getWebPath(request);
String cacheDir = (webPath + path.substring(1,path.lastIndexOf("/")+1))
.replace("/",File.separator);
log.debug("计算待生成的缓存图片的绝对路径目录:" + cacheDir);
String fileType;
try {
fileType = path.substring(path.lastIndexOf("."));
} catch (Exception e) {
return false;
}
log.debug("原图片的文件类型:" + fileType);
cacheFile = new File(webPath + cacheFileName);
log.debug("计算待生成图片的绝对路径:" + webPath + cacheFileName);
if(!cacheFile.exists()){
log.debug("待生成缓存文件的目录不存在,正在进行自动创建目录:" + cacheDir);
File cacheFileDir = new File(cacheDir);
cacheFileDir.mkdirs();
}
log.debug("从ftp服务器下载path对应的图片资源:" + path);
log.debug("保存到文件:" + cacheFile.getAbsolutePath());
imageFtpService.download(cacheFile, path);
BufferedImage image = ImageIO.read(cacheFile);
if (image == null) {//输出提示错误图像
log.debug("图像下载错误,返回false");
return false;
} else {
log.debug("图像下载成功,进行图像转换操作");
image = ImageUtil.imageConvert(image,height_str,width_str,sign,recomment,signAlpha,scale_str,alpha);
log.debug("保存转换后的图片为缓存文件写入磁盘");
ImageUtil.getInstance().writeImage(fileType,image,cacheFile);
if(cacheFile.exists()){
log.debug("缓存文件生成成功");
return true;
}else {
log.warn("缓存文件生成失败");
return false;
}
}
} catch (IOException e) {
RuntimeExceptionUtil.msgToFile(e);
log.error("保存request中的图片信息到缓存文件中发生异常",e);
return false;
}
}
在代码5中,用到了ImageUtil工具类,这个工具类包含了很多实用的方法,可以这么说,这个工具类,算是图片服务器处理图片的核心所在,它兼任了图像的转换处理任务,没有它对图像的转换处理,图皮服务器也就没有了存在的价值,接下来,我将贴出这个类:
代码6:ImageUtil.java :
import com.cqcae.util.CustomerMath;
import com.cqcae.util.RuntimeExceptionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.io.File;
import java.io.IOException;
/**
* 图片处理工具类
* 单例模式
* Copyright 2014-2015 the original BZTWT
* Created by QianLong on 2014/7/9 0009.
*/
public class ImageUtil {
private Logger log = LoggerFactory.getLogger(ImageUtil.class);
private static ImageUtil imageUtil = null;
private ImageUtil() {
}
public static String getWebPath(HttpServletRequest request){
String webPath = request.getSession().getServletContext().getRealPath("/");
if(webPath.lastIndexOf(File.separator) != webPath.length()-1){
webPath = webPath + File.separator;
}
return webPath;
}
public static ImageUtil getInstance() {
if (imageUtil == null) {
imageUtil = new ImageUtil();
}
return imageUtil;
}
/**
* 图片转换操作
* 注意:
* 1、width与height成对出现才会生效
* 2、如果指定了width和height,那么scale参数将会失效
* @param image
* 待转换的图像
* @param height_str
* 指定图像的输出高度
* @param width_str
* 指定图像的输出宽度
* @param sign
* false:不添加版权水印 默认true (小于100 * 50 的不加水印)
* @param recomment
* true:添加重点推荐水印,默认false
* @param signAlpha
* 水印的透明度(0.0到1.0之间的float值,默认1.0)
* @param scale_str
* 对图像进行缩放处理,小于100为缩小,大于100为放大
* @param alpha
* 图片的透明度(0.0到1.0之间的float值,默认1.0)
* @return
*/
public static BufferedImage imageConvert(BufferedImage image,String height_str,String width_str
,boolean sign,boolean recomment,float signAlpha,String scale_str,float alpha){
if(height_str != null && width_str != null){//转换图像到指定高宽
int width = 0,height = 0;
try {
width = Integer.parseInt(width_str);
height = Integer.parseInt(height_str);
image = ImageUtil.getInstance().turnImageToWH(width,height,image,sign,recomment,signAlpha);
} catch (NumberFormatException e) {//输出提示错误图像
RuntimeExceptionUtil.msgToFile(e);
image = ImageUtil.getInstance().getFontImage("图像参数错误");
}
}else if (scale_str != null) {//转换图像的等比缩放
int scale = 100;
try {
scale = Integer.parseInt(scale_str);
image = ImageUtil.getInstance().scale(scale,image,sign,recomment,signAlpha);
} catch (NumberFormatException e) {//输出提示错误图像
RuntimeExceptionUtil.msgToFile(e);
image = ImageUtil.getInstance().getFontImage("图像参数错误");
}
}else{
if(sign)
image = ImageUtil.getInstance().addSign(image,signAlpha);
}
//调整图像透明度
ImageUtil.getInstance().getImageAlpha(image,alpha);
return image;
}
/**
* 调整图像透明度
*
* @param image
* @param alpha
*/
public void getImageAlpha(BufferedImage image, float alpha) {
BufferedImage bufferedImage = new BufferedImage(image.getWidth(), image.getHeight(),
BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = bufferedImage.createGraphics();
bufferedImage = g2.getDeviceConfiguration().createCompatibleImage(image.getWidth(), image.getHeight(), Transparency.TRANSLUCENT);
g2.dispose();
g2 = bufferedImage.createGraphics();
g2.setComposite(AlphaComposite.SrcOver.derive(alpha));
g2.drawImage(
image.getScaledInstance(image.getWidth(), image.getHeight(), Image.SCALE_SMOOTH),
0, 0, null);
g2.dispose();
}
/**
* response写出图片
*
* @param fileType
* @param image
* @param servletOutputStream
* @throws java.io.IOException
*/
public void writeImage(String fileType, BufferedImage image, ServletOutputStream servletOutputStream) throws IOException {
try {
switch (fileType) {
case ".jpg":
ImageIO.write(image, "PNG", servletOutputStream);
break;
case ".gif":
ImageIO.write(image, "GIF", servletOutputStream);
break;
case ".png":
ImageIO.write(image, "PNG", servletOutputStream);
break;
}
} catch (IndexOutOfBoundsException e) {
ImageIO.write(getFontImage("图像输出错误"), "PNG", servletOutputStream);
} finally {
servletOutputStream.close();
}
}
/**
* response写出图片,同时保存请求图片的缓存文件
*
* @param fileType
* @param image
* @param servletOutputStream
* @param cacheFile
* @throws IOException
*/
public void writeImage(String fileType, BufferedImage image, ServletOutputStream servletOutputStream, File cacheFile) throws IOException {
try {
switch (fileType) {
case ".jpg":
ImageIO.write(image, "PNG", servletOutputStream);
ImageIO.write(image, "PNG", cacheFile);
break;
case ".gif":
ImageIO.write(image, "GIF", servletOutputStream);
ImageIO.write(image, "GIF", cacheFile);
break;
case ".png":
ImageIO.write(image, "PNG", servletOutputStream);
ImageIO.write(image, "PNG", cacheFile);
break;
}
} catch (IndexOutOfBoundsException e) {
ImageIO.write(getFontImage("图像输出错误"), "PNG", servletOutputStream);
//若缓存文件保存失败,则删除缓存文件
if (cacheFile.exists()) {
cacheFile.delete();
}
} finally {
servletOutputStream.close();
}
}
/**
* 保存请求图片的缓存文件
*
* @param fileType
* @param image
* @param cacheFile
* @throws IOException
*/
public void writeImage(String fileType, BufferedImage image, File cacheFile) throws IOException {
try {
switch (fileType) {
case ".jpg":
ImageIO.write(image, "PNG", cacheFile);
break;
case ".gif":
ImageIO.write(image, "GIF", cacheFile);
break;
case ".png":
ImageIO.write(image, "PNG", cacheFile);
break;
}
} catch (IndexOutOfBoundsException e) {
//若缓存文件保存失败,则删除缓存文件
if (cacheFile.exists()) {
cacheFile.delete();
}
}
}
/**
* 返回指定高宽的图片
* 按照中间的位置自动裁剪图片
* @param width
* @param height
* @param image
* @param sign
* @return
*/
public BufferedImage turnImageToWH(int width, int height, BufferedImage image, boolean sign, boolean recomment, float signAlpha) {
/**
* 转换图像(高宽至少有目标高宽的最大值)
*/
double z;
if (image.getWidth() == image.getHeight()) {
int s = width > height ? width : height;
z = CustomerMath.div(s, image.getHeight(), 2);
} else if (width > height) {
if (image.getHeight() > image.getWidth()) {
z = CustomerMath.div(width, image.getWidth(), 2);
} else {
z = CustomerMath.div(height, image.getHeight(), 2);
}
} else if (width < height) {
if (image.getHeight() > image.getWidth()) {
z = CustomerMath.div(width, image.getWidth(), 2);
} else {
z = CustomerMath.div(height, image.getHeight(), 2);
}
} else {
int cut = image.getWidth() <= image.getHeight() ? image.getWidth() : image.getHeight();
z = CustomerMath.div(width, cut, 2);
}
double tw = CustomerMath.mul(z,image.getWidth());
double th = CustomerMath.mul(z,image.getHeight());
while (tw < width || th < height){
z = z + 0.01;
tw = CustomerMath.mul(z,image.getWidth());
th = CustomerMath.mul(z,image.getHeight());
}
int z1 = (int) CustomerMath.mul(z, 100);
BufferedImage image1 = scale(z1, image, false, false, signAlpha);
int x = 0,y = 0;
if (image1.getWidth() > width) {
x = (int) (CustomerMath.div(image1.getWidth(), 2) - CustomerMath.div(width, 2));
}
if (image1.getHeight() > height) {
y = (int) (CustomerMath.div(image1.getHeight(), 2) - CustomerMath.div(height, 2));
}
BufferedImage result = cut(image1,x,y,width,height);
if(sign)
result = addSign(result,signAlpha);
if(recomment)
result = addRecommentSign(result);
return result;
}
/**
* 图像切割(指定切片的宽度和高度)
* @param bi 原图像
* @param x 裁剪原图像起点坐标X
* @param y 裁剪原图像起点坐标Y
* @param width 目标切片宽度
* @param height 目标切片高度
* @return
*/
public static BufferedImage cut(BufferedImage bi,int x, int y, int width, int height) {
BufferedImage tag = new BufferedImage(width,
height, BufferedImage.TYPE_INT_RGB);
int srcWidth = bi.getHeight(); // 源图宽度
int srcHeight = bi.getWidth(); // 源图高度
if (srcWidth > 0 && srcHeight > 0) {
ImageFilter cropFilter = new CropImageFilter(x, y, width, height);
Image img = Toolkit.getDefaultToolkit().createImage(
new FilteredImageSource(bi.getSource(),cropFilter));
Graphics g = tag.getGraphics();
g.drawImage(img, 0, 0, width, height, null); // 绘制切割后的图
g.dispose();
}
return tag;
}
/**
* 等比缩放
*
* @param scale
* @param scaleImage
* @param sign
* @return
*/
public BufferedImage scale(int scale, BufferedImage scaleImage, boolean sign, boolean recomment, float signAlpha) {
int width = (int) (scaleImage.getWidth(null) * scale / 100.0);
int height = (int) (scaleImage.getHeight(null) * scale / 100.0);
BufferedImage bufferedImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
bufferedImage.getGraphics().drawImage(
scaleImage.getScaledInstance(width, height, Image.SCALE_SMOOTH),
0, 0, null);
if (sign) {
bufferedImage = addSign(bufferedImage, signAlpha);
}
if (recomment) {
bufferedImage = addRecommentSign(bufferedImage);
}
return bufferedImage;
}
/**
* 获取指定文字的图片
*
* @param font
* @return
*/
public BufferedImage getFontImage(String font) {
BufferedImage image = new BufferedImage(100, 35,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setFont(new Font("宋体", Font.BOLD, 15));
g.setColor(Color.CYAN);
g.drawString(font, 0, 25);
g.dispose();
return image;
}
/**
* 添加版权水印
*
* @param image
* @return
*/
public BufferedImage addSign(BufferedImage image, float signAlpha) {
Graphics g = image.getGraphics();
g.setFont(new Font("宋体", Font.BOLD, 15));
g.setColor(Color.GRAY);
//小于120 * 50 的不加水印
if (image.getWidth() < 150 || image.getHeight() < 50)
return image;
Graphics2D g2 = image.createGraphics();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, signAlpha));
try {
String markImgPath = this.getClass().getClassLoader().getResource("watermark.png").getPath();
File file = new File(markImgPath);
BufferedImage markImg = ImageIO.read(file);
g2.drawImage(markImg, image.getWidth() - 110, image.getHeight() - 35, null);
} catch (IOException e) {
g2.drawString("盛世文化", image.getWidth() - 80, image.getHeight() - 25);
g2.drawString("版权所有", image.getWidth() - 80, image.getHeight() - 10);
}
g.dispose();
return image;
}
/**
* 添加推荐水印
*
* @param image
* @return
*/
public BufferedImage addRecommentSign(BufferedImage image) {
Graphics g = image.getGraphics();
g.setFont(new Font("宋体", Font.BOLD, 15));
g.setColor(Color.GRAY);
//小于120 * 50 的不加水印
Graphics2D g2 = image.createGraphics();
try {
String markImgPath = this.getClass().getClassLoader().getResource("recomment_ico.png").getPath();
File file = new File(markImgPath);
BufferedImage markImg = ImageIO.read(file);
g2.drawImage(markImg, 0, 0, null);
} catch (IOException ignored) {
}
g.dispose();
return image;
}
}
ok,至此,基本上把我在项目中,对图片分离的处理,交代的差不多了。写完了我自己看了一遍,感觉大部分都是代码,呵呵,程序员嘛,不看代码看啥嘛,是吧。源码,才是程序员,真正交流的纽带啊。
后续再分享我在项目中的其他经验。呵呵。