Java与二维码的那些事儿

主要介绍java常用解析二维码的两种方式!

写在前边:第一种比第二种功能要更强大一点,其可以解析图片中的二维码图片,但是第二种不可以。

使用File处理文件的方式适合在本地测试使用,如果把二维码图片现在到本地服务器,然后处理也不是不可以,只是比较麻烦。

使用输入流的方式适合在服务中使用,可以有效解决图片链接中带点号的问题。


实例demo以及第三方依赖jar包下载地址:点击打开链接

直接上代码

第一种:使用QRCode

1.maven依赖

        <dependency>
             <groupId>QRCode</groupId>
             <artifactId>QRCode</artifactId>
             <version>3.0</version>

        </dependency>

2.主要代码

package com.xxx.xxx.biz.util;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.imageio.ImageIO;

import com.swetake.util.Qrcode;

import jp.sourceforge.qrcode.QRCodeDecoder;
import jp.sourceforge.qrcode.exception.DecodingFailedException;

/**
 * 
 * Copyright © 2018 www.xxx.com All rights reserved.
 * 
 * 功能描述:二维码工具类
 * @Package: com.xxx.xxx.web.util 
 * @author: clg  
 * @date: 2018年5月14日 下午3:39:27
 */
public class TwoDimensionCodeUtil {
	
	/**
	 * 生成二维码(QRCode)图片
	 * @param content 存储内容
	 * @param imgPath 图片路径
	 */
	public void encoderQRCode(String content, String imgPath) {
		this.encoderQRCode(content, imgPath, "png", 7);
	}
	
	/**
	 * 生成二维码(QRCode)图片
	 * @param content 存储内容
	 * @param imgPath 图片路径
	 * @param imgType 图片类型
	 * @param size 二维码尺寸
	 */
	public void encoderQRCode(String content, String imgPath, String imgType, int size) {
		try {
			BufferedImage bufImg = this.qRCodeCommon(content, imgType, size);
			
			File imgFile = new File(imgPath);
			// 生成二维码QRCode图片
			ImageIO.write(bufImg, imgType, imgFile);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * 生成二维码(QRCode)图片的公共方法
	 * @param content 存储内容
	 * @param imgType 图片类型
	 * @param size 二维码尺寸
	 * @return
	 */
	private BufferedImage qRCodeCommon(String content, String imgType, int size) {
		BufferedImage bufImg = null;
		try {
			Qrcode qrcodeHandler = new Qrcode();
			// 设置二维码排错率,可选L(7%)、M(15%)、Q(25%)、H(30%),排错率越高可存储的信息越少,但对二维码清晰度的要求越小
			qrcodeHandler.setQrcodeErrorCorrect('M');
			qrcodeHandler.setQrcodeEncodeMode('B');
			// 设置设置二维码尺寸,取值范围1-40,值越大尺寸越大,可存储的信息越大
			qrcodeHandler.setQrcodeVersion(size);
			// 获得内容的字节数组,设置编码格式
			byte[] contentBytes = content.getBytes("utf-8");
			// 图片尺寸
			int imgSize = 67 + 12 * (size - 1);
			bufImg = new BufferedImage(imgSize, imgSize, BufferedImage.TYPE_INT_RGB);
			Graphics2D gs = bufImg.createGraphics();
			// 设置背景颜色
			gs.setBackground(Color.WHITE);
			gs.clearRect(0, 0, imgSize, imgSize);

			// 设定图像颜色> BLACK
			gs.setColor(Color.BLACK);
			// 设置偏移量,不设置可能导致解析出错
			int pixoff = 2;
			// 输出内容> 二维码
			if (contentBytes.length > 0 && contentBytes.length < 800) {
				boolean[][] codeOut = qrcodeHandler.calQrcode(contentBytes);
				for (int i = 0; i < codeOut.length; i++) {
					for (int j = 0; j < codeOut.length; j++) {
						if (codeOut[j][i]) {
							gs.fillRect(j * 3 + pixoff, i * 3 + pixoff, 3, 3);
						}
					}
				}
			} else {
				throw new Exception("QRCode content bytes length = " + contentBytes.length + " not in [0, 800].");
			}
			gs.dispose();
			bufImg.flush();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return bufImg;
	}
	
	/**
	 * 解析二维码(QRCode)
	 * @param imgPath 图片路径
	 * @return
	 */
	public static String decoderQRCode(String imgPath) {
		// QRCode 二维码图片的文件
		BufferedImage bufImg = null;
		String content = null;
		try {
			InputStream  input = getInputStream(imgPath);
		
                //      File input = new File(imgPath);//注释4
                        bufImg = ImageIO.read(input);
			QRCodeDecoder decoder = new QRCodeDecoder();
			content = new String(decoder.decode(new TwoDimensionCodeImage(bufImg)), "utf-8"); 
		} catch (IOException e) {
			System.out.println("Error: " + e.getMessage());
			e.printStackTrace();
		} catch (DecodingFailedException dfe) {
			System.out.println("Error: " + dfe.getMessage());
			dfe.printStackTrace();
		}
		return content;
	}
	
	
	/**下载服务器图片输入流*/
    public static  InputStream getInputStream(String  path){  
        InputStream inputStream=null;  
        HttpURLConnection httpURLConnection=null;  
        try{  
            URL url=new URL(path);  
            if(url!=null){  
                httpURLConnection=(HttpURLConnection) url.openConnection();  
                httpURLConnection.setConnectTimeout(3000);  
                httpURLConnection.setRequestMethod("GET");  
                int responseCode=httpURLConnection.getResponseCode();  
                if(responseCode==200){  
                    inputStream=httpURLConnection.getInputStream();  
                }  
            }  
        }catch(Exception e){  
            e.printStackTrace();  
        }  
        return inputStream;  
    }  

	public static void main(String[] args) {
		
		TwoDimensionCodeUtil  util = new TwoDimensionCodeUtil();
		util.encoderQRCode("www.baidu.com", "C:/Users/dell/Desktop/work-down/2.jpg");
//		String imgPath = "C:/Users/dell/Desktop/work-down/1.jpg";//注释1
//		imgPath = "http://wdgj.oss-cn-xxxx.aliyuncs.com/community/post/f496d880915c430e916b970e4848bd29.jpg";//注释2
//		String  cont = decoderQRCode(imgPath);//注释3
	}
}

3.执行说明:

一、直接运行main方法,生成二维码图片目录:C:/Users/dell/Desktop/work-down/1.jpg。

二、打开注释1、注释2和注释3,执行main方法,控制台打印出二维码图片中的内容(图片链接中带点号)。

三、关闭注释2并打开注释4,执行main方法,控制台打印出二维码图片中的内容(本地图片)。

备注:图片链接中如果有点号(后缀除外),不能使用File处理,只能适用流的方式!!!


第二种:使用Google工具

1.maven依赖

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

        </dependency>

2.主要代码

package com.xxx.xxx.biz.util;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
import com.google.zxing.Binarizer;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;

/**
 * 
 * Copyright © 2018 www.xxx.com All rights reserved.
 * 功能描述:用于二维码的解析,由Google提供。
 * 存在局限性,不能识别图片中附带的二维码
 * @Package: com.xxx.xxx.biz.util 
 * @author: clg 
 * @date: 2018年5月14日 下午5:14:31
 */
public final class BufferedImageLuminanceSource extends LuminanceSource {
    private final BufferedImage image;
    private final int left;
    private final int top;
    public BufferedImageLuminanceSource(BufferedImage image) {
        this(image, 0, 0, image.getWidth(), image.getHeight());
    }

    public BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height) {
        super(width, height);
        int sourceWidth = image.getWidth();
        int sourceHeight = image.getHeight();
        if (left + width > sourceWidth || top + height > sourceHeight) {
            throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
        }
        for (int y = top; y < top + height; y++) {
            for (int x = left; x < left + width; x++) {
                if ((image.getRGB(x, y) & 0xFF000000) == 0) {
                    image.setRGB(x, y, 0xFFFFFFFF); // = white
                }
            }
        }

        this.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY);
        this.image.getGraphics().drawImage(image, 0, 0, null);
        this.left = left;
        this.top = top;
    }

    @Override
    public byte[] getRow(int y, byte[] row) {
        if (y < 0 || y >= getHeight()) {
            throw new IllegalArgumentException("Requested row is outside the image: " + y);
        }
        int width = getWidth();
        if (row == null || row.length < width) {
            row = new byte[width];
        }
        image.getRaster().getDataElements(left, top + y, width, 1, row);
        return row;
    }

    @Override
    public byte[] getMatrix() {
        int width = getWidth();
        int height = getHeight();
        int area = width * height;
        byte[] matrix = new byte[area];
        image.getRaster().getDataElements(left, top, width, height, matrix);
        return matrix;
    }

    @Override
    public boolean isCropSupported() {
        return true;
    }

    @Override
    public LuminanceSource crop(int left, int top, int width, int height) {
        return new BufferedImageLuminanceSource(image, this.left + left, this.top + top, width, height);
    }

    @Override
    public boolean isRotateSupported() {
        return true;
    }

    @Override
    public LuminanceSource rotateCounterClockwise() {

        int sourceWidth = image.getWidth();
        int sourceHeight = image.getHeight();

        AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth);

        BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE_BYTE_GRAY);

        Graphics2D g = rotatedImage.createGraphics();
        g.drawImage(image, transform, null);
        g.dispose();

        int width = getWidth();
        return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width), getHeight(), width);
    }
    
    /**
     * 解析指定路径下的二维码图片
     *
     * @param filePath 二维码图片路径
     * @return
     */
    private static String parseQRCode(String filePath) {
        String content = "";
        try {
//            File file = new File(filePath);//注释4
            InputStream  input = getInputStream(filePath);//注释2
            BufferedImage image = ImageIO.read(input);
            LuminanceSource source = new BufferedImageLuminanceSource(image);
            Binarizer binarizer = new HybridBinarizer(source);
            BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
            Map<DecodeHintType, Object> hints = new HashMap<>();
            hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
            MultiFormatReader formatReader = new MultiFormatReader();
            Result result = formatReader.decode(binaryBitmap, hints);
            //设置返回值
            content = result.getText();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return content;
    }
    
    
    public static  InputStream getInputStream(String  path){  
        InputStream inputStream=null;  
        HttpURLConnection httpURLConnection=null;  
        try{  
            URL url=new URL(path);  
            if(url!=null){  
                httpURLConnection=(HttpURLConnection) url.openConnection();  
                httpURLConnection.setConnectTimeout(3000);  
                httpURLConnection.setRequestMethod("GET");  
                int responseCode=httpURLConnection.getResponseCode();  
                if(responseCode==200){  
                    inputStream=httpURLConnection.getInputStream();  
                }  
            }  
        }catch(Exception e){  
            e.printStackTrace();  
        }  
        return inputStream;  
          
    }  
    
    
    public static void main(String[] args) {
    	String  cont = parseQRCode("http://xxx.xxx.xxx.com/community/post/f496d880915c430e916b970e4848bd29.jpg");//注释1
//    	String  cont = parseQRCode("C:/Users/dell/Desktop/work-down/3.jpg");//注释3
    	System.out.println(cont);
    
    }

}

3.执行说明:

一、直接运行main方法,控制台打印出二维码图片中的内容(图片链接中带点号)。

二、打开注释3和注释4,注释注释1和注释2,执行main方法,控制台打印出二维码图片中的内容(本地图片)。

备注:图片链接中如果有点号(后缀除外),不能使用File处理,只能适用流的方式!!!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值