标签:
关于二维码是什么,以及二维码是如何生成的,我也没有研究得很深入,就不多说了,以免误导大家。请参看:
下面是一个可以生成和解析二维码的工具类,该类用到了zxing工具包,我通过Maven去下载的:
<dependencies> <!-- JavaSE包依赖于Core包,因此Core包不需要直接依赖了 <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.1.0</version> </dependency> --> <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> <version>3.1.0</version> </dependency> </dependencies>
在网上搜索的时候我发现,有不少同学在使用maven的时候都同时导入了这两个包,但是我发现这个artifactId为javase的包依赖于core包,因此我们不需要再在pom.xml中声明对core包的依赖了。
下面这个类是一个工具类:
package com.abc.qrcode; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Image; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import com.google.zxing.BarcodeFormat; import com.google.zxing.Binarizer; import com.google.zxing.BinaryBitmap; import com.google.zxing.LuminanceSource; import com.google.zxing.MultiFormatReader; import com.google.zxing.MultiFormatWriter; import com.google.zxing.NotFoundException; import com.google.zxing.ReaderException; import com.google.zxing.Result; import com.google.zxing.WriterException; import com.google.zxing.client.j2se.BufferedImageLuminanceSource; import com.google.zxing.common.BitMatrix; import com.google.zxing.common.HybridBinarizer; public class QRCodeUtil { // 这几项可以由其他调用的类设置,因此是public static的 public static int BARCODE_WIDTH = 80; public static int QRCODE_WIDTH = 200; public static String FORMAT = "jpg";// 生成的图片格式 public static int BLACK = 0x000000;// 编码的颜色 public static int WHITE = 0xFFFFFF;// 空白的颜色 // 二维码中间的图像配置。注意,由于二维码的容错率有限,因此中间遮挡的面积不要太大,否则可能解析不出来。 private static int ICON_WIDTH = (int)(QRCODE_WIDTH / 7.5); private static int HALF_ICON_WIDTH = ICON_WIDTH / 2; private static int FRAME_WIDTH = 4;// Icon四周的边框宽度 // 二维码读码器和写码器 private static final MultiFormatWriter WRITER = new MultiFormatWriter(); private static final MultiFormatReader READER = new MultiFormatReader(); // 测试 public static void main(String[] args) throws Exception { /** * 二维码测试。 */ String iconPath = "C:\\icon.jpg"; String content = "http://www.baidu.com"; File qrCode = new File("C:\\QRCode." + FORMAT); File qrCodeWithIcon = new File("C:\\QRCodeWithIcon." + FORMAT); // 生成二维码 writeToFile(createQRCode(content), qrCode); // 生成带图标的二维码 writeToFile(createQRCodeWithIcon(content, iconPath), qrCodeWithIcon); // 解析二维码 System.out.println(parseQRCode(qrCode)); // 解析带图标的二维码 System.out.println(parseQRCode(qrCodeWithIcon)); // 编码成字节数组并解析 byte[] data = createQRCodeToBytes(content); String result = parseQRFromBytes(data); System.out.println(result); /** * 一维码测试。 */ String barCodeContent="6936983800013"; File barCode = new File("C:\\BarCode." + FORMAT); writeToFile(createBarCode(barCodeContent), barCode); } /** * 将String编码成二维码的图片后,使用字节数组表示,便于传输。 * * @param content * @return * @throws WriterException * @throws IOException */ public static final byte[] createQRCodeToBytes(String content) throws WriterException, IOException { BufferedImage image = createQRCode(content); ByteArrayOutputStream os = new ByteArrayOutputStream(); ImageIO.write(image, FORMAT, os); return os.toByteArray(); } /** * 把一个String编码成二维码的BufferedImage. * * @param content * @return * @throws WriterException */ public static final BufferedImage createQRCode(String content) throws WriterException { // 长和宽一样,所以只需要定义一个SIZE即可 BitMatrix matrix = WRITER.encode( content, BarcodeFormat.QR_CODE, QRCODE_WIDTH, QRCODE_WIDTH); return toBufferedImage(matrix); } /** * 编码字符串为二维码,并在该二维码中央插入指定的图标。 * @param content * @param iconPath * @return * @throws WriterException */ public static final BufferedImage createQRCodeWithIcon( String content, String iconPath) throws WriterException { BitMatrix matrix = WRITER.encode( content, BarcodeFormat.QR_CODE, QRCODE_WIDTH, QRCODE_WIDTH); // 读取Icon图像 BufferedImage scaleImage = null; try { scaleImage = scaleImage(iconPath, ICON_WIDTH, ICON_WIDTH, true); } catch (IOException e) { e.printStackTrace(); } int[][] iconPixels = new int[ICON_WIDTH][ICON_WIDTH]; for (int i = 0; i < scaleImage.getWidth(); i++) { for (int j = 0; j < scaleImage.getHeight(); j++) { iconPixels[i][j] = scaleImage.getRGB(i, j); } } // 二维码的宽和高 int halfW = matrix.getWidth() / 2; int halfH = matrix.getHeight() / 2; // 计算图标的边界: int minX = halfW - HALF_ICON_WIDTH;//左 int maxX = halfW + HALF_ICON_WIDTH;//右 int minY = halfH - HALF_ICON_WIDTH;//上 int maxY = halfH + HALF_ICON_WIDTH;//下 int[] pixels = new int[QRCODE_WIDTH * QRCODE_WIDTH]; // 修改二维码的字节信息,替换掉一部分为图标的内容。 for (int y = 0; y < matrix.getHeight(); y++) { for (int x = 0; x < matrix.getWidth(); x++) { // 如果点在图标的位置,用图标的内容替换掉二维码的内容 if (x > minX && x < maxX && y > minY && y < maxY) { int indexX = x - halfW + HALF_ICON_WIDTH; int indexY = y - halfH + HALF_ICON_WIDTH; pixels[y * QRCODE_WIDTH + x] = iconPixels[indexX][indexY]; } // 在图片四周形成边框 else if ((x > minX - FRAME_WIDTH && x < minX + FRAME_WIDTH && y > minY - FRAME_WIDTH && y < maxY + FRAME_WIDTH) || (x > maxX - FRAME_WIDTH && x < maxX + FRAME_WIDTH && y > minY - FRAME_WIDTH && y < maxY + FRAME_WIDTH) || (x > minX - FRAME_WIDTH && x < maxX + FRAME_WIDTH && y > minY - FRAME_WIDTH && y < minY + FRAME_WIDTH) || (x > minX - FRAME_WIDTH && x < maxX + FRAME_WIDTH && y > maxY - FRAME_WIDTH && y < maxY + FRAME_WIDTH)) { pixels[y * QRCODE_WIDTH + x] = WHITE; } else { // 这里是其他不属于图标的内容。即为二维码没有被图标遮盖的内容,用矩阵的值来显示颜色。 pixels[y * QRCODE_WIDTH + x] = matrix.get(x, y) ? BLACK : WHITE; } } } // 用修改后的字节数组创建新的BufferedImage. BufferedImage image = new BufferedImage( QRCODE_WIDTH, QRCODE_WIDTH, BufferedImage.TYPE_INT_RGB); image.getRaster().setDataElements(0, 0, QRCODE_WIDTH, QRCODE_WIDTH, pixels); return image; } /** * 从一个二维码图片的字节信息解码出二维码中的内容。 * * @param data * @return * @throws ReaderException * @throws IOException */ public static final String parseQRCodeBytes(byte[] data) throws ReaderException, IOException { ByteArrayInputStream is = new ByteArrayInputStream(data); BufferedImage image = ImageIO.read(is); return parseQRCode(image); } /** * 从一个BufferedImage中解码出二维码的内容。 * * @param image * @return * @throws ReaderException */ public static final String parseQRCode(BufferedImage image) throws ReaderException { LuminanceSource source = new BufferedImageLuminanceSource(image); Binarizer binarizer = new HybridBinarizer(source); BinaryBitmap bitmap = new BinaryBitmap(binarizer); Result result = READER.decode(bitmap); // 这里丢掉了Result中其他一些数据 return result.getText(); } /** * 从一个图片文件中解码出二维码中的内容。 * * @param file * @return 解析后的内容。 * @throws IOException * @throws ReaderException */ public static final String parseQRCode(File file) throws IOException, ReaderException { BufferedImage image = ImageIO.read(file); return parseQRCode(image); } /** * 将字符串编码成一维码(条形码)。 * @param content * @return * @throws WriterException * @throws IOException */ public static final BufferedImage createBarCode(String content) throws WriterException, IOException { MultiFormatWriter writer = new MultiFormatWriter(); // 一维码的宽>高。这里我设置为 宽:高=3:1 BitMatrix matrix = writer.encode(content, BarcodeFormat.EAN_13, BARCODE_WIDTH * 3, BARCODE_WIDTH); return toBufferedImage(matrix); } /** * 从图片中解析出一维码或者二维码的内容。如果解析失败,则抛出NotFoundException。 * @param image * @return * @throws NotFoundException */ public static final String parseImage(BufferedImage image) throws NotFoundException { LuminanceSource source = new BufferedImageLuminanceSource(image); Binarizer binarizer = new HybridBinarizer(source); BinaryBitmap bitmap = new BinaryBitmap(binarizer); Result result = READER.decode(bitmap); // 这里丢掉了Result中其他一些数据 return result.getText(); } /** * 将BufferedImage对象输出到指定的文件中。 * * @param image * @param destFile * @throws IOException */ public static final void writeToFile(BufferedImage image, File destFile) throws IOException { ImageIO.write(image, FORMAT, destFile); } /** * 将一个BitMatrix对象转换成BufferedImage对象 * * @param matrix * @return */ private static final 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; } /** * 把传入的原始图像按高度和宽度进行缩放,生成符合要求的图标。 * * @param srcImageFile 源文件地址 * @param height 目标高度 * @param width 目标宽度 * @param hasFiller 比例不对时是否需要补白:true为补白; false为不补白; * @throws IOException */ private static final BufferedImage scaleImage(String srcImageFile, int height, int width, boolean hasFiller) throws IOException { double ratio = 0.0; // 缩放比例 File file = new File(srcImageFile); BufferedImage srcImage = ImageIO.read(file); Image destImage = srcImage.getScaledInstance( width, height, BufferedImage.SCALE_SMOOTH); // 计算比例 if ((srcImage.getHeight() > height) || (srcImage.getWidth() > width)) { if (srcImage.getHeight() > srcImage.getWidth()) { ratio = (new Integer(height)).doubleValue() / srcImage.getHeight(); } else { ratio = (new Integer(width)).doubleValue() / srcImage.getWidth(); } AffineTransformOp op = new AffineTransformOp( AffineTransform.getScaleInstance(ratio, ratio), null); destImage = op.filter(srcImage, null); } if (hasFiller) {// 补白 BufferedImage image = new BufferedImage( width, height, BufferedImage.TYPE_INT_RGB); Graphics2D graphic = image.createGraphics(); graphic.setColor(Color.white); graphic.fillRect(0, 0, width, height); if (width == destImage.getWidth(null)) { graphic.drawImage(destImage, 0, (height - destImage.getHeight(null)) / 2, destImage.getWidth(null), destImage.getHeight(null), Color.white, null); } else { graphic.drawImage(destImage, (width - destImage.getWidth(null)) / 2, 0, destImage.getWidth(null), destImage.getHeight(null), Color.white, null); } graphic.dispose(); destImage = image; } return (BufferedImage) destImage; } }
方法的作用和用法在文档中都写得很清楚啦,就不需要解释了。下面是执行结果:
下面是生成的二维码:
下面是生成的一维码:
大家可以用手机扫描试试看。
标签:
原文地址:http://my.oschina.net/itblog/blog/501577