原创——图片服务器分离

在做前前端项目的时候,由于业务图片是通过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,至此,基本上把我在项目中,对图片分离的处理,交代的差不多了。写完了我自己看了一遍,感觉大部分都是代码,呵呵,程序员嘛,不看代码看啥嘛,是吧。源码,才是程序员,真正交流的纽带啊。

后续再分享我在项目中的其他经验。呵呵。

你可能感兴趣的:(服务器)