java 给图片打水印 Plus

    之前写了一篇文章,java 给图片打水印,虽然呢,功能是实现了,但是,代码结构混乱、效率低下,还使用到了SUN包下的东西,到服务器Maven打包的时候都打包不了,部门老大看了都看不下去了,忍不住亲自操刀斧正了一番,斧正后的就称呼plus版吧,我测试了下效率,原版是200+ms一张图片,plus版是10+ms,实在是汗颜啊。。。。。。。这里把plus版的贴出来,以后敲代码多借鉴下面的代码思想

import java.awt.Color;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.font.TextAttribute;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.util.List;

import javax.imageio.ImageIO;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ttpai.cms.content.model.ImageDeal;
import com.ttpai.cms.content.model.ImageGujia;
import com.ttpai.tfs.TFSClicent;

/**
 * 估价文章图片,画图工具类 
 * 1、不变的做缓存,字体和背景图 。用到的字体size不多可以考虑做缓存,因为Font.deriveFont会再new一个Font,可以减少gc
 * 2、图片上传改为直接TFS上传,不往磁盘上写,不但增加IO还很慢 
 * 3、增加异常处理。如:a)TFS上传异常 b)绘图异常。则返回NULL ,为什么返回空字符串? 区分NULL和“”的含义。
 * 4、图片限制最大宽高:1200F, 900F。图片已知大小,去掉多余的调用 
 * 5、不要用main写测试用例 
 * 6、根据开闭原则,多考虑给外部提供接口有哪些,其他接口一律屏蔽。
 * @author rickycoder
 *
 */
public class AppraiseImageUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(AppraiseImageUtils.class);
    private static final String IMAGE_URL = "http://pic001.ttpaicdn.com/images/";
    private static final String PRICE_UNIT = "万元";// 估价的数字和单位是不同的size,所以需要另外绘画
    /**
     * 车况很新背景图
     */
    private static BufferedImage backgroundImageNew = null;
    /**
     * 车况良好背景图
     */
    private static BufferedImage backgroundImageGood = null;
    /**
     * 车况一般背景图
     */
    private static BufferedImage backgroundImageGeneral = null;
    /**
     * 成交背景图
     */
    private static BufferedImage backgroundImageDeal = null;

    private static Font fontBold28 = null;
    private static Font fontBold36 = null;

    private static Font fontRegular18 = null;
    private static Font fontRegular20 = null;

    static {
        try {
            backgroundImageNew =
                    ImageIO.read(AppraiseImageUtils.class
                            .getResourceAsStream("/appraise/appraise_background_new.png"));
            backgroundImageGood =
                    ImageIO.read(AppraiseImageUtils.class
                            .getResourceAsStream("/appraise/appraise_background_good.png"));
            backgroundImageGeneral =
                    ImageIO.read(AppraiseImageUtils.class
                            .getResourceAsStream("/appraise/appraise_background_general.png"));
            backgroundImageDeal =
                    ImageIO.read(AppraiseImageUtils.class
                            .getResourceAsStream("/appraise/background_deal.png"));
        } catch (IOException e) {
            LOGGER.error("加载背景图报错", e);
        }

        InputStream is = null;
        BufferedInputStream bis = null;
        Font definedFont = null;
        try {
            is = AppraiseImageUtils.class.getResourceAsStream("/font/PingFang_Bold.ttf");
            bis = new BufferedInputStream(is);

            definedFont = Font.createFont(Font.TRUETYPE_FONT, bis);

            fontBold28 = definedFont.deriveFont(28f);
            fontBold36 = definedFont.deriveFont(36f);

            is = AppraiseImageUtils.class.getResourceAsStream("/font/PingFang_SC_Regular.otf");
            bis = new BufferedInputStream(is);
            definedFont = Font.createFont(Font.TRUETYPE_FONT, bis);

            fontRegular18 = definedFont.deriveFont(18f);
            fontRegular20 = definedFont.deriveFont(20f);

            is.close();
            bis.close();

        } catch (FontFormatException e) {
            LOGGER.error("字体格式报错", e);
        } catch (IOException e) {
            LOGGER.error("加载字体格式报错", e);
        } finally {
            is = null;
            bis = null;
        }
        definedFont = null;
    }

    private AppraiseImageUtils() {}

    /**
     * @Description: 上传图片到TFS
     * @param out 图片数据流
     * @return String
     * @by: yan.zhang@2017年12月15日
     */
    private static String uploadImage(ByteArrayOutputStream out) {
        if (null == out || 0 == out.size()) {
            return null;
        }
        // 设置图片上传至服务器的配置并上传
        TFSClicent tfsClicent = new TFSClicent();
        String address = null;
        try {
            address = IMAGE_URL + tfsClicent.uploadImage(out.toByteArray());
        } catch (Exception e) {
            LOGGER.error("图片上传失败", e);
        }
        return address;
    }

    /**
     * @Description:填充文字到图片上(成交列表)
     * @param inImagePath
     * @param outImagePath
     * @param deals
     * @return String 返回TFS上的图片地址
     * @by: yan.zhang@2017年12月14日
     */
    public static String createDealImage(List<ImageDeal> deals) {

        Image image = backgroundImageDeal;
        int width = image.getWidth(null);
        int height = image.getHeight(null);

        BufferedImage bImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = bImage.createGraphics();
        g.setColor(Color.black);
        g.setBackground(Color.white);
        /* 画出图片 */
        g.drawImage(image, 0, 0, null);

        Color color = new Color(102, 102, 102);
        /** 下面代码的参数都是根据UED的图片用尺子量的,不会产生魔数,请不要codeReview **/
        int x1 = 75;
        int x2 = 248;
        int x3 = 427;
        int x4 = 630;
        int y = 90;// 递增48

        for (int i = 0; i < deals.size(); i++) {
            ImageDeal deal = deals.get(i);
            addWord2image(g, deal.getDealCity(), x1, y, fontRegular18, color);// 成交城市
            addWord2image(g, DateUtils.formatDateS(deal.getCardTime()), x2, y, fontRegular18, color);// 上牌时间
            addWord2image(g, DateUtils.formatDateS(deal.getDealTime()), x3, y, fontRegular18, color);// 成交时间
            if (deal.getDealPrice().length() == 6) {// 若是99.99万,则坐标向左挪19个单位
                addWord2image(g, deal.getDealPrice(), x4 - 35, y, fontRegular18, color);// 成交价格
            } else if (deal.getDealPrice().length() == 5) {// 若是99.9万,则坐标向左挪14个单位
                addWord2image(g, deal.getDealPrice(), x4 - 25, y, fontRegular18, color);// 成交价格
            } else if (deal.getDealPrice().length() == 4) {// 若是9.9万,则坐标向左挪44个单位
                addWord2image(g, deal.getDealPrice(), x4 - 7, y, fontRegular18, color);// 成交价格
            } else if (deal.getDealPrice().length() == 3) {// 若是99万,则坐标向左挪44个单位
                addWord2image(g, deal.getDealPrice(), x4 - 10, y, fontRegular18, color);// 成交价格
            } else {
                addWord2image(g, deal.getDealPrice(), x4, y, fontRegular18, color);// 成交价格
            }
            y += 48;
        }
        g.dispose();// 画笔结束
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            ImageIO.write(bImage, "jpg", out);
            String imageUrl = uploadImage(out);
            out.close();
            return imageUrl;
        } catch (Exception e) {
            LOGGER.error("createDealImage" + e.getMessage(), e);
        }
        return null;
    }

    /**
     * 创建车况很新的估价图
     * 
     * @param vo
     * @return
     */
    public static String createGujiaNewImage(ImageGujia vo) {
        return createGujiaImage(backgroundImageNew, vo);
    }

    /**
     * 创建车况良好的估价图
     * 
     * @param vo
     * @return
     */
    public static String createGujiaGoodImage(ImageGujia vo) {
        return createGujiaImage(backgroundImageGood, vo);
    }

    /**
     * 创建车况一般的估价图
     * 
     * @param vo
     * @return
     */
    public static String createGujiaGeneralImage(ImageGujia vo) {
        return createGujiaImage(backgroundImageGeneral, vo);
    }


    /**
     * @Description:填充文字到图片上(估价页)
     * @param backgroundImage 背景图
     * @param vo 图片参数实体
     * @return String 返回TFS上的图片地址
     * @by: yan.zhang@2017年12月14日
     */
    private static String createGujiaImage(BufferedImage backgroundImage, ImageGujia vo) {
        Image image = backgroundImage;
        int width = image.getWidth(null);
        int height = image.getHeight(null);

        BufferedImage bImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = bImage.createGraphics();
        g.setColor(Color.black);
        g.setBackground(Color.white);
        /* 画出图片 */
        g.drawImage(image, 0, 0, null);

        /** 下面代码的参数都是根据UED的图片用尺子量的,不会产生魔数,请不要codeReview **/
        Color color = new Color(51, 51, 51);// 大标题颜色
        if (vo.getTitle().length() <= 32) {// 标题字小于32,则用planA
            addWord2image(g, vo.getTitle(), 10, 62, fontBold28, color);// 标题
        } else {
            String titleLine1 = vo.getTitle().substring(0, 32);
            addWord2image(g, titleLine1, 10, 41, fontBold28, color);// 标题
            String titleLine2 = vo.getTitle().substring(32);
            addWord2image(g, titleLine2, 10, 78, fontBold28, color);// 标题
        }
        color = new Color(81, 81, 81);// 行2文字的颜色 20 35
        addWord2image(g, vo.getCity(), 80, 120, fontRegular20, color);// 城市
        addWord2image(g, vo.getCarAge(), 200, 120, fontRegular20, color);// 车龄
        addWord2image(g, vo.getMileAge(), 310, 120, fontRegular20, color);// 里程
        color = new Color(253, 96, 63);// 估价和估价单位的颜色
        addWord2image(g, vo.getGujia(), 60, 243, fontBold36, color);// 估价
		addWord2image(g, PRICE_UNIT, 156, 243, fontRegular20,color);//估价的单位,估价的数字和单位是不同的size,所以需要另外绘画
        color = new Color(167, 167, 167);// 指导价的颜色
        addWord2image(g, vo.getGuidancePrice(), 327, 243, fontRegular20, color);// 指导价

        g.dispose();// 画笔结束

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            ImageIO.write(bImage, "jpg", out);
            String imageUrl = uploadImage(out);
            out.close();
            return imageUrl;
        } catch (Exception e) {
            LOGGER.error("createGujiaImage" + e.getMessage(), e);
        }

        return null;
    }

    /**
     * @Description: 把文字绘画到图片上,绘画内容为空就不画了。
     * @param g Graphics2D
     * @param addWord 要加上去的文字
     * @param x 横坐标
     * @param y 纵坐标
     * @param font 字的类型
     * @param color 字的颜色 void
     * @by: yan.zhang@2017年12月14日
     */
    private static void addWord2image(Graphics2D g, String addWord, int x, int y, Font font,
            Color color) {
        // 绘画内容为空就不画了。
        if (StringUtils.isBlank(addWord)) {
            return;
        }
        AttributedString ats = new AttributedString(addWord);
        g.setFont(font);
        g.setColor(color);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);


        ats.addAttribute(TextAttribute.FONT, font, 0, addWord.length());

        AttributedCharacterIterator iter = ats.getIterator();
        g.drawString(iter, x, y);
    }
}
posted @ 2018-02-25 21:55  Bug开发攻城狮  阅读(311)  评论(0编辑  收藏  举报