1. 程式人生 > >分享:Java 開發精美藝術二維碼

分享:Java 開發精美藝術二維碼

Java 開發精美藝術二維碼

看到網路上各種各樣的二維碼層出不窮,好像很炫酷的樣子,一時興起,我也要製作這種炫酷二維碼效果

例如:

根據以往例子

根據之前所做的小專案 java 開發二維碼系統

以這個為基礎,將實現精美藝術二維碼

基本程式碼:

// 建立二維碼物件
Qrcode qrcode = new Qrcode();
// 設定二維碼的糾錯級別
// L(7%) M(15%) Q(25%) H(30%)
qrcode.setQrcodeErrorCorrect('L'); // 一般糾錯級別小一點
// 設定二維碼的編碼模式 Binary(按照位元組編碼模式)
qrcode.setQrcodeEncodeMode('B');
// 設定二維碼的版本號 1-40  1:20*21    2:25*25   40:177*177
qrcode.setQrcodeVersion(7);
// 生成二維碼中要儲存的資訊
String qrData = "https://ainyi.com";
// 設定一下二維碼的畫素
int width = 300;
int height = 300;
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 繪圖
Graphics2D gs = bufferedImage.createGraphics();
gs.setBackground(Color.WHITE);
gs.setColor(Color.BLACK);
gs.clearRect(0, 0, width, height); // 清除下畫板內容

// 設定下偏移量,如果不加偏移量,有時會導致出錯
int pixoff = 2;

byte[] d = qrData.getBytes("utf-8");
if(d.length > 0 && d.length <120){
  boolean[][] s = qrcode.calQrcode(d);
  for(int i=0;i<s.length;i++){
    for(int j=0;j<s.length;j++){
      if(s[j][i]){
        gs.fillRect(j*3+pixoff, i*3+pixoff, 3, 3);
      }
    }
  }
}
gs.dispose();
bufferedImage.flush();
ImageIO.write(bufferedImage, "png", new File("E:/code/qrcode.png"));

準備工作

java 可以實現生成二維碼,需要用到 Qrcode 的 jar 包

  1. java、jsp
  2. struts2 以及相關 jar 包
  3. Qrcode.jar
  4. 檔案上傳相關 jar 包
  5. 自己編寫摸索出來的藝術二維碼演算法
  6. 響應式

實現流程

因為要實現精美藝術二維碼,把黑白二維碼的黑色部分,點狀部分替換成有顏色的點,匯聚成一張精美的二維碼

那麼實現的關鍵點就是:==替換==

將製作好的小圖片素材,按照編號命名,三個碼眼使用大圖片素材,其他使用不相同小圖片素材,繪製二維碼圖片的時候,將畫筆改為將插入圖片素材 drawImage

根據不同型別的藝術二維碼(不同的素材),使用不同的演算法

話不多說,上程式碼

/**
 * QrcodeText 二維碼
 * @author krry
 * @version 1.0
 *
 */
public class QrcodeText{
    
  private static int width = 975;
  private static int height = 975;
    
  // 設定偏移量,不設定可能導致解析出錯
  private static int pixoff = 25;
  // 畫素大小
  private static int pix = 25;
  // 二維碼陣列的長度
  private static int codeLength;
  // 隨機數,生成[0,2]之間的隨機整數,取長度為3的陣列下標
  private static int max = 3;
    
  //素材圖片容器
  private static BufferedImage image_eye;
  private static BufferedImage image11;
  private static BufferedImage image12;
  private static BufferedImage image13;
  private static BufferedImage image21;
  private static BufferedImage image22;
  private static BufferedImage image23;
  private static BufferedImage image31;
  private static BufferedImage image32;
  private static BufferedImage image33;
  private static BufferedImage image41;
  private static BufferedImage image42;
  private static BufferedImage image43;
    
    
 /**
  * 生成二維碼
  * @param message  二維碼內容
  * @param type   二維碼型別 如:鎖屏
  * @param filename     二維碼型別下的標號  如1
  * @param arti     使用演算法型別  如0  熱門
  * @param transparent 是否透明     1:透明  0背景是白色
  * @param request  請求
  * @return
  */
  public static String qrcode(String message,String type,String filename,String arti,String transparent,HttpServletRequest request){
    String pathName = null;
    FileOutputStream outputStream = null;

    try{
      //建立二維碼物件
      Qrcode qrcode = new Qrcode();
      //設定二維碼的糾錯級別
      //L(7%) M(15%) Q(25%) H(30%)
      qrcode.setQrcodeErrorCorrect('L'); //一般糾錯級別小一點
      //設定二維碼的編碼模式 Binary(按照位元組編碼模式)
      qrcode.setQrcodeEncodeMode('B');
      //設定二維碼的版本號 1-40  1:20*21    2:25*25   40:177*177
      qrcode.setQrcodeVersion(5);
            
      //獲取圖片快取流物件
      BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
      //獲取畫筆
      Graphics2D gs = image.createGraphics();
            
      //判斷是否使用二維碼背景顏色是透明
      if(transparent.equals("yes")){
        //設定透明
        image = gs.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);  
        gs = image.createGraphics();
      } else {
        gs.setBackground(Color.WHITE);
        gs.clearRect(0, 0, width, height);
      }
            
      //設定內容
      String content = message;
      byte[] contentsBytes = content.getBytes("utf-8");

      //二維碼
      boolean[][] code = qrcode.calQrcode(contentsBytes);
      //獲取二維碼陣列的長度
      codeLength = code.length;
            
      //碼眼部分全部設定為false
      for(int i=0;i<7;i++){
        for(int j=0;j<7;j++){
          code[i][j]=false;
        }
        for(int j=codeLength-7;j<codeLength;j++){
          code[i][j]=false;
          code[j][i]=false;
        }
      }
            
      //獲取資源地址
      String aspath = request.getServletContext().getRealPath("/resource");
            
      //載入圖片
      loadImage(aspath,type,filename);
            
      //繪製二維碼,選擇演算法
      if(arti.equals("0")) drawQrcodeHot(gs, code); //熱門演算法
      else if(arti.equals("1")) drawQrcodeOrdi(gs, code); //最初演算法
      else if(arti.equals("2")) drawQrcodeRiTojiao(gs, code); //三角演算法
            
      //如果型別不是單碼,則裝載背景圖片,將二維碼寫進背景圖片中,只有單碼沒有背景
      if(!type.equals("dan")){
        //裝載背景圖片
        BufferedImage imageBG = ImageIO.read(new FileInputStream(aspath+"\\images\\ImageMaker\\"+type+"\\"+filename+"\\bg.jpg"));
        //獲取背景圖片的畫筆
    Graphics2D bg = imageBG.createGraphics();
                
    //位置座標
        int x = 0;
        int y = 0;
                
        //如果型別是方形,判斷二維碼在背景圖片的位置,單碼圖片縮小到640畫素
        if(type.equals("fang")){
      x = (imageBG.getWidth() - 640) / 2;
          y = (imageBG.getHeight() - 640) / 2;
        }
        //如果型別是名片,判斷二維碼在背景圖片的位置,單碼圖片縮小到640畫素
        if(type.equals("ming")){
      x = (imageBG.getWidth() - 100) / 2;
          y = (imageBG.getHeight() - 640) / 2;
        }
        //如果型別是鎖屏,判斷二維碼在背景圖片的位置,單碼圖片縮小到640畫素
        if(type.equals("suo")){
          x = (imageBG.getWidth() - 640) / 2;
          y = (imageBG.getHeight() - 1100) / 2;
        }
                
        //將單碼圖片寫進背景圖片中,單碼圖片縮小到640畫素
        bg.drawImage(image, x, y, 640, 640, null);
                
        //釋放畫筆
        bg.dispose();
        gs.dispose();
        //生成二維碼圖片
        String realPath = request.getRealPath("/");
        //String realPath = 伺服器專案的地址;
        pathName = new Date().getTime()+".jpg";
        outputStream = new FileOutputStream(new File(realPath+"upload\\", pathName));
        ImageIO.write(imageBG, "jpg", outputStream);
                
      } else { //如果型別是單碼,直接釋放輸出
        //釋放畫筆
        gs.dispose();
        //生成二維碼圖片
        String realPath = request.getRealPath("/");
        //String realPath = 伺服器專案的地址;
        pathName = new Date().getTime()+".png";
        outputStream = new FileOutputStream(new File(realPath+"upload\\", pathName));
        ImageIO.write(image, "png", outputStream);
      }
    } catch (Exception e){
      e.printStackTrace();
    } finally {
      try {
    //關閉流
    outputStream.close();
      } catch (IOException e) {
    e.printStackTrace();
      }
    }
    return pathName;
  }
    
  /**
   * 載入圖片素材
   * @param aspath
   * @param type
   * @param filename
   */
  public static void loadImage(String aspath,String type,String filename){
    try {
      //載入碼眼
      image_eye = ImageIO.read(new FileInputStream(aspath+"\\images\\ImageMaker\\"+type+"\\"+filename+"\\eye.png"));
      //裝載50*50的圖片素材
      image11 = ImageIO.read(new FileInputStream(aspath+"\\images\\ImageMaker\\"+type+"\\"+filename+"\\11.png"));
      image12 = ImageIO.read(new FileInputStream(aspath+"\\images\\ImageMaker\\"+type+"\\"+filename+"\\12.png"));
      image13 = ImageIO.read(new FileInputStream(aspath+"\\images\\ImageMaker\\"+type+"\\"+filename+"\\13.png"));
      //裝載100*50的圖片素材
      image21 = ImageIO.read(new FileInputStream(aspath+"\\images\\ImageMaker\\"+type+"\\"+filename+"\\21.png"));
      image22 = ImageIO.read(new FileInputStream(aspath+"\\images\\ImageMaker\\"+type+"\\"+filename+"\\22.png"));
      image23 = ImageIO.read(new FileInputStream(aspath+"\\images\\ImageMaker\\"+type+"\\"+filename+"\\23.png"));
      //裝載50*100的圖片素材
      image31 = ImageIO.read(new FileInputStream(aspath+"\\images\\ImageMaker\\"+type+"\\"+filename+"\\31.png"));
      image32 = ImageIO.read(new FileInputStream(aspath+"\\images\\ImageMaker\\"+type+"\\"+filename+"\\32.png"));
      image33 = ImageIO.read(new FileInputStream(aspath+"\\images\\ImageMaker\\"+type+"\\"+filename+"\\33.png"));
      //裝載100*100的圖片素材
      image41 = ImageIO.read(new FileInputStream(aspath+"\\images\\ImageMaker\\"+type+"\\"+filename+"\\41.png"));
      image42 = ImageIO.read(new FileInputStream(aspath+"\\images\\ImageMaker\\"+type+"\\"+filename+"\\42.png"));
      image43 = ImageIO.read(new FileInputStream(aspath+"\\images\\ImageMaker\\"+type+"\\"+filename+"\\43.png"));
            
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
    
    
  /**
   * 繪製 演算法0  熱門二維碼   素材有50*50 50*100 100*50 100*100
   * @param gs 畫筆
   * @param code 二維碼陣列
   */
  public static void drawQrcodeHot(Graphics2D gs,boolean[][] code){
    //把圖片素材放進陣列
    BufferedImage[] img1 = {image11,image12,image13};
    BufferedImage[] img2 = {image21,image22,image23};
    BufferedImage[] img3 = {image31,image32,image33};
    BufferedImage[] img4 = {image41,image42,image43};
        
    //通用地繪製碼眼
    gs.drawImage(image_eye, pix, pix, pix*7, pix*7, null);
    gs.drawImage(image_eye, (codeLength-7)*pix+pixoff, pix, pix*7, pix*7, null);
    gs.drawImage(image_eye, pix, (codeLength-7)*pix+pixoff, pix*7, pix*7, null);
        
    Random random = new Random();
        
    // 繪製
    for (int i = 0; i < codeLength; i++) {
      for (int j = 0; j < codeLength; j++) {
        if (code[i][j]) {
          if (i+1 < codeLength && j+1 < codeLength && code[i][j + 1] && code[i + 1][j + 1] && code[i + 1][j]){
            //隨機取圖片,畫100*100的圖
            int s4 = random.nextInt(max);
            gs.drawImage(img4[s4], i * pix + pixoff, j * pix + pixoff, pix * 2, pix * 2, null);
            code[i][j + 1] = code[i + 1][j] = code[i + 1][j + 1] = false;
          } else if(j+1 < codeLength && code[i][j+1]){
            //隨機取圖片,畫50*100的圖
            int s3 = random.nextInt(max);
            gs.drawImage(img3[s3], i * pix + pixoff, j * pix + pixoff, pix, pix*2, null);
            code[i][j+1] = false;
          } else if (i+1 < codeLength && code[i+1][j]) {
            //隨機取圖片,畫100*50的圖
            int s2 = random.nextInt(max);
            gs.drawImage(img2[s2], i * pix + pixoff, j * pix + pixoff, pix * 2, pix, null);
            code[i+1][j] = false;
          } else {
            //隨機取圖片,畫50*50的圖
            int s1 = random.nextInt(max);
            gs.drawImage(img1[s1], i * pix + pixoff, j * pix + pixoff, pix, pix, null);
          }
        }
      }
    }
  }
    
  /**
   * 繪製  演算法2 二維碼   素材有50*50 50*100 100*50 100*100  其中100*100是三個角的演算法,右上角沒有填充
   * @param gs 畫筆
   * @param code 二維碼陣列
   */
  public static void drawQrcodeRiTojiao(Graphics2D gs,boolean[][] code){
    System.out.println("三角啊");
    //把圖片素材放進陣列
    BufferedImage[] img1 = {image11,image12,image13};
    BufferedImage[] img2 = {image21,image22,image23};
    BufferedImage[] img3 = {image31,image32,image33};
    BufferedImage[] img4 = {image41,image42,image43};
        
    //通用地繪製碼眼
    gs.drawImage(image_eye, pix, pix, pix*7, pix*7, null);
    gs.drawImage(image_eye, (codeLength-7)*pix+pixoff, pix, pix*7, pix*7, null);
    gs.drawImage(image_eye, pix, (codeLength-7)*pix+pixoff, pix*7, pix*7, null);
        
    Random random = new Random();
        
    // 繪製
    for (int i = 0; i < codeLength; i++) {
      for (int j = 0; j < codeLength; j++) {
        if (code[i][j]) {
          if (i+1 < codeLength && j+1 < codeLength && code[i][j + 1] && code[i + 1][j + 1]){
            //隨機取圖片,畫100*100的圖  右上角沒有填充
            int s4 = random.nextInt(max);
            gs.drawImage(img4[s4], i * pix + pixoff, j * pix + pixoff, pix * 2, pix * 2, null);
            code[i][j + 1] = code[i + 1][j + 1] = false;
          } else if(j+1 < codeLength && code[i][j+1]){
            //隨機取圖片,畫50*100的圖
            int s3 = random.nextInt(max);
            gs.drawImage(img3[s3], i * pix + pixoff, j * pix + pixoff, pix, pix*2, null);
            code[i][j+1] = false;
          } else if (i+1 < codeLength && code[i+1][j]) {
            //隨機取圖片,畫100*50的圖
            int s2 = random.nextInt(max);
            gs.drawImage(img2[s2], i * pix + pixoff, j * pix + pixoff, pix * 2, pix, null);
            code[i+1][j] = false;
          } else {
            //隨機取圖片,畫50*50的圖
            int s1 = random.nextInt(max);
            gs.drawImage(img1[s1], i * pix + pixoff, j * pix + pixoff, pix, pix, null);
          }
        }
      }
    }
  }
    
  /**
   * 繪製  演算法1 普通二維碼   素材有50*50 50*100 50*150
   * @param gs 畫筆
   * @param code 二維碼陣列
   */
  public static void drawQrcodeOrdi(Graphics2D gs,boolean[][] code){
    //把圖片素材放進陣列
    BufferedImage[] img1 = {image11,image12,image13};
    BufferedImage[] img2 = {image21,image22,image23};
    BufferedImage[] img3 = {image31,image32,image33};
        
    //通用地繪製碼眼
    gs.drawImage(image_eye, pix, pix, pix*7, pix*7, null);
    gs.drawImage(image_eye, (codeLength-7)*pix+pixoff, pix, pix*7, pix*7, null);
    gs.drawImage(image_eye, pix, (codeLength-7)*pix+pixoff, pix*7, pix*7, null);
        
    Random random = new Random();
        
    for(int i = 0;i < codeLength;i++){
      for(int j = 0;j < codeLength;j++){
        //1*3
        if(code[i][j]){
          if(i+2 < codeLength && code[i+1][j] && code[i+2][j]){
            //隨機取圖片  下標隨機[0,2],畫50*150的圖
            int s3 = random.nextInt(max);
            gs.drawImage(img3[s3], j*25+pixoff, i*25+pixoff, 25, 75, null);
            code[i+2][j]=false;
            code[i+1][j]=false;
          }else if(i+1 < codeLength && code[i+1][j]){
            //1*2
            //隨機取圖片,畫50*100的圖
            int s2 = random.nextInt(max);
            gs.drawImage(img2[s2], j*25+pixoff, i*25+pixoff, 25, 50, null);
            code[i+1][j]=false;
          } else {
            //隨機取圖片,畫50*50的圖
            int s1 = random.nextInt(max);
            gs.drawImage(img1[s1], j*25+pixoff, i*25+pixoff, 25, 25, null);
          }
        }
      }
    }
  }
}

專案截圖

相關地址

歡迎 start