【java】google的zxing架包生成二維碼和讀取二維碼【可帶文字和logo】

承接RC4生成不重複字符串的需求以後,由於優惠碼要方便用戶使用的緣故,因此思來想去,以爲仍是直接生成二維碼給用戶直接掃比較實用,也不用用戶專門記錄冗長的優惠碼編號。html

========================================================java

因此這一章,就先把java生成二維碼【可帶logo和文字】作一記錄,使用google的工具包zxingspring

========================================================maven

1.maven依賴ide

<!-- google提供二維碼生成和解析https://mvnrepository.com/artifact/com.google.zxing/core -->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.3.2</version>
        </dependency>

2.完整代碼工具

package testExample;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;

import com.google.zxing.*;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.springframework.util.StringUtils;

import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

/**
 * 二維碼工具類
 * @author SXD
 * @Date 2018.2.1
 *
 */
public class QR_Code {
    private static int BLACK = 0x000000;
    private static int WHITE = 0xFFFFFF;

    /**
     * 內部類,設置二維碼相關參數
     */
    @Data(staticConstructor = "of")
    @NoArgsConstructor
    @AllArgsConstructor
    @Accessors(chain = true)
    public  class CodeModel {
        /**
         * 正文
         */
        private String contents;
        /**
         * 二維碼寬度
         */
        private int width = 400;
        /**
         * 二維碼高度
         */
        private int height = 400;
        /**
         * 圖片格式
         */
        private String format = "png";
        /**
         * 編碼方式
         */
        private String character_set = "utf-8";
        /**
         * 字體大小
         */
        private int fontSize = 12;
        /**
         * logo
         */
        private File logoFile;
        /**
         * logo所佔二維碼比例
         */
        private float logoRatio = 0.20f;
        /**
         * 二維碼下文字
         */
        private String desc;
        private int whiteWidth;//白邊的寬度
        private int[] bottomStart;//二維碼最下邊的開始座標
        private int[] bottomEnd;//二維碼最下邊的結束座標
    }


    /**
     * 1.建立最原始的二維碼圖片
     * @param info
     * @return
     */
    private BufferedImage createCodeImage(CodeModel info){

        String contents = StringUtils.isEmpty(info.getContents()) ? "暫無內容" : info.getContents();//獲取正文
        int width = info.getWidth();//寬度
        int height = info.getHeight();//高度
        Map<EncodeHintType, Object> hint = new HashMap<>();
        hint.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);//設置二維碼的糾錯級別【級別分別爲M L H Q ,H糾錯能力級別最高,約可糾錯30%的數據碼字】
        hint.put(EncodeHintType.CHARACTER_SET, info.getCharacter_set());//設置二維碼編碼方式【UTF-8】
        hint.put(EncodeHintType.MARGIN, 0);

        MultiFormatWriter writer = new MultiFormatWriter();
        BufferedImage img = null;
        try {
            //構建二維碼圖片
            //QR_CODE 一種矩陣二維碼
            BitMatrix bm = writer.encode(contents, BarcodeFormat.QR_CODE, width, height, hint);
            int[] locationTopLeft = bm.getTopLeftOnBit();
            int[] locationBottomRight = bm.getBottomRightOnBit();
            info.setBottomStart(new int[]{locationTopLeft[0], locationBottomRight[1]});
            info.setBottomEnd(locationBottomRight);
            int w = bm.getWidth();
            int h = bm.getHeight();
            img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
            for(int x=0;x<w;x++){
                for(int y=0;y<h;y++){
                    img.setRGB(x, y, bm.get(x, y) ? BLACK : WHITE);
                }
            }
        } catch (WriterException e) {
            e.printStackTrace();
        }
        return img;
    }

    /**
     * 2.爲二維碼增長logo和二維碼下文字
     * logo--能夠爲null
     * 文字--能夠爲null或者空字符串""
     * @param info
     * @param output
     */
    private void dealLogoAndDesc(CodeModel info, OutputStream output){
        //獲取原始二維碼圖片
        BufferedImage bm = createCodeImage(info);
        //獲取Logo圖片
        File logoFile = info.getLogoFile();
        int width = bm.getWidth();
        int height = bm.getHeight();
        Graphics g = bm.getGraphics();

        //處理logo
        if(logoFile!=null && logoFile.exists()){
            try{
                BufferedImage logoImg = ImageIO.read(logoFile);
                int logoWidth = logoImg.getWidth();
                int logoHeight = logoImg.getHeight();
                float ratio = info.getLogoRatio();//獲取Logo所佔二維碼比例大小
                if(ratio>0){
                    logoWidth = logoWidth>width*ratio ? (int)(width*ratio) : logoWidth;
                    logoHeight = logoHeight>height*ratio ? (int)(height*ratio) : logoHeight;
                }
                int x = (width-logoWidth)/2;
                int y = (height-logoHeight)/2;
                //根據logo 起始位置 和 寬高 在二維碼圖片上畫出logo
                g.drawImage(logoImg, x, y, logoWidth, logoHeight, null);
            }catch(Exception e){
                e.printStackTrace();
            }
        }

        //處理二維碼下文字
        String desc = info.getDesc();
        if(!StringUtils.isEmpty(desc)){
            try{
                //設置文字字體
                int whiteWidth = info.getHeight()-info.getBottomEnd()[1];
                Font font = new Font("黑體", Font.BOLD, info.getFontSize());
                int fontHeight = g.getFontMetrics(font).getHeight();
                //計算須要多少行
                int lineNum = 1;
                int currentLineLen = 0;
                for(int i=0;i<desc.length();i++){
                    char c = desc.charAt(i);
                    int charWidth = g.getFontMetrics(font).charWidth(c);
                    if(currentLineLen+charWidth>width){
                        lineNum++;
                        currentLineLen = 0;
                        continue;
                    }
                    currentLineLen += charWidth;
                }
                int totalFontHeight = fontHeight*lineNum;
                int wordTopMargin = 4;
                BufferedImage bm1 = new BufferedImage(width, height+totalFontHeight+wordTopMargin-whiteWidth, BufferedImage.TYPE_INT_RGB);
                Graphics g1 = bm1.getGraphics();
                if(totalFontHeight+wordTopMargin-whiteWidth>0){
                    g1.setColor(Color.WHITE);
                    g1.fillRect(0, height, width, totalFontHeight+wordTopMargin-whiteWidth);
                }
                g1.setColor(new Color(BLACK));
                g1.setFont(font);
                g1.drawImage(bm, 0, 0, null);
                width = info.getBottomEnd()[0]-info.getBottomStart()[0];
                height = info.getBottomEnd()[1]+1;
                currentLineLen = 0;
                int currentLineIndex = 0;
                int baseLo = g1.getFontMetrics().getAscent();
                for(int i=0;i<desc.length();i++){
                    String c = desc.substring(i, i+1);
                    int charWidth = g.getFontMetrics(font).stringWidth(c);
                    if(currentLineLen+charWidth>width){
                        currentLineIndex++;
                        currentLineLen = 0;
                        g1.drawString(c, currentLineLen + whiteWidth, height+baseLo+fontHeight*(currentLineIndex)+wordTopMargin);
                        currentLineLen = charWidth;
                        continue;
                    }
                    g1.drawString(c, currentLineLen+whiteWidth, height+baseLo+fontHeight*(currentLineIndex) + wordTopMargin);
                    currentLineLen += charWidth;
                }
                g1.dispose();
                bm = bm1;
            }catch(Exception e){
                e.printStackTrace();
            }
        }

        try{
            ImageIO.write(bm, StringUtils.isEmpty(info.getFormat()) ? info.getFormat() : info.getFormat(), output);
        }catch(Exception e){
            e.printStackTrace();
        }
    }


    /**
     * 3.建立 帶logo和文字的二維碼
     * @param info
     * @param file
     */
    public void createCodeImage(CodeModel info, File file){
        File parent = file.getParentFile();
        if(!parent.exists())parent.mkdirs();
        OutputStream output = null;
        try{
            output = new BufferedOutputStream(new FileOutputStream(file));
            dealLogoAndDesc(info, output);
            output.flush();
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            try {
                output.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 3.建立  帶logo和文字的二維碼
     * @param info
     * @param filePath
     */
    public void createCodeImage(CodeModel info, String filePath){
        createCodeImage(info, new File(filePath));
    }

    /**
     * 4.建立  帶logo和文字的二維碼
     * @param filePath
     */
    public void createCodeImage(String contents,String filePath){
        CodeModel codeModel = new CodeModel();
        codeModel.setContents(contents);
        createCodeImage(codeModel, new File(filePath));
    }


    /**
     * 5.讀取 二維碼 獲取二維碼中正文
     * @param input
     * @return
     */
    public String decode(InputStream input){
        Map<DecodeHintType, Object> hint = new HashMap<DecodeHintType, Object>();
        hint.put(DecodeHintType.POSSIBLE_FORMATS, BarcodeFormat.QR_CODE);
        String result = "";
        try{
            BufferedImage img = ImageIO.read(input);
            int[] pixels = img.getRGB(0, 0, img.getWidth(), img.getHeight(), null, 0, img.getWidth());
            LuminanceSource source = new RGBLuminanceSource(img.getWidth(), img.getHeight(), pixels);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
            QRCodeReader reader = new QRCodeReader();
            Result r = reader.decode(bitmap, hint);
            result = r.getText();
        }catch(Exception e){
            result="讀取錯誤";
        }
        return result;
    }



}
View Code

3.測試一下測試

    @Test
    public void getUUid(){
        String ss = RC4.RC4();
        System.out.println(ss);

        QR_Code code = new QR_Code();
//        Code.CodeModel codeModel = code.new CodeModel();
//        codeModel.setContents(ss);
//        codeModel.setWidth(400);
//        codeModel.setHeight(400);
//        codeModel.setFontSize(15);
//        codeModel.setLogoFile(new File("G:/ACODE/29936672.jpg"));
//        codeModel.setDesc("國大金象大藥房優惠碼");

        code.createCodeImage(ss,"G:/ACODE/國大金象大藥房.jpg");
    }
View Code

 

=======================================================字體

方法 選取哪一個生成均可以 大同小異 大同小異 沒有區別google

======================================================編碼

最後,若是想封裝成jar包供別人調用,參考步驟以下:http://www.cnblogs.com/sxdcgaq8080/p/8399854.html

相關文章
相關標籤/搜索