给定一个既含有ASCII码又含有汉字的字符串,如“abcd今天天气不错”,如何生成其二维码并将获得的二维码识别成该字符串呢?要解决这个问题,首先我们需明白ASCII码和汉字的区别。ASCII码字节数为1,且其对应的二进码字符串首字符都是0,而汉字字节数为2,其对应的二进码字符串首字符可为0也可为1。所以为了区别汉字和ASCII码,我们可以在汉字第一个字节前添加一个由二进码1开头的字节。
方法一:
(一)二维码生成:
思路:获取给定字符串中的每个字符,并将其转为二进制码字符串。根据二进制码字符串的长度来判断字符是汉字还是ASCII码,并对其进行相应的补码操作。若是ASCII码,则补完码后需在其后加两个字节,以保持二维码图形的美观。若是汉字,则补完码后需在第一个字节前加一个由二进制码1开头的字节,以区分汉字和ASCII码。添加相应的字节后,将获得的二进制码字符串保存到数组中。之后对数组中的每个二进制码字符串进行字符遍历,若是‘0’,则设置画笔颜色为白色,若是‘1’,则设置画笔颜色为黑色。最后绘制图片。
1.获取给定字符串中的每个字符,并将其转为二进制码字符串。
String str="abcd今天天气不错";
for(int i=0;i<str.length();i++) {
char c=str.charAt(i);//遍历字符串中的每个字符
binarystr=Integer.toBinaryString(c);//将获得的字符转为二进制码字符串
}
2.判断字符是汉字还是ASCII码,并对其进行相应的补码操作和添加字节操作。
if(binarystr.length()<=8) {//ASCII码
while(binarystr.length()<8) {//不足8位的在前补0
binarystr="0"+binarystr;
}
binarystr=binarystr+"1001010011010011";//补完码后 凑齐3个字节 保持图形的美观
}
else{//汉字
while(binarystr.length()<16) {//不足16位在前补0
binarystr="0"+binarystr;
}
binarystr="10010100"+binarystr;//在前补一个字节 该字节首个二进制码为1 用来区分是汉字还是ASCII码
}
3.对数组中的每个二进制码字符串进行字符遍历,设置画笔颜色,绘制图形。
for(int i=0;i<tobinarystr.length;i++) {
String str=tobinarystr[i];//获取二进制码字符串数组中的每个二进码字符串
for(int j=0;j<str.length();j++) {
char c=str.charAt(j);//获取二进制码字符串中的每个字符
//根据获得的字符进行判断 设置画笔颜色
if(c=='0') {
g.setColor(Color.WHITE);
}else {
g.setColor(Color.BLACK);
}
//绘制图片
g.fillRect(100+i*10, 100+j*10, 10, 10);
}
}
4.完整代码
QRcodeunion1类:将给定字符串中的每个字符转换为二进制码字符串,并创建保存二进制码字符串的数组。
public class QRcodeunion1 {
String str="abcd今天天气不错";
//声明一个字符串数组,用来保存将字符转为二进制码的字符串
String[] binarystring=new String[str.length()];
//创建方法 将字符串中每个字符(ASCII码或汉字)转为二进制码字符串 返回字符串数组
public String[] tobinarystring() {
String binarystr;
for(int i=0;i<str.length();i++) {
char c=str.charAt(i);//遍历字符串中的每个字符
binarystr=Integer.toBinaryString(c);//将获得的字符转为二进制码字符串
//判断是汉字还是ASCII码
if(binarystr.length()<=8) {//ASCII码
while(binarystr.length()<8) {//不足8位的在前补0
binarystr="0"+binarystr;
}
binarystr=binarystr+"1001010011010011";//凑齐3个字节 保持图形的美观
}
else{//汉字
while(binarystr.length()<16) {//不足16位在前补0
binarystr="0"+binarystr;
}
binarystr="10010100"+binarystr;//在前补一个字节 该字节前一位为1 用来区分是汉字还是ASCII码
}
System.out.println(binarystr);
binarystring[i]=binarystr;
}
return binarystring;
}
}
QRcodeunionUI1类:创建二维码窗体界面,绘制二维码
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class QRcodeunionUI1 extends JFrame {
private static final long serialVersionUID = 1L;
String[] tobinarystr= {};
//创建窗体界面
public void initUI() {
setTitle("二维码");
setSize(800,800);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
Graphics g=getGraphics();
paint(g);//调用绘制方法
}
public void paint(Graphics g) {
super.paint(g);
//遍历二进制码字符串数组
for(int i=0;i<tobinarystr.length;i++) {
String str=tobinarystr[i];
for(int j=0;j<str.length();j++) {
char c=str.charAt(j);
if(c=='0') {
g.setColor(Color.WHITE);
}else {
g.setColor(Color.BLACK);
}
//按行绘制二进制码字符串 按列绘制二进制码字符串中的每个字符
g.fillRect(100+i*10, 100+j*10, 10, 10);
}
}
}
public static void main(String[]args) {
QRcodeunionUI1 qrcodeui=new QRcodeunionUI1();
QRcodeunion1 qrcode=new QRcodeunion1();
qrcodeui.tobinarystr=qrcode.tobinarystring();//调用QRcodeunion中的方法
qrcodeui.initUI();
}
}
5.效果图

(二)二维码识别
思路:将获得的二维码图片转为int类型的二维数组,保存该图片的像素点。根据图片的宽度和方向进行取值,并设置灰度值,从而对灰度值进行判断以获得二进制码字符串。然后根据获得的二进制码字符串中的首个字符来判断是汉字还是ASCII码。若是ASCII码,则只取前8位二进制码字符合成一个二进制码字符串,若是汉字,则只取后16位二进制码字符合成一个二进制码字符串。之后将获得的二进码字符串先转为整数,再转为字符,并保存到字符数组中。最后遍历输出字符数组中的字符。
1.将获得的二维码图片转为int类型的二维数组,保存该图片的像素点。
public int[][] getpixelarry(String imgpath){
BufferedImage img = null;//先声明图片对象为空
try {
img=ImageIO.read(new File(imgpath));//根据图片路径生成图片
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//获取图片的宽和高
int w=img.getWidth();
int h=img.getHeight();
int[][] imgarr=new int[w][h];//定义一个与图片宽高一样的用来保存图片像素点的二维数组
for(int i=0;i<w;i++) {
for(int j=0;j<h;j++) {
imgarr[i][j]=img.getRGB(i, j);
}
}
return imgarr;
}
2.根据图片的宽度和方向进行取值,并设置灰度值,从而对灰度值进行判断以获得二进码字符串。
//考虑到截图边界的问题 每次从格子矩形的中点取起
for(int i=width/2;i<w;i+=width) {
String str1="";
String str2="";
for(int j=width/2;j<width*24;j+=width) {//每隔一个格子取
int rgb=imgarr[i][j];
Color color=new Color(rgb);
//设置灰度值
int red=color.getRed();
int blue=color.getBlue();
int green=color.getGreen();
int gray=(red+blue+green)/3;
//根据灰度值进行判断 获取字符串
if(gray<150) {
str1+="1";//黑色取1
}else {
str1+="0";
}
}
}
3.根据所获二进制码字符串中的首个字符来判断是汉字还是ASCII码,从而进行相应的取值操作,获得新的二进码字符串。
if(str1.charAt(0)=='0') {//ASCII码
for(int k=0;k<8;k++) {//只取前8位为一个ASCII码字符的字节
str2+=""+str1.charAt(k);//二进制码字符转为二进制码字符串
}
}else {//汉字
for(int t=8;t<24;t++) {//后16位为汉字的两个字节
str2+=""+str1.charAt(t);
}
}
4.将新的二进码字符串先转为整数,再转为字符,并保存到字符数组中。最后遍历输出该数组中的字符。
int in=Integer.parseInt(str2, 2);//将获取的二进制码字符串转换为整数
char c=(char)in;//整数转为字符
ch[m]=c;//将获取的字符保存在字符数组中
m++;
for(int k=0;k<ch.length;k++) {
System.out.print(ch[k]);//打印输出字符数组
}
5.完整代码
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
//中英混合二维码识别
public class QRcodecla {
//构建一个方法 返回将二维码图片转为int类型的二维数组
public int[][] getpixelarry(String imgpath){
BufferedImage img = null;//先声明图片对象为空
try {
img=ImageIO.read(new File(imgpath));//根据图片路径生成图片
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//获取图片的宽和高
int w=img.getWidth();
int h=img.getHeight();
int[][] imgarr=new int[w][h];//定义一个与图片宽高一样的用来保存图片像素点的二维数组
for(int i=0;i<w;i++) {
for(int j=0;j<h;j++) {
imgarr[i][j]=img.getRGB(i, j);
}
}
return imgarr;
}
//创建方法 根据获得的二进制码 生成字符
public void tostring() {
//获取存有二维码图片像素点数组
int[][] imgarr=getpixelarry("C:\\Users\\011\\Pictures\\Saved Pictures\\中英混合QRcode.png");
int w=imgarr.length;
int width=w/10;//格子宽度
char[] ch=new char[10];
int m=0;//待输出字符数组的下标
//考虑到截图边界的问题 每次从格子矩形的中点取起
for(int i=width/2;i<w;i+=width) {
String str1="";
String str2="";
for(int j=width/2;j<width*24;j+=width) {//每隔一个格子取
int rgb=imgarr[i][j];
Color color=new Color(rgb);
//设置灰度值
int red=color.getRed();
int blue=color.getBlue();
int green=color.getGreen();
int gray=(red+blue+green)/3;
//根据灰度值进行判断
if(gray<150) {
str1+="1";//黑色取1
}else {
str1+="0";
}
}
//根据获得二进制码字符串中的首个字符判断是汉字还ASCII码
if(str1.charAt(0)=='0') {//ASCII码
for(int k=0;k<8;k++) {//只取前8位为一个ASCII码字符的字节
str2+=""+str1.charAt(k);//二进制码字符转为二进制码字符串
}
}else {//汉字
for(int t=8;t<24;t++) {//后16位为汉字的两个字节
str2+=""+str1.charAt(t);
}
}
int in=Integer.parseInt(str2, 2);//将获取的二进制码字符串转换为整数
char c=(char)in;//整数转为字符
System.out.println(str2+"---"+c);
ch[m]=c;//将获取的字符保存到字符数组中
m++;
}
for(int k=0;k<ch.length;k++) {
System.out.print(ch[k]);//打印输出字符数组
}
}
public static void main(String[]args) {
QRcodecla qrcode=new QRcodecla();
qrcode.tostring();
}
}
6.效果图

方法二:
(一)二维码生成
思路:获取给定字符串中的每个字符,并将其转为二进制码字符串。根据二进制码字符串的长度来判断字符是汉字还是ASCII码,并对其进行相应的补码操作。若是汉字,补完码后还需在第一个字节前添加一个由二进制码1开头的字节,以区分ASCII码和汉字。并将所有获得的二进制码字符串合成一个新的二进制码字符串。由于新获得的二进制码字符串共有176位二进制码,所以在对新获得的二进码字符串进行字符遍历时,需借助一个计数器,每隔16个字符将计数器设置为0。这样就可以巧妙地设置坐标,使绘制出的图形美观。
1.获取给定字符串中的每个字符,并将其转为二进制码字符串。
String str="abcd今天天气不错";
String binarystr;
for(int i=0;i<str.length();i++) {
char c=str.charAt(i);//遍历字符串中的每个字符
binarystr=Integer.toBinaryString(c);//将获得的字符转为二进制码字符串
2.判断字符是汉字还是ASCII码,并对其进行相应的补码和添加字节操作。之后将所有获得的二进制码字符串合成一个新的二进制码字符串。
//声明一个字符串,用来保存将字符转为二进制码的字符串
String binarystring="";
if(binarystr.length()<=8) {//ASCII码
while(binarystr.length()<8) {//不足8位的在前补0
binarystr="0"+binarystr;
}
}
else{//汉字
while(binarystr.length()<16) {//不足16位在前补0
binarystr="0"+binarystr;
}
binarystr="10010100"+binarystr;//在前补一个字节 该字节第一位为1 用来区分是汉字还是ASCII码
}
binarystring+=binarystr;
3.对新获得的二进码字符串进行字符遍历,设置画笔颜色,并巧妙地设置坐标。
for(int i=0;i<tobinarystr.length();i++) {
//每列绘制指定二进制码字符串中的一个字符 设置一个计数器count
//将所获得的新二进制码字符串每取16个字符 即每隔16个字符将计数器设置为0
if(count==16) {
count=0;
}
char c=tobinarystr.charAt(i);
if(c=='0') {
g.setColor(Color.WHITE);
}else {
g.setColor(Color.BLACK);
}
//按行绘制二进制码字符串 按列绘制二进制码字符串中的每个字符 这样每行有11个格子 每列有16个格子
g.fillRect(100+i/16*10, 100+count*10, 10, 10);//格子的宽度和高度都为10
count++;
}
4.完整代码
QRcodeunion2类:将给定字符串中的每个字符转换为二进制码字符串,并将这些二进制码字符串合成一个新的二进制码字符串。
public class QRcodeunion2 {
String str="abcd今天天气不错";
//声明一个字符串,用来保存将字符转为二进制码的字符串
String binarystring="";
//创建方法 将字符串中每个字符(ASCII码或汉字)转为二进制码字符串 返回字符串数组
public String tobinarystring() {
String binarystr;
for(int i=0;i<str.length();i++) {
char c=str.charAt(i);//遍历字符串中的每个字符
binarystr=Integer.toBinaryString(c);//将获得的字符转为二进制码字符串
//判断是汉字还是ASCII码
if(binarystr.length()<=8) {//ASCII码
while(binarystr.length()<8) {//不足8位的在前补0
binarystr="0"+binarystr;
}
}
else{//汉字
while(binarystr.length()<16) {//不足16位在前补0
binarystr="0"+binarystr;
}
binarystr="10010100"+binarystr;//在前补一个字节 该字节第一位为1 用来区分是汉字还是ASCII码
}
System.out.println(binarystr);
binarystring+=binarystr;
}
return binarystring;
}
}
QRcodeunionUI2类:创建窗体界面,绘制二维码
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class QRcodeunionUI2 extends JFrame {
private static final long serialVersionUID = 1L;
QRcodeunion2 qrcode2=new QRcodeunion2();//调用QRcodeunion2中的方法
String tobinarystr=qrcode2.tobinarystring();
//创建窗体界面
public void initUI() {
setTitle("二维码");
setSize(800,800);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
Graphics g=getGraphics();
paint(g);//调用绘制方法
}
public void paint(Graphics g) {
super.paint(g);
//遍历字符串
int count=0;
for(int i=0;i<tobinarystr.length();i++) {
//每列绘制指定字符串中的一个字符 设置一个计数器count
//将所获得的二进制码字符串每取16个字符 即每隔16个字符将计数器设置为0
if(count==16) {
count=0;
}
char c=tobinarystr.charAt(i);
if(c=='0') {
g.setColor(Color.WHITE);
}else {
g.setColor(Color.BLACK);
}
//按行绘制二进制码字符串 按列绘制二进制码字符串中的每个字符 这样每行有11个格子 每列有16个格子
g.fillRect(100+i/16*10, 100+count*10, 10, 10);//格子的宽度和高度都为10
count++;
}
}
public static void main(String[]args) {
QRcodeunionUI2 qrcodeui=new QRcodeunionUI2();
qrcodeui.initUI();
}
}
5.效果图

(二)二维码识别
思路:将获得的二维码图片转为int类型的二维数组,保存该图片的像素点。根据图片的宽度和方向进行取值,并设置灰度值,从而对灰度值进行判断以获得二进制码字符串。从获得的二进制码字符串中截取需转为ASCII码字符或中文字符的二进制码字符串子串,将其保存到字符串数组中。遍历数组中二进制码字符串,将其转为对应的字符,并输出该字符。
1.将获得的二维码图片转为int类型的二维数组,保存该图片的像素点。
public int[][] getpixelarry(String imgpath){
BufferedImage img = null;//先声明图片对象为空
try {
img=ImageIO.read(new File(imgpath));//根据图片路径生成图片
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//获取图片的宽和高
int w=img.getWidth();
int h=img.getHeight();
int[][] imgarr=new int[w][h];//定义一个与图片宽高一样的用来保存图片像素点的二维数组
for(int i=0;i<w;i++) {
for(int j=0;j<h;j++) {
imgarr[i][j]=img.getRGB(i, j);
}
}
return imgarr;
}
2.根据图片的宽度和方向进行取值,并设置灰度值,从而对灰度值进行判断以获得二进制码字符串。
for(int i=width/2;i<w;i+=width) {//每隔一个格子进行取值
for(int j=width/2;j<16*width;j+=width) {//每列有16个格子
int rgb=imgarr[i][j];
Color color=new Color(rgb);
//取灰度值进行判断
int red=color.getRed();
int green=color.getGreen();
int blue=color.getBlue();
int gray=(red+green+blue)/3;
if(gray<150) {
str1+="1";
}else {
str1+="0";
}
}
}
3.截取需转为ASCII码字符或中文字符的二进制码字符串子串,将其保存到字符串数组中。
int k=0;
while(k<4) {//从二维码图可知,前四个字符为ASCII码
str2[k]="";//数组中的每个字符串需初始化
for(int m=k*8;m<8*(1+k);m++) {//每隔8个二进制码取值
str2[k]+=str1.charAt(m);
}
k++;
}
while(4<=k&&k<10) {//后六个字符为中文
str2[k]="";
for(int n=40+24*(k-4);n<32+24*(k-3);n++) {//每隔16个二进制码取值
str2[k]+=str1.charAt(n);
}
k++;
}
4.遍历数组中二进制码字符串,将其转为对应的字符,并输出该字符。
for(int t=0;t<str2.length;t++) {
int in=Integer.parseInt(str2[t], 2);
char c=(char)in;
System.out.print(c);
}
5.完整代码
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class QRcodecla2 {
//构建一个方法 返回将二维码图片转为int类型的二维数组
public int[][] getpixelarry(String imgpath){
BufferedImage img = null;//先声明图片对象为空
try {
img=ImageIO.read(new File(imgpath));//根据图片路径生成图片
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//获取图片的宽和高
int w=img.getWidth();
int h=img.getHeight();
int[][] imgarr=new int[w][h];//定义一个与图片宽高一样的用来保存图片像素点的二维数组
for(int i=0;i<w;i++) {
for(int j=0;j<h;j++) {
imgarr[i][j]=img.getRGB(i, j);
}
}
return imgarr;
}
public void tostring() {
int[][] imgarr=getpixelarry("C:\\Users\\011\\Pictures\\Saved Pictures\\中英混合2.png");
int w=imgarr.length;
int width=w/11;//格子宽度(一行由11个黑白格子组成)
String str1="";//定义保存由灰度值判断的二进制码
String[] str2=new String[10];//定义保存待转换字符的二进制码字符串
//考虑到截图边界的问题 每次从格子矩形的中点取起
for(int i=width/2;i<w;i+=width) {
for(int j=width/2;j<16*width;j+=width) {
int rgb=imgarr[i][j];
Color color=new Color(rgb);
//取灰度值进行判断
int red=color.getRed();
int green=color.getGreen();
int blue=color.getBlue();
int gray=(red+green+blue)/3;
if(gray<150) {
str1+="1";
}else {
str1+="0";
}
}
}
//从str1中截取需转为ASCII码字符(8bit)或中文字符(16bit)的二进制码字符串
//保存到数组中
int k=0;
while(k<4) {//从中英混合二维码图可知,前四个字符为ASCII码
str2[k]="";//数组中的每个字符串需初始化
for(int m=k*8;m<8*(1+k);m++) {//每隔8个二进制码取值
str2[k]+=str1.charAt(m);
}
k++;
}
while(4<=k&&k<10) {//后六个字符为中文
str2[k]="";
for(int n=40+24*(k-4);n<32+24*(k-3);n++) {//每隔16个二进制码取值
str2[k]+=str1.charAt(n);
}
k++;
}
//打印输出二进制码字符串及其所代表的字符
for(int t=0;t<str2.length;t++) {
int in=Integer.parseInt(str2[t], 2);
char c=(char)in;
System.out.println(str2[t]+"---"+c);
}
//打印输出识别后的二维码字符串
for(int t=0;t<str2.length;t++) {
int in=Integer.parseInt(str2[t], 2);
char c=(char)in;
System.out.print(c);
}
}
//程序入口
public static void main(String[]args) {
QRcodecla2 qrcodecla2=new QRcodecla2();
qrcodecla2.tostring();
}
}
6.效果图

本文介绍了一种处理包含ASCII码和汉字的字符串生成二维码的方法,并提供了两种生成方案及二维码识别过程。通过补码和添加特殊标识区分不同字符类型,确保了二维码的正确生成与解析。
&spm=1001.2101.3001.5002&articleId=123831520&d=1&t=3&u=631622e26c31432dabb1a899924832c2)

被折叠的 条评论
为什么被折叠?



