zoukankan      html  css  js  c++  java
  • 两张图片合并生成

    java中偶尔会出现需要将一张小图片嵌入大图中或带二维码的海报图片,那么本文就是奔着这个目的来的,直接上腊肉!

    zxing是生成1D和2D条形或二维码的工具类库,java图形库Graphics2D进行图片的合成。

    依赖:

    <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>core</artifactId>
        <version>3.3.3</version>
    </dependency>

    代码:
    以下为合成图片和二维码,合成2张图片参看第一个方法注释掉的代码
     

    /*
     * overlapImage
     * @description:合成二维码和图片为文件
     * @author 李阳
     * @date 2018/12/13
     * @params [backPicPath, code]
     * @return void
     */
    public static final void combineCodeAndPicToFile(String backPicPath, BufferedImage code/*String fillPicPath*/) {
        try {
            BufferedImage big = ImageIO.read(new File(backPicPath));
            BufferedImage small = code;
            /*//合成两个文件时使用
            BufferedImage small = ImageIO.read(new File(fillPicPath));*/
            Graphics2D g = big.createGraphics();
    
            //二维码或小图在大图的左上角坐标
            int x = (big.getWidth() - small.getWidth()) / 2;
            // int y = (big.getHeight() - small.getHeight()) / 2;
            int y = (big.getHeight() - small.getHeight() - 100);
            g.drawImage(small, x, y, small.getWidth(), small.getHeight(), null);
            g.dispose();
            //为了保证大图背景不变色,formatName必须为"png"
            ImageIO.write(big, "png", new File("C:/Users/kevin/Desktop/combinePic.jpg"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /* 
     * combineCodeAndPicToInputstream
     * @description:合成二维码和图片为输出流,可用于下载或直接展示
     * @author 李阳
     * @date 2018/12/13
     * @params [backPicPath, code]
     * @return java.io.InputStream
     */
    public static final void combineCodeAndPicToInputstream(String backPicPath, BufferedImage code, HttpServletResponse resp) {
        try {
            BufferedImage big = ImageIO.read(new File(backPicPath));
            // BufferedImage small = ImageIO.read(new File(fillPicPath));
            BufferedImage small = code;
            Graphics2D g = big.createGraphics();
    
            //二维码或小图在大图的左上角坐标
            int x = (big.getWidth() - small.getWidth()) / 2;
            int y = (big.getHeight() - small.getHeight() - 100);   //二维码距大图下边距100
            g.drawImage(small, x, y, small.getWidth(), small.getHeight(), null);
            g.dispose();
            resp.addHeader("Content-Disposition", "attachment;filename="+ URLEncoder.encode("lia阿里.png","UTF-8") );//去掉这行设置header的代码,前端访问可以直接展示
            //为了保证大图背景不变色,formatName必须为"png"
            ImageIO.write(big, "png", resp.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /* 
     * combineCodeAndPicToBase64 
     * @description:合成二维码和图片为Base64,同样可用于直接展示
     * @author 李阳
     * @date 2018/12/14
     * @params [backPicPath, code]
     * @return java.lang.String
     */
    public static final String combineCodeAndPicToBase64(String backPicPath, BufferedImage code) {
        ImageOutputStream imOut = null;
        try {
            BufferedImage big = ImageIO.read(new File(backPicPath));
            // BufferedImage small = ImageIO.read(new File(fillPicPath));
            BufferedImage small = code;
            Graphics2D g = big.createGraphics();
    
            //二维码或小图在大图的左上角坐标
            int x = (big.getWidth() - small.getWidth()) / 2;
            int y = (big.getHeight() - small.getHeight() - 100);
            g.drawImage(small, x, y, small.getWidth(), small.getHeight(), null);
            g.dispose();
            //为了保证大图背景不变色,formatName必须为"png"
    
            ByteArrayOutputStream bs = new ByteArrayOutputStream();
            imOut = ImageIO.createImageOutputStream(bs);
            ImageIO.write(big, "png", imOut);
            InputStream in = new ByteArrayInputStream(bs.toByteArray());
    
            byte[] bytes = new byte[in.available()];
            in.read(bytes);
            String base64 = Base64.getEncoder().encodeToString(bytes);
            System.out.println(base64);
    
            return "data:image/jpeg;base64," + base64;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /* 
     * createImage 
     * @description:生成二维码
     * @author 李阳
     * @date 2018/12/13
     * @params [content 二维码内容, logoImgPath 中间logo, needCompress 是否压缩]
     * @return java.awt.image.BufferedImage
     */
    private static BufferedImage createImage(String content, String logoImgPath, boolean needCompress) throws IOException, WriterException {
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        //200是定义的二维码或小图片的大小
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, 200, 200, hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        //循环遍历每一个像素点
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        // 没有logo
        if (logoImgPath == null || "".equals(logoImgPath)) {
            return image;
        }
    
        // 插入logo
        insertImage(image, logoImgPath, needCompress);
        return image;
    }
    
    /* 
     * insertImage 
     * @description:二维码插入logo
     * @author 李阳
     * @date 2018/12/13
     * @params [source, logoImgPath, needCompress]
     * @return void
     */
    private static void insertImage(BufferedImage source, String logoImgPath, boolean needCompress) throws IOException {
        File file = new File(logoImgPath);
        if (!file.exists()) {
            return;
        }
    
        Image src = ImageIO.read(new File(logoImgPath));
        int width = src.getWidth(null);
        int height = src.getHeight(null);
        //处理logo
        if (needCompress) {
            if (width > WIDTH) {
                width = WIDTH;
            }
    
            if (height > HEIGHT) {
                height = HEIGHT;
            }
    
            Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
            BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics gMaker = tag.getGraphics();
            gMaker.drawImage(image, 0, 0, null); // 绘制缩小后的图
            gMaker.dispose();
            src = image;
        }
    
        // 在中心位置插入logo
        Graphics2D graph = source.createGraphics();
        int x = (200 - width) / 2;
        int y = (200 - height) / 2;
        graph.drawImage(src, x, y, width, height, null);
        Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
        graph.setStroke(new BasicStroke(3f));
        graph.draw(shape);
        graph.dispose();
    }
    
    public static final void main(String[] args) throws IOException, WriterException {
        BufferedImage code = createImage("https://my.oschina.net/kevin2kelly", null, false);
        combineCodeAndPicToFile("C:/Users/kevin/Desktop/无标题.png", code);
        combineCodeAndPicToBase64("C:/Users/kevin/Desktop/无标题.png", code);
    }

    自己的代码:

    package com.lingouu.tools.picutre;
    
    import com.google.zxing.BarcodeFormat;
    import com.google.zxing.EncodeHintType;
    import com.google.zxing.MultiFormatWriter;
    import com.google.zxing.WriterException;
    import com.google.zxing.common.BitMatrix;
    import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    import sun.font.FontDesignMetrics;
    
    import javax.imageio.ImageIO;
    import javax.persistence.GeneratedValue;
    import javax.servlet.http.HttpServletResponse;
    import java.awt.*;
    import java.awt.font.GlyphVector;
    import java.awt.geom.Ellipse2D;
    import java.awt.image.BufferedImage;
    import java.io.*;
    import java.net.URL;
    import java.util.Hashtable;
    
    import static org.apache.catalina.manager.Constants.CHARSET;
    
    @Component
    @Slf4j
    public class PictureUtils {
    
    
        public static void combineCodeAndPic(String headImgUrl, String nickName, String backPicPath, String codePath, HttpServletResponse resp) {
            BufferedImage backPic = null;
            BufferedImage code = null;
            BufferedImage headImg = null;
            try {
                headImg = generateRoundness(headImgUrl);
                code = ImageIO.read(new URL(codePath));
                backPic = ImageIO.read(new URL(backPicPath));
            } catch (IOException e) {
                log.error("分享图生成失败", e);
            }
            combineCodeAndPic(nickName + "向你推荐了灵狗优优",headImg, backPic, code, resp);
        }
    
        public static void generateCodeAndPic(String backPicPath, String pathUrl, HttpServletResponse resp) {
            BufferedImage backPic = null;
            BufferedImage code = null;
            try {
                backPic = ImageIO.read(new URL(backPicPath));
                code = createCode(pathUrl);
            } catch (Exception e) {
                log.error("分享图生成失败", e);
            }
            combineCodeAndPic(backPic, code, resp);
        }
    
        private static void combineCodeAndPic(BufferedImage backPic, BufferedImage code, HttpServletResponse resp) {
            try {
                Graphics2D g = backPic.createGraphics();
                g.drawImage(code, 384, 598, 83, 83, null);
                g.dispose();
    //            resp.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("back.png", "UTF-8"));//去掉这行设置header的代码,前端访问可以直接展示
                ImageIO.write(backPic, "png", resp.getOutputStream());
            } catch (Exception e) {
                log.error("课程分享图片生成失败", e);
            }
        }
    
        private static void combineCodeAndPic(String fontImg,BufferedImage headImg, BufferedImage backPic, BufferedImage code, HttpServletResponse resp) {
            try {
                Graphics2D g = backPic.createGraphics();
                g.drawImage(code, 215, 685, 185, 185, null);
                g.drawImage(headImg, 130, 93, 95, 95, null);
    //            g.drawImage(fontImg, 300, 143, fontImg.getWidth(), fontImg.getHeight(), null);
                //写字
                g.setFont(new Font("宋体",Font.BOLD,15));
                g.drawString(fontImg,230,165);
                g.dispose();
    //            resp.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("back.png", "UTF-8"));//去掉这行设置header的代码,前端访问可以直接展示
                ImageIO.write(backPic, "png", resp.getOutputStream());
            } catch (Exception e) {
                log.error("邀请图片生成失败", e);
            }
        }
    
        /*
         * @description:生成二维码
         * @params [content 二维码内容, needCompress 是否压缩]
         * @return java.awt.image.BufferedImage
         */
        private static BufferedImage createCode(String content) throws IOException, WriterException {
            Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
            hints.put(EncodeHintType.MARGIN, 1);
            //200是定义的二维码或小图片的大小
            BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, 430, 430, hints);
            int width = bitMatrix.getWidth();
            int height = bitMatrix.getHeight();
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            //循环遍历每一个像素点
            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
                }
            }
            return image;
        }
    
        /**
         * @param filePath
         * @return
         * @throws Exception
         */
        private static BufferedImage generateRoundness(String filePath) throws IOException {
            BufferedImage bi1 = ImageIO.read(new URL(filePath));
            // 根据需要是否使用 BufferedImage.TYPE_INT_ARGB
            BufferedImage image = new BufferedImage(bi1.getWidth(), bi1.getHeight(), BufferedImage.TYPE_INT_ARGB);
            Ellipse2D.Double shape = new Ellipse2D.Double(0, 0, bi1.getWidth(), bi1.getHeight());
            Graphics2D g2 = image.createGraphics();
            image = g2.getDeviceConfiguration().createCompatibleImage(bi1.getWidth(), bi1.getHeight(), Transparency.TRANSLUCENT);
            g2 = image.createGraphics();
            g2.setComposite(AlphaComposite.Clear);
            g2.fill(new Rectangle(image.getWidth(), image.getHeight()));
            g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, 1.0f));
            g2.setClip(shape);
            // 使用 setRenderingHint 设置抗锯齿
            RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            rh.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
            rh.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            g2.setRenderingHints(rh);
            g2.drawImage(bi1, 0, 0, null);
            g2.dispose();
    
    //        ByteArrayOutputStream out = new ByteArrayOutputStream();
    //        ImageIO.write(image, "png", out);
    //        ByteArrayInputStream inputStream = new ByteArrayInputStream(out.toByteArray());
            return image;
        }
    }
    View Code

    填充图片:


    背景图和合成图片:
    图一为原始背景图,第二图为base64在浏览器访问效果,三为2张图合成,四图为图片和二维码合成。

    参考:
    http://www.zhaochengquan.com/2018/03/29/%E5%9F%BA%E4%BA%8EZXing%E7%9A%84%E4%BA%8C%E7%BB%B4%E7%A0%81%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90%E4%B8%8E%E5%9B%BE%E7%89%87%E5%90%88%E6%88%90/

    https://blog.csdn.net/qq_35971258/article/details/80593500

  • 相关阅读:
    Word Puzzles [POJ 1204]
    set用法
    FOJ有奖月赛2012年11月
    BerDonalds
    POJ1469 匈牙利算法
    后缀数组
    ZOJ Monthly, January 2013
    算法导论<一>
    Yell Classico
    点聚 WebOffice 编辑辅助控件 WebOffice.OCX
  • 原文地址:https://www.cnblogs.com/cl-rr/p/11910552.html
Copyright © 2011-2022 走看看