java实现图片的组合(一)

需求是这样子的:

当用户在我们的公众号里购买课程成功后,我要推送一条课程详情的信息和一张图片;图片里有购买课程的用户头像,用户昵称,课程名称,讲师的二维码等,由于这些信息都是动的,那我只能用图片的组合关系来做。

下面是最终效果图和UI提供的模板图,四个地方是动的(用户头像,用户昵称,课程名称,讲师的二维码)。UI出个图,把不动的地方给写死,然后标出动的地方的坐标值(x多少px,y多少px),图给到我,我把用户头像,昵称等信息依次填到该坐标上。

最终效果图


UI提供的模板图

下面贴代码

package com.ywwl.nmedia.api.uulijun_pic_test;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageDecoder;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import com.ywwl.common.util.JedisUtil;
import com.ywwl.nmedia.api.biz.base.SpringApplicationContextUtil;
import com.ywwl.nmedia.api.biz.util.OssFileUtil;
import org.apache.commons.lang3.StringUtils;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * @Author whb
 * @Date 21:30 2018/7/9
 **/
public class ImageUtil {

    //模板图片(存放在阿里云的OSS上)
    private static final String ORIGINAL_IMG_PATH = "lesson/qrcode/2018/07/89670065122466.jpg";
    //图片传到服务器里的路径
    private static final String LECTURER_QRCODE_PATH = "/opt/lectuereQrcode.jpg";
    //private static final String LECTURER_QRCODE_PATH = "/Users/whb/Documents/lectuereQrcode.jpg";


    /**OssFileUtil.getUploadFilePath这个方法是我们公司自己写的,不方便贴出来,其实作用就是,把图片路径传进来,返回完整地址
     伪代码是 String http://xxx.com:8080/lesson/qrcode/123.jpg = OssFileUtil.getUploadFilePath(String lesson/qrcode/123.jpg);
     确保 http://xxx.com:8080/lesson/qrcode/123.jpg 在浏览器里输入后能看到图片
     OssFileUtil.uploadFile(InputStream in, uploadPathReal) 这个就是把图片上传到OSS里
     */

    /**
     * 绘制图片 * * @param headImg 用户头像(完整地址) * http://thirdwx.qlogo.cn/mmopen/vi_32/UUIiaLFI3nrye6cCG7oEcur40FmlBOINm0G3fYId9yzoDSk41v04zBd8kDPxf7j82wc325P237R7RScCcwR1TFg/132 * @param nickname 用户昵称 * @param lessonName 课程名称 * @param qrcode 讲师二维码 * @param cover 课程封面图 lesson/icon/2018/01/359819524709343.jpg * @return 绘制后的图片在OSS里的路径
     */
    public String drawImg(String headImg, String nickname, String lessonName, String qrcode, String cover) {
        BufferedInputStream is = null;
        OutputStream os = null;
        String key = "writePicToPath";
        InputStream in = null;
        JedisUtil jedisUtil = SpringApplicationContextUtil.getBean(JedisUtil.class);
        try {
            String path = OssFileUtil.getUploadFilePath(ORIGINAL_IMG_PATH);//获取模板图片完整地址
            is = new BufferedInputStream(readFile(path));//读取到模板图片流
            JPEGImageDecoder jpegDecoder = JPEGCodec.createJPEGDecoder(is);//通过JPEG图像流创建JPEG数据流解码器
            BufferedImage buffImg = jpegDecoder.decodeAsBufferedImage();//解码当前JPEG数据流,返回BufferedImage对象
            Graphics g = buffImg.getGraphics();//得到画笔对象
            BufferedImage imgCover = ImageUtil.getBufferedImage(OssFileUtil.getUploadFilePath(cover), "lesson/icon/", 341 * 2, 255 * 2);
            g.drawImage(imgCover, 0 + 30 + 4, 0 + 30 + 3, null);//将封面图绘制到模板图上
            g.setColor(Color.BLACK);
            BufferedImage img = ImageUtil.roundImg(headImg);//把头像裁剪成圆形
            g.drawImage(img, 146 * 2 + 30 + 5, 229 * 2 + 30 + 5, null);//将头像绘制到模板图上
            g.setColor(Color.BLACK);
            Font f = new Font("宋体", Font.PLAIN, 30);
            Color myColor = Color.BLACK;
            g.setColor(myColor);
            g.setFont(f);
            FontMetrics fmNick = g.getFontMetrics(f);//昵称居中设置
            int nickWidth = fmNick.stringWidth(nickname);
            int nickWidthX = (730 - nickWidth) / 2;
            g.drawString(nickname, nickWidthX, 285 * 2 + 30 + 30); //绘制文字
            FontMetrics fmLesson = g.getFontMetrics(f);//课程名称居中设置
            // 课程名称较长,还要进行换行处理,设置每14个字换行
            int batch = 14;
            int line = lessonName.length() / batch;
            if (lessonName.length() % batch != 0) line++;
            int begin = 0;
            int end = 14;
            int h = 0;//上下行间距30px
            String lessonNameTmp = "";
            boolean isEnd = false;
            for (int i = 0; i < line; i++) {
                if (lessonName.length() <= 14) {
                    //课程名称少于14个字
                    int lessonWidth = fmLesson.stringWidth(lessonName);
                    int lessonWidthX = (730 - lessonWidth) / 2;
                    g.drawString(lessonNameTmp, lessonWidthX, 342 * 2 + 30 + 20 + 5 + 5);
                    break;
                }
                lessonNameTmp = lessonName.substring(begin, end);//每次截取14个字,把文字绘制到模板图上
                int lessonWidth = fmLesson.stringWidth(lessonNameTmp);
                int lessonWidthX = (730 - lessonWidth) / 2;
                g.drawString(lessonNameTmp, lessonWidthX, 342 * 2 + 30 + 20 + 5 + 5 + h);
                h += 30;
                begin += batch;
                end += batch;
                if (isEnd) break;
                if (end > lessonName.length()) {
                    end = lessonName.length();
                    isEnd = true;
                }
            }
            BufferedImage imgQrcode = ImageUtil.getBufferedImage(OssFileUtil.getUploadFilePath(qrcode), "lesson/qrcode/", 90 * 2 + 10, 90 * 2 + 10);
            g.drawImage(imgQrcode, 126 * 2 + 30 + 5, 448 * 2 + 30 + 5, null);//将讲师二维码绘制到模板图上
            g.setColor(Color.BLACK);
            g.dispose(); //把绘制好的图片写到下面这个图片里,加锁处理
            if (!lock(jedisUtil, key)) return null;
            os = new FileOutputStream(LECTURER_QRCODE_PATH);
            JPEGImageEncoder en = JPEGCodec.createJPEGEncoder(os);//创建编码器,用于编码内存中的图像数据
            en.encode(buffImg); //写完之后,再次读到这个图片
            in = new BufferedInputStream(new FileInputStream(new File(LECTURER_QRCODE_PATH)));
            String uploadPathReal = OssFileUtil.getUploadPath("lesson/qrcode", ".jpg"); //把最终图片上传到OSS里
            OssFileUtil.uploadFile(in, uploadPathReal); //返回最终图片上传到OSS里的路径
            return uploadPathReal;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
                if (os != null) {
                    os.close();
                }
                if (is != null) {
                    is.close();
                }
                delLock(jedisUtil, key);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    private boolean lock(JedisUtil jedisUtil, String key) {
        if (jedisUtil.setnx(key, "1", 1 * 10) <= 0) {
            return false;
        }
        return true;
    }

    private boolean delLock(JedisUtil jedisUtil, String key) {
        if (jedisUtil.del(key) > 0) {
            return true;
        }
        return false;
    }

    /**
     * 获取图片流 * * @param fileUrl http://url:port/store/lesson/qrcode/2018/07/12909064255321.jpg * @return InputStream
     */
    public static InputStream readFile(String fileUrl) {
        if (StringUtils.isBlank(fileUrl)) {
            return null;
        }
        try {
            URL url = new URL(fileUrl);
            HttpURLConnection urlCon = (HttpURLConnection) url.openConnection();
            urlCon.setConnectTimeout(6000);
            urlCon.setReadTimeout(6000);
            int code = urlCon.getResponseCode();
            if (code != HttpURLConnection.HTTP_OK) {
                throw new Exception("文件读取失败");
            }
            return urlCon.getInputStream();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 改变图片尺寸
     *
     * @param imgUrl 图片的路径 domail + path
     * @param width  修改后的宽度
     * @param height 修改后的高度
     * @return 并返回BufferedImage对象
     */
    public static BufferedImage getBufferedImage(String imgUrl, String path, int width, int height) {
        if (StringUtils.isBlank(imgUrl)) {
            return null;
        }
        try {
            BufferedImage bi = ImageIO.read(new URL(imgUrl));
            BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            tag.getGraphics().drawImage(bi, 0, 0, width, height, null);
            ByteArrayOutputStream bs = new ByteArrayOutputStream();
            ImageOutputStream imOut = ImageIO.createImageOutputStream(bs);
            ImageIO.write(tag, "jpg", imOut);
            InputStream is = new ByteArrayInputStream(bs.toByteArray());
            JPEGImageDecoder jpegDecoder = JPEGCodec.createJPEGDecoder(is);
            BufferedImage buffImg = jpegDecoder.decodeAsBufferedImage();
            return buffImg;

        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 把头像裁剪成圆形
     *
     * @param headImg 图片的完整地址 domail + path
     * @return 并返回BufferedImage对象
     */

    public static BufferedImage roundImg(String headImg) {
        if (StringUtils.isBlank(headImg)) {
            return null;
        }
        try {
            BufferedImage bi1 = ImageIO.read(new URL(headImg));
            BufferedImage bi2 = new BufferedImage(bi1.getWidth(), bi1.getHeight(), BufferedImage.TYPE_INT_RGB);
            Ellipse2D.Double shape = new Ellipse2D.Double(0, 0, bi1.getWidth(), bi1.getHeight());
            Graphics2D g2 = bi2.createGraphics();
            g2.setBackground(Color.WHITE);
            g2.fill(new Rectangle(bi2.getWidth(), bi2.getHeight()));
            g2.setClip(shape); // 使用 setRenderingHint 设置抗锯齿
            g2.drawImage(bi1, 0, 0, null);
            g2.dispose();
            ByteArrayOutputStream bs = new ByteArrayOutputStream();
            ImageOutputStream imOut = ImageIO.createImageOutputStream(bs);
            ImageIO.write(bi2, "jpg", imOut);
            InputStream is = new ByteArrayInputStream(bs.toByteArray());
            JPEGImageDecoder jpegDecoder = JPEGCodec.createJPEGDecoder(is);
            BufferedImage buffImg = jpegDecoder.decodeAsBufferedImage();
            return buffImg;

        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}


}

因为 import com.sun.image.codec.jpeg.JPEGCodec;

这个在jdk1.7还是1.6以后就不建议使用了,如果我们要用的话,就要在

pom文件里配置下,打包的时候把rt.jar包打进去

<build>
        <filters>
            <filter>../build/${env}.properties</filter>
        </filters>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>3.0.0</version>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.6.1</version>
                    <configuration>
                        <source>${java.version}</source>
                        <target>${java.version}</target>
                        <!-- 解决jdk1.6以上不识别JPEGCodec问题-->
                        <compilerArguments>
                            <verbose />
                            <bootclasspath>${java.home}/lib/rt.jar;${java.home}/lib/jce.jar</bootclasspath>
                        </compilerArguments>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.eclipse.jetty</groupId>
                    <artifactId>jetty-maven-plugin</artifactId>
                    <version>9.3.6.v20151106</version>
                    <configuration>
                        <scanIntervalSeconds>0</scanIntervalSeconds>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

这样就可以了,但是会有两个问题:

1、本身jdk就不建议使用,用起来不优雅

2、打包的时候要把rt.jar打进来,导致东西变多,打包变慢

所以我还在寻找更好的方法,把上面的给替换掉

下一篇我会对本篇文章的代码进行优化

java实现图片的组合(二)


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

maple 枫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值