关于二维码实验的总结(前言+小试牛刀)

最近一段时间由于需要,差不多花了一周的时间,研究了一下二维码的问题。大致的时间分配是这样的:1~2天学习二维码的原理知识,1~2天分析学习网上的例程,1~2天根据需要修改例程。

最开始的时候,对于二维码一无所知,因而到网上去看了很多二维码原理方面的东西。也根据自己看的一些东西准备整理一些自己认为重要的东西(见上篇《二维码原理简介》)。但是,看到最后发现,二维码的原理中涉及到很多数学方面的知识,很多文章在讲解的同时会掺杂很多专业性较强的东西。笔者自认为不是一个数学天才,也不愿意花费过多的时间去阅读数学方面的知识。所以那篇《二维码原理简介》的确称得上是简介了。笔者只是希望能有一个感性的认识,知道诸如“通过识别三个边角上的正方形,即可唯一确定二维码”、“二维码的具体信息对应图片的哪一块区域”、“二维码的容错的能力”等等。

1.初试牛刀

首先,笔者在网上下载了一个用java语言实现的二维码生成和编写的程序。其结构非常简单,如下图:

其主要的底层功能主要由QRCode.jar包来实现(即具体的那些底层东西)。QR Code码是由日本Denso公司于1994年9月研制的一种矩阵二维码符号,它具有一维条码及其它二维条码所具有的信息容量大、可靠性高、可表示汉字及图象多种文字信息、保密防伪性强等优点。

在这个demo中,主要有2个类,一个就是EncodeImg,另一个就是TwoDimensionCodeImage。TwoDimensionCodeImage类中定义了一个BufferedImage类的变量,这个变量就是二维码图片的长、宽和颜色(黑色与白色)的信息。在后面解码二维码图片会调用它。

EncodeImg则实现了所有的逻辑。这个类中定义了6个方法(还有一些方法调用这几个方法,类似于接口,此处略去不提),分别是:2个生成二维码方法、1个生成二维码公共方法(前面2个方法会调用它)、2个解析二维码 和一个main方法。结构也是十分清晰。我们逐个来分析。

生成QRCode图片 1:

/**

* 生成二维码(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图片 2:

/**

* 生成二维码(QRCode)图片

* @param content 存储内容

* @param output 输出流

* @param imgType 图片类型

* @param size 二维码尺寸

*/

public void encoderQRCode(String content, OutputStream output, String imgType, int size) {

try {

BufferedImage bufImg = this.qRCodeCommon(content, imgType, size);

// 生成二维码QRCode图片

ImageIO.write(bufImg, imgType, output);

} catch (Exception e) {

e.printStackTrace();

}

}

大家可以仔细比对一下这两个方法,会发现二者仅仅在参数上有略微不同。一种是以图片的形式保存生成的二维码,一种则把结果写入到数据流中。既然涉及数据流,多半都是和网络传输部分有关(这句是个人臆想)。而二者的共同点就是一开始都调用了this.qRCodeCommon(content, imgType, size)这个方法。那么这个方法具体是实现了什么呢?

生成QRCode的公共方法:

/**

* 生成二维码(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

boolean[][] codeOut = qrcodeHandler.calQrcode(contentBytes);

for (int i = 0; i

for (int j = 0; 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;

}

相信配上注释,代码的可读性大大提高。可见,红色部分标记的语句是完成输出内容到二维码转换的重要步骤。可惜,这个方法qrcodeHandler.calQrcode(contentBytes)被封装在QRCode.jar文件中,无法继续分析。有了这一步,后面的逻辑就很简单了,遍历二维数组,codeOut[j][i]如果是1则将图片相应位置设为黑色。最后得到二维码图片。

对应地,有2种解码方法。

解析QRCode方法1:

/**

* 解析二维码(QRCode)

* @param imgPath 图片路径

* @return

*/

public String decoderQRCode(String imgPath) {

// QRCode 二维码图片的文件

File imageFile = new File(imgPath);

BufferedImage bufImg = null;

String content = null;

try {

bufImg = ImageIO.read(imageFile);

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;

}

解析QRCode方法2:

/**

* 解析二维码(QRCode)

* @param input 输入流

* @return

*/

public String decoderQRCode(InputStream input) {

BufferedImage bufImg = null;

String content = null;

try {

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;

}

二者的区别,在此不再赘述。二者蓝色部分就是解码的部分。同样被封装到QRcode.jar中。我们无法看到更多的内容。

最后再来看看main方法:

public static void main(String[] args) {

String imgPath = "F:/Michael_QRCode3.png";

String encoderContent = "我名为宇智波斑 ";

EncodeImg handler = new EncodeImg();

handler.encoderQRCode(encoderContent, imgPath, "png");

System.out.println("========encoder success");

String decoderContent = handler.decoderQRCode(imgPath);

System.out.println("解析结果如下:");

System.out.println(decoderContent);

System.out.println("========decoder success!!!");

}

运行该程序,即可在电脑的F盘找到生成的二维码图片Michael_QRCode3.png。在eclipse的控制台窗口也是可以看到解析的结果。此时,你用手机上的二维码扫描软件扫描一下生成的二维码,同样可以得到正确的结果。

总结:可以看到,这个java程序的接口还是相对较简单的,使用起来也很方便。笔者本来是要写一个Android的程序的。于是想把这个Java程序移植到一个Android工程上。但事情远比想象中的复杂。当把这些文件放到一个Android程序中发现,程序中出现了很多错误。这些错误主要集中在那些绘图相关的包上。网上有人说Android和java在绘图上的实现好像是不兼容的,需要自己做相应的移植。笔者仍不想放弃,看到"JRE System Libruary"下面有很多jar包,将它们全部导入Android程序中。则程序可以成功编译。但是程序在运行时,点击生成二维码时出现闪退的现象。根据打印的Log发现仍然是因为Android中不包含相应绘图APi。至此,笔者决意放弃这个java程序。

最近一段时间由于需要,差不多花了一周的时间,研究了一下二维码的问题。大致的时间分配是这样的:1~2天学习二维码的原理知识,1~2天分析学习网上的例程,1~2天根据需要修改例程。

最开始的时候,对于二维码一无所知,因而到网上去看了很多二维码原理方面的东西。也根据自己看的一些东西准备整理一些自己认为重要的东西(见上篇《二维码原理简介》)。但是,看到最后发现,二维码的原理中涉及到很多数学方面的知识,很多文章在讲解的同时会掺杂很多专业性较强的东西。笔者自认为不是一个数学天才,也不愿意花费过多的时间去阅读数学方面的知识。所以那篇《二维码原理简介》的确称得上是简介了。笔者只是希望能有一个感性的认识,知道诸如“通过识别三个边角上的正方形,即可唯一确定二维码”、“二维码的具体信息对应图片的哪一块区域”、“二维码的容错的能力”等等。

1.初试牛刀

首先,笔者在网上下载了一个用java语言实现的二维码生成和编写的程序。其结构非常简单,如下图:

其主要的底层功能主要由QRCode.jar包来实现(即具体的那些底层东西)。QR Code码是由日本Denso公司于1994年9月研制的一种矩阵二维码符号,它具有一维条码及其它二维条码所具有的信息容量大、可靠性高、可表示汉字及图象多种文字信息、保密防伪性强等优点。

在这个demo中,主要有2个类,一个就是EncodeImg,另一个就是TwoDimensionCodeImage。TwoDimensionCodeImage类中定义了一个BufferedImage类的变量,这个变量就是二维码图片的长、宽和颜色(黑色与白色)的信息。在后面解码二维码图片会调用它。

EncodeImg则实现了所有的逻辑。这个类中定义了6个方法(还有一些方法调用这几个方法,类似于接口,此处略去不提),分别是:2个生成二维码方法、1个生成二维码公共方法(前面2个方法会调用它)、2个解析二维码 和一个main方法。结构也是十分清晰。我们逐个来分析。

生成QRCode图片 1:

/**

* 生成二维码(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图片 2:

/**

* 生成二维码(QRCode)图片

* @param content 存储内容

* @param output 输出流

* @param imgType 图片类型

* @param size 二维码尺寸

*/

public void encoderQRCode(String content, OutputStream output, String imgType, int size) {

try {

BufferedImage bufImg = this.qRCodeCommon(content, imgType, size);

// 生成二维码QRCode图片

ImageIO.write(bufImg, imgType, output);

} catch (Exception e) {

e.printStackTrace();

}

}

大家可以仔细比对一下这两个方法,会发现二者仅仅在参数上有略微不同。一种是以图片的形式保存生成的二维码,一种则把结果写入到数据流中。既然涉及数据流,多半都是和网络传输部分有关(这句是个人臆想)。而二者的共同点就是一开始都调用了this.qRCodeCommon(content, imgType, size)这个方法。那么这个方法具体是实现了什么呢?

生成QRCode的公共方法:

/**

* 生成二维码(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

boolean[][] codeOut = qrcodeHandler.calQrcode(contentBytes);

for (int i = 0; i

for (int j = 0; 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;

}

相信配上注释,代码的可读性大大提高。可见,红色部分标记的语句是完成输出内容到二维码转换的重要步骤。可惜,这个方法qrcodeHandler.calQrcode(contentBytes)被封装在QRCode.jar文件中,无法继续分析。有了这一步,后面的逻辑就很简单了,遍历二维数组,codeOut[j][i]如果是1则将图片相应位置设为黑色。最后得到二维码图片。

对应地,有2种解码方法。

解析QRCode方法1:

/**

* 解析二维码(QRCode)

* @param imgPath 图片路径

* @return

*/

public String decoderQRCode(String imgPath) {

// QRCode 二维码图片的文件

File imageFile = new File(imgPath);

BufferedImage bufImg = null;

String content = null;

try {

bufImg = ImageIO.read(imageFile);

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;

}

解析QRCode方法2:

/**

* 解析二维码(QRCode)

* @param input 输入流

* @return

*/

public String decoderQRCode(InputStream input) {

BufferedImage bufImg = null;

String content = null;

try {

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;

}

二者的区别,在此不再赘述。二者蓝色部分就是解码的部分。同样被封装到QRcode.jar中。我们无法看到更多的内容。

最后再来看看main方法:

public static void main(String[] args) {

String imgPath = "F:/Michael_QRCode3.png";

String encoderContent = "我名为宇智波斑 ";

EncodeImg handler = new EncodeImg();

handler.encoderQRCode(encoderContent, imgPath, "png");

System.out.println("========encoder success");

String decoderContent = handler.decoderQRCode(imgPath);

System.out.println("解析结果如下:");

System.out.println(decoderContent);

System.out.println("========decoder success!!!");

}

运行该程序,即可在电脑的F盘找到生成的二维码图片Michael_QRCode3.png。在eclipse的控制台窗口也是可以看到解析的结果。此时,你用手机上的二维码扫描软件扫描一下生成的二维码,同样可以得到正确的结果。

总结:可以看到,这个java程序的接口还是相对较简单的,使用起来也很方便。笔者本来是要写一个Android的程序的。于是想把这个Java程序移植到一个Android工程上。但事情远比想象中的复杂。当把这些文件放到一个Android程序中发现,程序中出现了很多错误。这些错误主要集中在那些绘图相关的包上。网上有人说Android和java在绘图上的实现好像是不兼容的,需要自己做相应的移植。笔者仍不想放弃,看到"JRE System Libruary"下面有很多jar包,将它们全部导入Android程序中。则程序可以成功编译。但是程序在运行时,点击生成二维码时出现闪退的现象。根据打印的Log发现仍然是因为Android中不包含相应绘图APi。至此,笔者决意放弃这个java程序。


相关内容

  • 科技论文图片处理方法
  • 科技论文中图片的处理方法 有位论文审稿人在自己的博文中写道:"我审稿时看稿件的顺序是题目.摘要.图表.前言.参考文献和正文".可见论文中图片的质量是非常重要的,处理一张图可能会花费大量的时间,正如焦老师所说的,那位德国小伙子处理一张图用了一个月时间.图片质量的好坏一定程度上决定了 ...

  • 智能餐厨垃圾预处理
  • 二维码功能大纲 一.智能预处理系统简介 1.概述 餐厨垃圾预处理系统是青岛天人环境股份有限公司在引进国外先进同类设备的基础上,进行消化吸收,针对我国餐厨垃圾特性,通过大量小试.中试.大试试验研制而成的系统化预处理系统.该系统工艺流程具有更简单.更可靠.低投资.低能耗.低有机质损失.高杂质去除率.高油 ...

  • 测绘实验报告
  • 中国矿业大学 变形监测与沉陷工程 实验报告 学院:环境与测绘学院 姓名:特列克 实验一 岩体内部移动变形监测演示试验 一. 实验内容 1.了解岩体内部移动变形监测系统的组成,各组成部分的名称及作用: 2.观看教师演示岩体内部观测站的建立过程和监测方法: 3.练习钻孔测斜仪.钻孔伸长仪各部件的连接.测 ...

  • 一审判决书(实例)
  • 重庆轻工业机械厂专利申请权权属纠纷案 重庆市第一中级人民法院 民事判决书 (2004)渝一中民初字第26号 原告重庆轻工业机械厂,住所地重庆市巴南区鱼洞镇新一村. 法定代表人于冰雁,厂长. 委托代理人龙云辉,重庆康实律师事务所律师. 委托代理人方海平,重庆康实律师事务所助理律师. 被告米文达,男,1 ...

  • 最新2015混沌在保密通信系统中的应用研究
  • 目 录 摘要 .................................................... 错误!未定义书签. ABSTRACT ................................................ 错误!未定义书签. 1 绪论 ....... ...

  • "割鸡焉用牛刀"阅读答案
  • 阅读<论语>中的一段文字,然后回答问题.(4分) 子之武城①,闻弦歌之声.夫子莞尔而笑,曰:"割鸡焉用牛刀?"子游对曰:"昔者偃也闻诸夫子曰:'君子学道则爱人,小人学道则易使也.'"子曰:"二三子!偃之言是也.前言戏之耳."(1 ...

  • MATLAB与建筑结构分析(前言建筑技术开发)
  • 第30卷第2期2003年2月 建 筑 技 术 开 发 BuildingTechniqueDevelopment Vol.30,No.2 Feb.2003 技术开发报道 MATLAB与建筑结构分析 卢林枫 解 琦 曾 珂 1 2 1 (11西安建筑科技大学土木工程学院,西安710055;21西安高科( ...

  • 2010届高三生物实验变量的应用
  • 变量的应用 一.学习目标 1. 掌握变量的类型.学会如何去除无关变量 2. 学会运用实验变量设置实验 二.重点难点 运用实验变量设置实验 [牛刀小试] 请写出本题的解题思路: 三.知识梳理 (一)自变量的确定 上题的自变量是 因变量是 . 上题的课题名称或研究目的是 . 变式训练1.为了研究光照是否 ...

  • 我的高山仰止教案
  • 高山仰止 [教学目标] 1.感悟孔子的人格之美以及与弟子之间感人的师生关系. 2.理解并积累文中常用的文言词语以及源自本课的成语. 3.背诵重点章句. [教学重难点] 重点: 1.掌握文句中的重点字词的读音,通假字,多义词,古今异义词,词类活用,特殊文言句式等. 2.掌握"党". ...