二维码技术不是什么新技术了,但是这几天工作用到,然后才现学习现使用,使用的是Google的ZXing,使用起来很简单,
我练习的两种方式,一种的简单的javase工程,一种是Android客户端生成解析二维码的demo,线面逐个介绍。
一、JavaSE生成解析二维码,就是建立一个JavaProject,然后导入jar包,我用的是maven,所以建立了一个简单的maven工程。
1、第一种形式,生成一个中间没有logo的二维码,并解析,写好之后,直接说哪个junit测试,就能生成解析二维码了
package com.wang.qr.code; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import javax.imageio.ImageIO; import org.junit.Test; import com.alibaba.fastjson.JSONObject; import com.google.zxing.BarcodeFormat; import com.google.zxing.Binarizer; import com.google.zxing.BinaryBitmap; import com.google.zxing.DecodeHintType; import com.google.zxing.EncodeHintType; import com.google.zxing.LuminanceSource; import com.google.zxing.MultiFormatReader; import com.google.zxing.MultiFormatWriter; import com.google.zxing.NotFoundException; import com.google.zxing.Result; import com.google.zxing.WriterException; import com.google.zxing.client.j2se.BufferedImageLuminanceSource; import com.google.zxing.client.j2se.MatrixToImageWriter; import com.google.zxing.common.BitMatrix; import com.google.zxing.common.HybridBinarizer; /** * 生成没有logo的二维码</br> 有多个信息json * * @author wang * */ public class QRCodeTest1 { /** * 生成二维码</br> * * 二维码中的内容是json数据 * * @throws WriterException * @throws IOException */ @Test public void testEncode() throws WriterException, IOException { /* * 把生成的二维码放到此目录下 */ String filePath = "E://"; /* * 生成的二维码名称 */ String fileName = "zxing.png"; JSONObject json = new JSONObject(); json.put("zxing", "https://github.com/zxing/zxing/tree/zxing-3.0.0/javase/src/main/java/com/google/zxing"); json.put("author", "shihy"); /* * 二维码中的内容 */ String content = json.toJSONString();// 内容 int width = 200; // 图像宽度 int height = 200; // 图像高度 String format = "png";// 图像类型 Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>(); hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);// 生成矩阵 Path path = FileSystems.getDefault().getPath(filePath, fileName); MatrixToImageWriter.writeToPath(bitMatrix, format, path);// 输出图像 System.out.println("输出成功."); } /** * 解析二维码</br> 二维码中的内容是json数据 */ @Test public void testDecode() { /* * 要解析的二维码 */ String filePath = "E://zxing.png"; BufferedImage image; try { image = ImageIO.read(new File(filePath)); 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);// 对图像进行解码 /* * 得到二维码中的字符串内容 */ //String context = result.getText(); JSONObject content = JSONObject.parseObject(result.getText()); System.out.println("图片中内容: "); System.out.println("author: " + content.getString("author")); System.out.println("zxing: " + content.getString("zxing")); System.out.println("图片中格式: "); System.out.println("encode: " + result.getBarcodeFormat()); } catch (IOException e) { e.printStackTrace(); } catch (NotFoundException e) { e.printStackTrace(); } } }
2、第二种形式,生成有logo的二维码,工具类如下
package com.wang.qr.code.utils; import java.awt.Graphics2D; import java.awt.Image; import java.awt.image.BufferedImage; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Hashtable; import javax.imageio.ImageIO; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; import com.google.zxing.client.j2se.MatrixToImageWriter; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; /** * 生成普通二维码和生成带logo的二维码 * * @author wang * */ public class QRCodeTestUtil3 { private static final int BLACK = 0xFF000000; private static final int WHITE = 0xFFFFFFFF; /** * 生成普通没有logo的二维码 * * @param filePath * 文本文件路径,该文件中的内容是生成二维码图片中的内容(文本需以UTF-8) * @param imgFormate * 指定生成的二维码图片的后缀名 * @param width * 指定生成的二维码图片的宽度 * @param height * 指定生成的二维码图片的高度 */ public static void createTwoDimensionalCode(String filePath, String imgFormate, int width, int height) { File file = new File(filePath); StringBuffer contents = new StringBuffer(""); // 读取文本文件内容到 contents try { InputStream is = new FileInputStream(file); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); try { String temp = br.readLine(); while (temp != null) { contents.append(temp + "\r\n"); temp = br.readLine(); } } catch (IOException e) { e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); } // 得到图片该存放路径 String imgPath = file.getParent(); // 得到文件该设置的名字 String imgName = file.getName(); int endIndex = imgName.lastIndexOf("."); imgName = imgName.substring(0, endIndex); File imageFile = new File(imgPath, imgName + "." + imgFormate); Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); // 指定纠错等级 hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); // 指定编码格式 hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); try { BitMatrix bitMatrix = new MultiFormatWriter().encode(contents.toString(), BarcodeFormat.QR_CODE, width, height, hints); MatrixToImageWriter.writeToPath(bitMatrix, imgFormate, imageFile.toPath()); } catch (Exception e) { e.printStackTrace(); } } /** * 生成带logo的二维码图片 * * @param url * 要生成二维码的url * @param imgPath * 二维码生成的绝对路径 * @param logoPath * 二维码中间logo绝对地址 * @throws Exception */ public static void get2CodeImage(String url, String imgPath, String logoPath) throws Exception { String format = "png"; Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>(); hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 300, 300, hints); File qrcodeFile = new File(imgPath); writeToFile(bitMatrix, format, qrcodeFile, logoPath); } /** * * @param matrix * 二维码矩阵相关 * @param format * 二维码图片格式 * @param file * 二维码图片文件 * @param logoPath * logo路径 * @throws IOException */ private static void writeToFile(BitMatrix matrix, String format, File file, String logoPath) throws IOException { BufferedImage image = toBufferedImage(matrix); Graphics2D gs = image.createGraphics(); // 载入logo Image img = ImageIO.read(new File(logoPath)); gs.drawImage(img, 125, 125, null); gs.dispose(); img.flush(); if (!ImageIO.write(image, format, file)) { throw new IOException("Could not write an image of format " + format + " to " + file); } } private static BufferedImage toBufferedImage(BitMatrix matrix) { int width = matrix.getWidth(); int height = matrix.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, matrix.get(x, y) ? BLACK : WHITE); } } return image; } }
测试类:
package com.wang.qr.code; import org.junit.Test; import com.wang.qr.code.utils.QRCodeTestUtil3; /** * @author wang * */ public class QRCodeTest3 { @Test public void createNoLogoQRCode() { QRCodeTestUtil3.createTwoDimensionalCode("E://test.txt", "png", 200, 200); } @Test public void createHaveLogoQRCode() { try { QRCodeTestUtil3.get2CodeImage("https://shop100133013.taobao.com/shop/view_shop.htm?spm=a1z0k.7386009.1997989141.d4915209.abFEJh&shop_id=100133013", "E://havalogoQRCode.png", "E://logo.png"); } catch (Exception e) { e.printStackTrace(); } } }
效果图:(一张有用的二维码,不信可以用微信扫扫哦。。。)
在联系的时候,我是用的maven工程,附上maven工程的pom文件:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>QRCodeTest</groupId> <artifactId>QRCodeTest</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>QRCodeTest</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependency> <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.2.1</version> </dependency> <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> <version>3.2.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.7</version> </dependency> </dependencies> </project>
二、第二个练习的是写了一个Android的应用程序,能够根据填写内容,和是否选择二维码logo,生成一个二维码;能够像微信一样扫描二维码(在网上找到的demo代码直接用的),
Android上生成二维码与javase生成二维码的核心代码原理一样,都是zxing,但是有不一样的地方,javase生成二维码后,能够直 接在本地保存二维码文件。Android应用程序这样的话就不要友好了,我们应该先将二维码生成bitmap的形式,然后显示在imageView上面, 由使用者选择是否保存二维码,就像下面的界面一样,
这样的话,生成二维码的代码就不一样了。下面是在Android中生成二维码bitmap的代码:
package com.wang.qrcodecreateandscantool.util; import android.graphics.Bitmap; import android.graphics.Canvas; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import java.util.Hashtable; /** * 生成二维码的工具类 * <p/> * Created by wang on 2015/11/12. */ public class QRCodeCreateUtil { /** * 生成没有logo的二维码Bitmap * * @param context 二维码内容 * @param widthPix 二维码宽度 * @param heightPix 二维码高度 * @return Bitmap */ public static Bitmap createNoLogoQRCode(String context, int widthPix, int heightPix) { Bitmap bitmap = null; try { Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); BitMatrix bitMatrix = new MultiFormatWriter().encode(context, BarcodeFormat.QR_CODE, widthPix, heightPix, hints); int[] pixels = new int[widthPix * heightPix]; for (int y = 0; y < heightPix; y++) { for (int x = 0; x < widthPix; x++) { if (bitMatrix.get(x, y)) { pixels[y * widthPix + x] = 0xff000000; } else { pixels[y * widthPix + x] = 0xffffffff; } } } bitmap = Bitmap.createBitmap(widthPix, heightPix, Bitmap.Config.ARGB_8888); bitmap.setPixels(pixels, 0, widthPix, 0, 0, widthPix, heightPix); } catch (Exception e) { e.printStackTrace(); } return bitmap; } /** * 生成有logo的二维码Bitmap * * @param context 二维码内容 * @param widthPix 二维码宽度 * @param heightPix 二维码高度 * @param logo 二维码logo的bitmap * @return Bitmap */ public static Bitmap createHaveLogoQRCode(String context, int widthPix, int heightPix, Bitmap logo) { Bitmap haveLogoQRCodeBitmap = null; Bitmap noLogoQRCodeBitmap = createNoLogoQRCode(context, widthPix, heightPix); haveLogoQRCodeBitmap = addLogo(noLogoQRCodeBitmap, logo); return haveLogoQRCodeBitmap; } /** * 向原来的bitmap上面添加一个bitmap * * @param src 原始Bitmap * @param logo 添加的Bitmap * @return Bitmap */ private static Bitmap addLogo(Bitmap src, Bitmap logo) { if (src == null) { return null; } if (logo == null) { return src; } int srcWidth = src.getWidth(); int srcHeight = src.getHeight(); int logoWidth = logo.getWidth(); int logoHeight = logo.getHeight(); if (srcWidth == 0 || srcHeight == 0) { return null; } if (logoWidth == 0 || logoHeight == 0) { return src; } float scaleFactor = srcWidth * 1.0f / 8 / logoWidth; Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888); try { Canvas canvas = new Canvas(bitmap); canvas.drawBitmap(src, 0, 0, null); canvas.scale(scaleFactor, scaleFactor, srcWidth / 2, srcHeight / 2); canvas.drawBitmap(logo, (srcWidth - logoWidth) / 2, (srcHeight - logoHeight) / 2, null); canvas.save(Canvas.ALL_SAVE_FLAG); canvas.restore(); } catch (Exception e) { bitmap = null; e.getStackTrace(); } return bitmap; } }
相信有点Android基础的猿们都会使用上面的代码了,就不给使用代码了。
这个Android应用程序还能够像微信一样扫描二维码,就行下面一样:
这个功能是抄的,在网上找的示例代码,一点没改直接用了。。。扫描之后,能够对二维码的内容进行解析,显示在一个界面上。
这个Android应用程序是用Android studio创建的。