前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

1、多个图片合成

2、生成不带logo的二维码

3、读取图片二维码信息

4、生成带logo的二维码

5、图片压缩

6、文字水印到图片

7、图片水印到图片

8、 添加图片水印

9、解决图片红色问题 ,JDK中提供的Image

10、自己做图片 ,根据文本宽度进行换行

package com.hlj.util.QRcode;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.junit.Test;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

/**
 * 作者 :HealerJean
 * 日期 :2018/10/29  下午4:31.
 * 类描述:
 */
public class QrCodeUtils {


    /**
     *
     * 1、 输出图片到本地目录
     * @param buffImg 图片
     * @param savePath 本地目录的路径
     */
    public static void  saveImageToLocalDir(BufferedImage buffImg, String savePath) {
        try {
            ImageIO.write(buffImg, "jpg", new File(savePath));
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }



    /**
     *
     * 2、 方法描述: 多个图片合成
     * exImage 底图
     * innerImage 嵌入的图片
     * x 坐标x
     * y 坐标y
     * innerImageWedith 嵌入图片的长度
     * innerImageHeight 嵌入图片的宽度
     */
    public  static BufferedImage imageAndImages(BufferedImage exImage, BufferedImage innerImage, int x, int y, int innerImageWedith, int innerImageHeight, float alpha) throws IOException {
        Graphics2D g2d = exImage.createGraphics();
        // 在图形和图像中实现混合和透明效果
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
        // 绘制
        g2d.drawImage(innerImage, x, y, innerImageWedith, innerImageHeight, null);
        g2d.dispose();// 释放图形上下文使用的系统资源
        return exImage;
    }

    /**
     * 2、测试 多个图片合成
     */
    @Test
    public void testimageAndImages(){

        String sourceFilePath = "/Users/healerjean/Desktop/origin.jpeg";
        String innerImageFilePath = "/Users/healerjean/Desktop/img.jpeg";
        // 构建叠加层
        BufferedImage buffImg = null;
        try {
            buffImg = imageAndImages(ImageIO.read(new File(sourceFilePath)), ImageIO.read(new File(innerImageFilePath)),238, 588,210 ,208, 1.0f);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 输出水印图片
        String saveFilePath = "/Users/healerjean/Desktop/new.png";
        saveImageToLocalDir(buffImg, saveFilePath);
    }


    /**
     * 3、不带logo的二维码
     *
     * @param text 二维码内容
     * @param width 二维码宽度
     * @param height 长度
     * @param whiteSize 白边大小
     * @return
     */
    public static BufferedImage writeQRImg(String text,int width,int height,int whiteSize){
        // 配置参数
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        // 字符编码
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        // 容错级别
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);

        // 设置空白边距的宽度
        hints.put(EncodeHintType.MARGIN, whiteSize); // 默认是4

        // 1、生成二维码
        BitMatrix bitMatrix = null;
        try {
            bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);
        } catch (WriterException e) {
            e.printStackTrace();
        }

        // 2、获取二维码宽高
        int codeWidth = bitMatrix.getWidth();
        int codeHeight = bitMatrix.getHeight();

        // 3、将二维码放入缓冲流
        BufferedImage image = new BufferedImage(codeWidth, codeHeight, BufferedImage.TYPE_INT_RGB);

        for (int i = 0; i < codeWidth; i++) {
            for (int j = 0; j < codeHeight; j++) {
                // 4、循环将二维码内容定入图片
                //判断 BitMatrix 是否存在像素  二维码填充颜色 黑色  0XFF000000 白色 :0xFF是补码 0XFFFFFFFF
                image.setRGB(i, j, bitMatrix.get(i, j) ? 0XFF000000 : 0XFFFFFFFF);
            }
        }

        return image ;
    }

    /**
     * 3、测试 不带logo的二维码
     * @throws Exception
     */
    @Test
    public void testWriteQRImg(){
        String text = "http://blog.healerjean.top";
        BufferedImage  noLogoImage = writeQRImg(text,200,200, 4 );
        //存储到本地
        String saveFilePath = "/Users/healerjean/Desktop/new.png";
        saveImageToLocalDir(noLogoImage, saveFilePath);
    }





    /**
     *  4、 读取二维码的文件里面的信息
     */
    public static String readQRImg(BufferedImage image) throws Exception {

        LuminanceSource source = new BufferedImageLuminanceSource(image);
        Binarizer binarizer = new HybridBinarizer(source);
        BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
        Map<DecodeHintType, Object> hints = new HashMap<DecodeHintType, Object>();
        // 字符编码
        hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
        Result result = new MultiFormatReader().decode(binaryBitmap, hints);// 对图像进行解码
        return result.getText();
    }

    /**
     * 4、测试 读取二维码信息
     * @throws Exception
     */
    @Test
    public void testReadQRImg() throws Exception{
        //读取二维码信息
        String filePath = "/Users/healerjean/Desktop/new.png";
        BufferedImage image = ImageIO.read(new File(filePath));
        String info =readQRImg(image);
        System.out.println(info);
    }



    /**
     *   5、 生成带logo的二维码
     *
     *
     * @param text 二维码内容
     * @param text 二维码内容
     * @param width 二维码宽度
     * @param height 长度
     * @param whiteSize 白边大小
     * @param logo LOGO图片
     * @return
     * @throws Exception
     */
    public static BufferedImage createLogoQRImg(String text,int width,int height, int whiteSize,BufferedImage logo) throws Exception {
        // 配置参数
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        // 字符编码
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        // 容错级别
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);

        // 设置空白边距的宽度
        hints.put(EncodeHintType.MARGIN, whiteSize); // 默认是4

        // 1、生成二维码
        BitMatrix bitMatrix = null;
        try {
            bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);
        } catch (WriterException e) {
            e.printStackTrace();
        }

        // 2、获取二维码宽高
        int codeWidth = bitMatrix.getWidth();
        int codeHeight = bitMatrix.getHeight();

        // 3、将二维码放入缓冲流
        BufferedImage image = new BufferedImage(codeWidth, codeHeight, BufferedImage.TYPE_INT_RGB);

        for (int i = 0; i < codeWidth; i++) {
            for (int j = 0; j < codeHeight; j++) {
                // 4、循环将二维码内容定入图片
                //判断 BitMatrix 是否存在像素  二维码填充颜色 黑色  0XFF000000 白色 :0xFF是补码 0XFFFFFFFF
                image.setRGB(i, j, bitMatrix.get(i, j) ? 0XFF000000 : 0XFFFFFFFF);
            }
        }

            //在原来基础上,再添加一个图片
            Graphics2D g = image.createGraphics();
            int widthLogo = logo.getWidth(null) > image.getWidth() * 2 / 10 ?
                    (image.getWidth() * 2 / 10) : logo.getWidth(null);
            int heightLogo = logo.getHeight(null) > image.getHeight() * 2 / 10 ?
                    (image.getHeight() * 2 / 10) : logo.getHeight(null);

            //设定在图片中间
            int x = (image.getWidth() - widthLogo) / 2;
            int y = (image.getHeight() - heightLogo) / 2;

            // 开始绘制图片
            g.drawImage(logo, x, y, widthLogo, heightLogo, null);

            //绘制圆角矩形
            g.drawRoundRect(x, y, widthLogo, heightLogo, 15, 15);

            //边框宽度
            g.setStroke(new BasicStroke(2));

            //边框颜色
            g.setColor(Color.WHITE);
            g.drawRect(x, y, widthLogo, heightLogo);

            g.dispose();
            logo.flush();
            image.flush();
            return image;
    }




    /**
     * 5、测试 带logo的二维码
     * @throws Exception
     */
    @Test
    public void testWriteQRImgWithLogo() throws Exception{
        String text = "http://blog.healerjean.top";
        String logoPath = "/Users/healerjean/Desktop/logo.png";
        BufferedImage logo = ImageIO.read(new File(logoPath));
        BufferedImage  logoImage = createLogoQRImg(text,200,200, 1 ,logo);

        //存储到本地
        String saveFilePath = "/Users/healerjean/Desktop/new.png";
        saveImageToLocalDir(logoImage, saveFilePath);
    }


    /**
     * 6/ 指定图片宽度和高度和压缩比例对图片进行压缩
     * @param widthdist 压缩后图片的宽度
     * @param heightdist 压缩后图片的高度
     * @param rate 压缩的比例 ,可以设置为null
     */
    public static BufferedImage reduceImg(BufferedImage bufferedImage, int widthdist, int heightdist, Float rate) {
        try {

            // 如果比例不为空则说明是按比例压缩
            if (rate != null && rate > 0) {
                //获得源图片的宽高存入数组中
                int results[] = { 0, 0 };
                results[0] =bufferedImage.getWidth(null); // 得到源图片宽
                results[1] =bufferedImage.getHeight(null);// 得到源图片高

                if (results == null || results[0] == 0 || results[1] == 0) {
                    return null;
                } else {
                    //按比例缩放或扩大图片大小,将浮点型转为整型
                    widthdist = (int) (results[0] * rate);
                    heightdist = (int) (results[1] * rate);
                }
            }
            // 开始读取文件并进行压缩
            Image src = (Image) bufferedImage;
            // 构造一个类型为预定义图像类型之一的 BufferedImage
            BufferedImage tag = new BufferedImage((int) widthdist, (int) heightdist, BufferedImage.TYPE_INT_RGB);
            //绘制图像  getScaledInstance表示创建此图像的缩放版本,返回一个新的缩放版本Image,按指定的width,height呈现图像
            //Image.SCALE_SMOOTH,选择图像平滑度比缩放速度具有更高优先级的图像缩放算法。
            tag.getGraphics().drawImage(src.getScaledInstance(widthdist, heightdist, Image.SCALE_SMOOTH), 0, 0, null);

            return tag;
        } catch (Exception ef) {
            ef.printStackTrace();
        }
        return  null;
    }

    /**
     * 6 测试
     * @throws IOException
     */
    @Test
    public void testReduceImg() throws IOException {
        String reducePath = "/Users/healerjean/Desktop/reduce.png";
        BufferedImage originImage = ImageIO.read(new File(reducePath));
        BufferedImage  reduceImg = reduceImg(originImage,200,200, null );

        //存储到本地
        String saveFilePath = "/Users/healerjean/Desktop/new.png";
        saveImageToLocalDir(reduceImg, saveFilePath);
    }


    /**
     *  7、 添加文字水印
     * @param image 需要加水印的文件
     * @param waterText 水印文本
     * @param moreMark  是否是多个水印 true多个水印   /false 或不写,一个水印
     * @return
     */
    public static BufferedImage textWaterMark(BufferedImage image,String waterText, boolean... moreMark) {

            //字体样式
            int FONT_STYLE = Font.BOLD;
            //字体大小
            int FONT_SIZE = 50;
            //字体颜色
            Color FONT_COLOR = Color.black;
            //字体颜色
            String FONT_NAME = "微软雅黑";
            //透明度
            float ALPHA = 0.3F;

            //多图的情况下,水印的间距
            Integer MORE_MARK_DISTANCE = 100;

            //计算原始图片宽度长度
            int width = image.getWidth();
            int height = image.getHeight();
            //创建图片缓存对象
            BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            //创建java绘图工具对象
            Graphics2D graphics2d = bufferedImage.createGraphics();
            //参数主要是,原图,坐标,宽高
            graphics2d.drawImage(image, 0, 0, width, height, null);

            //使用绘图工具将水印绘制到图片上
            //计算文字水印宽高值
            int waterWidth = FONT_SIZE*getTextLength(waterText);
            int waterHeight = FONT_SIZE;
            //水印透明设置
            graphics2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, ALPHA));
            graphics2d.setFont(new Font(FONT_NAME, FONT_STYLE, FONT_SIZE));
            graphics2d.setColor(FONT_COLOR);

            if(moreMark!= null && moreMark.length >0 && moreMark[0]){
                //设定旋转 , 后面两个参数表示的是围绕那个坐标
                graphics2d.rotate(Math.toRadians(-30), bufferedImage.getWidth()/2, bufferedImage.getHeight()/2);

                int x = -width/2;
                int y = -height/2;

                while(x < width*1.5){
                    y = -height/2;
                    while(y < height*1.5){
                        graphics2d.drawString(waterText, x, y);
                        //水印的间距
                        y+=waterHeight+MORE_MARK_DISTANCE;
                    }
                    x+=waterWidth+MORE_MARK_DISTANCE;
                }
            }else{
                graphics2d.drawString(waterText, width-waterWidth, height);
            }

            //写图片
            graphics2d.dispose();
            return  bufferedImage;
    }
    /**
     * 计算水印文本长度
     *
     * 中文长度即文本长度 2、英文长度为文本长度二分之一
     * @param text
     * @return
     */
    private static int getTextLength(String text){
        //水印文字长度
        int length = text.length();

        for (int i = 0; i < text.length(); i++) {
            String s =String.valueOf(text.charAt(i));
            if (s.getBytes().length>1) {
                length++;
            }
        }
        length = length%2==0?length/2:length/2+1;
        return length;
    }

    @Test
    public void testTextWaterMark() throws IOException {
        String originPath = "/Users/healerjean/Desktop/reduce.png";
        BufferedImage originImage = ImageIO.read(new File(originPath));
        BufferedImage newImage = textWaterMark(originImage,"healerjean",true);

        //存储到本地
        String saveFilePath = "/Users/healerjean/Desktop/new.png";
        saveImageToLocalDir(newImage, saveFilePath);
    }





    /**
     * 8、 添加图片水印
     * @param srcFile 需要家水印的文件路径
     * @return
     */
    public static BufferedImage imageWaterMark(BufferedImage image,BufferedImage imageLogo, boolean... moreMark) {
        //字体样式
        int FONT_STYLE = Font.BOLD;
        //字体大小
        int FONT_SIZE = 50;
        //字体颜色
        Color FONT_COLOR = Color.black;
        //字体颜色
        String FONT_NAME = "微软雅黑";
        //透明度
        float ALPHA = 0.3F;
        //多图的情况下,水印的间距
        Integer MORE_MARK_DISTANCE = 100;

        int X = 636;
        int Y = 763;
            //计算原始图片宽度长度
            int width = image.getWidth(null);
            int height = image.getHeight(null);
            //创建图片缓存对象
            BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            //创建java绘图工具对象
            Graphics2D graphics2d = bufferedImage.createGraphics();
            //参数主要是,原图,坐标,宽高
            graphics2d.drawImage(image, 0, 0, width, height, null);
            graphics2d.setFont(new Font(FONT_NAME, FONT_STYLE, FONT_SIZE));
            graphics2d.setColor(FONT_COLOR);

            //水印图片路径
            int widthLogo = imageLogo.getWidth(null);
            int heightLogo = imageLogo.getHeight(null);
            int widthDiff = width-widthLogo;
            int heightDiff = height-heightLogo;
            //水印坐标设置
            if (X > widthDiff) {
                X = widthDiff;
            }
            if (Y > heightDiff) {
                Y = heightDiff;
            }
            //水印透明设置
            graphics2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, ALPHA));

            if(moreMark!= null && moreMark.length >0 && moreMark[0]){
                graphics2d.rotate(Math.toRadians(-30), bufferedImage.getWidth()/2, bufferedImage.getHeight()/2);

                int x = -width/2;
                int y = -height/2;

                while(x < width*1.5){
                    y = -height/2;
                    while(y < height*1.5){
                        graphics2d.drawImage(imageLogo, x, y, null);
                        y+=heightLogo+MORE_MARK_DISTANCE;
                    }
                    x+=widthLogo+MORE_MARK_DISTANCE;
                }
            }else{
                graphics2d.drawImage(imageLogo, X, Y, null);
            }

            graphics2d.dispose();

            return  bufferedImage;

    }




    @Test
    public void testImageWaterMark() throws IOException {
        String originPath = "/Users/healerjean/Desktop/reduce.png";
        BufferedImage originImage = ImageIO.read(new File(originPath));


        String logoPath = "/Users/healerjean/Desktop/origin.jpeg";
        BufferedImage logoImage = ImageIO.read(new File(logoPath));

        BufferedImage newImage = imageWaterMark(originImage,logoImage,true);

        //存储到本地
        String saveFilePath = "/Users/healerjean/Desktop/new.png";
        saveImageToLocalDir(newImage, saveFilePath);
    }



		/**
		 *  9、解决图片红色问题 ,JDK中提供的Image
		
		 //如果是file
		 Image src=Toolkit.getDefaultToolkit().getImage(file.getPath());

		
		 如果是url
		 URL url = new URL(wechat_erweimaTmail);
		 java.awt.Image imageTookittitle = Toolkit.getDefaultToolkit().createImage(url);
		 BufferedImage titleLab = ImageUtils.toBufferedImage(imageTookittitle);
		
		 * @param image
		 * @return
		 */
		public static BufferedImage toBufferedImage(Image image) {
		    if (image instanceof BufferedImage) {
		        return (BufferedImage) image;
		    }
		    // This code ensures that all the pixels in the image are loaded
		    image = new ImageIcon(image).getImage();
		    BufferedImage bimage = null;
		    GraphicsEnvironment ge = GraphicsEnvironment
		            .getLocalGraphicsEnvironment();
		    try {
		        int transparency = Transparency.OPAQUE;
		        GraphicsDevice gs = ge.getDefaultScreenDevice();
		        GraphicsConfiguration gc = gs.getDefaultConfiguration();
		        bimage = gc.createCompatibleImage(image.getWidth(null),
		                image.getHeight(null), transparency);
		    } catch (HeadlessException e) {
		        // The system does not have a screen
		    }
		    if (bimage == null) {
		        // Create a buffered image using the default color model
		        int type = BufferedImage.TYPE_INT_RGB;
		        bimage = new BufferedImage(image.getWidth(null),
		                image.getHeight(null), type);
		    }
		    // Copy image to buffered image
		    Graphics g = bimage.createGraphics();
		    // Paint the image onto the buffered image
		    g.drawImage(image, 0, 0, null);
		    g.dispose();
		    return bimage;
		}
		
		
		
		
    /**
     * 10、自己做图片 ,根据文本宽度进行换行
     */
    @Test
    public void creatMyImage(){

        //整体图合成
        BufferedImage bufferedImage = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB);
        //设置图片的背景色
        Graphics2D main = bufferedImage.createGraphics();
        main.fillRect(0, 0, 500, 500);

        String text = "111122223所以比传统纸巾更环保3334441比传统纸巾更环11111111111111122223所以比传统纸巾更环保3334441比传统纸巾更环11111111111111122223所以比传统纸巾更环保3334441比传统纸巾更环11111111111111122223所以比传统纸巾更环保3334441比传统纸巾更环11111111111";

        Graphics2D textG = bufferedImage.createGraphics() ;

        textG.setColor(new Color(37,37,37));
        Font hualaoContentFont = new Font("PingFang SC", Font.PLAIN, 20);
        textG.setFont(hualaoContentFont);
        textG.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);
        drawString(textG,text,30,100,4,10,50,true,false);

        //存储到本地
        String saveFilePath = "/Users/healerjean/Desktop/new.png";
        saveImageToLocalDir(bufferedImage, saveFilePath);

    }


    /**
     *
     * @param g
     * @param text 文本
     * @param lineHeight 行高(注意字体大小的控制哦)
     * @param maxWidth 行宽
     * @param maxLine 最大行数
     * @param left 左边距 //整段文字的左边距
     * @param top 上边距 //整顿文字的上边距
     * @param trim 是否修剪文本(1、去除首尾空格,2、将多个换行符替换为一个)
     * @param lineIndent 是否首行缩进
     */
    public static void drawString(Graphics2D g, String text, float lineHeight, float maxWidth, int maxLine, float left,
                                  float top, boolean trim, boolean lineIndent) {
        if (text == null || text.length() == 0) return;
        if(trim) {
            text = text.replaceAll("\\n+", "\n").trim();
        }
        if(lineIndent) {
            text = "  " + text.replaceAll("\\n", "\n  ");
        }
        drawString(g, text, lineHeight, maxWidth, maxLine, left, top);
    }

    /**
     *
     * @param g
     * @param text 文本
     * @param lineHeight 行高
     * @param maxWidth 行宽
     * @param maxLine 最大行数
     * @param left 左边距
     * @param top 上边距
     */
    private static void drawString(Graphics2D g, String text, float lineHeight, float maxWidth, int maxLine, float left,
                                   float top) {
        if (text == null || text.length() == 0) return;

        FontMetrics fm = g.getFontMetrics();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < text.length(); i++) {
            char c = text.charAt(i);
            sb.append(c);
            int stringWidth = fm.stringWidth(sb.toString());
            if (c == '\n' || stringWidth > maxWidth) {
                if(c == '\n') {
                    i += 1;
                }
                if (maxLine > 1) {
                    g.drawString(text.substring(0, i), left, top);
                    drawString(g, text.substring(i), lineHeight, maxWidth, maxLine - 1, left, top + lineHeight);
                } else {
                    g.drawString(text.substring(0, i - 1) + "…", left, top);
                }
                return;
            }
        }
        g.drawString(text, left, top);
    }****
		
		
		

}



ContactAuthor