`
龙飞凤舞的程序员
  • 浏览: 1307 次
  • 性别: Icon_minigender_1
文章分类
社区版块
存档分类
最新评论

原创——图片服务器分离

 
阅读更多

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

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

分享到:
评论

相关推荐

    PHP实例开发源码——金点网络原创图标在线生成器 PHP版.zip

    "PHP实例开发源码——金点网络原创图标在线生成器 PHP版.zip" 是一个基于PHP编程语言的实例项目,主要用于创建在线图标生成器。这个项目由金点网络开发,提供了完整的源代码,让开发者可以研究、学习或在自己的项目...

    ASP.NET源码——[整站程序]Thumbstudio申博工作室原创全站.zip

    "Thumbstudio申博工作室原创全站.zip"这个压缩包文件包含了一个完整的ASP.NET网站程序,可能是由Thumbstudio申博工作室开发的。 在ASP.NET中,开发人员可以使用多种编程语言,如C#或VB.NET,来编写后端代码。这个...

    毕业论文——基于jsp的随堂考试系统

    【描述】:“毕业论文——基于jsp的随堂考试系统”表明这是一项学术研究,作者可能是一位计算机科学或信息技术专业的学生,其毕业设计或论文项目就是构建这样一个系统。系统的目标是为教学环境提供实时的在线考试...

    ASP.NET源码——[企业]良精.Net企业网站管理系统 v1.5.zip

    【ASP.NET源码——[企业]良精.Net企业网站管理系统 v1.5.zip】这个压缩包文件包含了良精.Net企业网站管理系统 v1.5的源代码,是基于ASP.NET技术开发的一款专门针对企业的网站管理解决方案。ASP.NET是微软公司推出的...

    AspectJ+Spring编程(原创)

    首先,AspectJ是一种强大的AOP语言,它扩展了Java,允许我们定义“切面”——即跨越多个对象和类的关注点。切面可以包含业务逻辑,但更多时候用于处理那些影响多个类的通用行为,如日志、性能监控和事务控制。...

    BoardroomManager.zip

    《董事会管理器——JavaWeb应用深度解析》 在IT行业中,JavaWeb技术是构建企业级应用的重要工具,尤其在管理类系统中,如"BoardroomManager"这样的项目,其复杂性和实用性并重,展现了JavaWeb的强大功能。这个...

    StudentManagement.zip

    《学生管理系统——基于JavaEE技术实现》 在IT行业中,JavaEE(Java Platform, Enterprise Edition)是一种广泛应用于企业级应用开发的技术平台。本项目“StudentManagement.zip”是田超凡原创设计的一个学生管理...

    StuManageSys.zip

    《JavaWeb学生管理系统——StuManageSys》 在IT领域,JavaWeb技术是构建Web应用程序的常用工具,尤其适用于企业级应用开发。本项目“StuManageSys”是一款基于JavaWeb的学生管理系统,由作者田超凡原创设计。下面将...

    TravelSystem.zip

    《旅行系统(TravelSystem)——JavaWeb开发详解》 在当今信息化社会,旅游管理系统(TravelSystem)已经成为旅游业不可或缺的一部分,它极大地提升了业务处理效率,优化了用户体验。本系统基于JavaWeb技术栈进行开发...

    帝国CMS 兴宁网DIV+CSS模板

    这个模板采用了流行的网页布局方式——DIV+CSS,使得页面结构清晰,代码简洁,对于搜索引擎优化(SEO)友好,并且支持多种浏览器,包括IE6、IE7、IE8、Firefox、Chrome、Safari等。 在网页设计中,`DIV`(Division...

    MrBFFsOfficial网站:BFF先生的官方网站!

    这个网站可能采用了现代Web开发的前后端分离模式,前端使用SCSS进行样式管理,JavaScript处理交互,而服务器端可能由PHP、Node.js或其他技术提供支持。同时,考虑到它是一个游戏网站,可能还包括与游戏API的集成,...

Global site tag (gtag.js) - Google Analytics