中文乱码

  上篇《ZBar-windows下编译和使用》已经成功解析了条形码,但目标是二维码,经测试二维码中文会出现乱码。
下图二维码的内容是“http123测试456”,解析后的内容为“http123娴嬭瘯456”

搜索了一下关键词,解决方案如下http://blog.csdn.net/zizi7/article/details/51880129

修改文件 zbar/qrcode/qrdectxt.c:

 latin1_cd=iconv_open("GB18030","UTF-8");
/*But this one is often used, as well.*/
sjis_cd=iconv_open("GB2312","UTF-8");
/*This is a trivial conversion just to check validity without extra code.*/
utf8_cd=iconv_open("UTF-8","UTF-8");
...
enc_list[]=sjis_cd;
enc_list[]=latin1_cd;
enc_list[]=utf8_cd;

重新编译运行后,正确输出“http123测试456”

自己实现中文解码

  ZBar解析后的字符原始输出是UTF-8格式,然后使用了iconv将其转换为相应的字符编码,但最终目标是移植到STM32F4上,如果要直接输出中文编码,有几种方案:

1. 把iconv移植到STM32F4上
2. 自己实现UTF8-8转中文编码
3. 把编码工作交给上位机

字符集和编码格式

搜索了一下字符编码规则,觉得方案2比方案1,3更容易实现。这里先简单介绍下与本文相关的字符集和编码格式。
1. Unicode
Unicode是字符集,也叫万国码,顾名思义就是包含所有国家的文字。
2. GB18030
GB18030是中文字符集,可以认为是Unicode的一个子集,还有其他GBXXXXX的中文字符集,他们的关系简单来说就是包含的中文字符个数不一样。简单起见,这里只是使用2个字节的GB18030,一共20902个汉字,也基本覆盖常见的汉字了。书读得少,4个字节的汉字也没认识几个。
3. UTF-8
UTF-8是Unicode字符集的一种编码格式,还有其他UTF-16,UTF-32,ZBar使用了 UTF-8。
UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~6个字节表示一个符号,根据不同的符号而变化字节长度。
UTF-8的编码规则很简单,只有二条:
1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。
(具体例子可以参考http://blog.csdn.net/xiaolei1021/article/details/52093706)

下表总结了编码规则,字母x表示可用编码的位。

4. GB18030,Unicode,UTF-8的关系

UTF-8转GB18030实现

了解相关字符集和编码格式,可以开始写转换代码了。

1. 需要一个GB18030字符集,其实就是一个数组,实现代码如下(VS下编译)
调用UnicodeToGB18030Table函数生成一个GB18030字符集数组。

 char* UnicodeToGB18030String(const wchar_t* unicode_str)
{
UINT code_page = ; //GB2312 :936 GB18030: 54936
int len=WideCharToMultiByte(code_page,,unicode_str,-,NULL,,NULL,NULL);
char* buf=new char[len+];
WideCharToMultiByte(code_page,,unicode_str,-,buf,len,NULL,NULL);
buf[len]=;
return buf;
}
int UnicodeToGB18030Table(void)
{
FILE *table;
wchar_t unicode[]={0x4E00,};
char* gb18030;
int cnt=;
table = fopen("unicode_to_gb18030_table.c","w");
if(table == NULL)
{
printf("can not open unicode_to_gb18030_table.c\n");
system("pause");
exit();
}
fprintf(table, "%s", "const char unicode_to_gb18030_table1[] = {\n");
for(unicode[]=0x4E00; unicode[]<=0x9FA5; unicode[]++)
{
gb18030 = UnicodeToGB18030String(unicode); if(unicode[]==0x9FA5)
{
fprintf(table, "0x%X,0x%X ", (UINT8)gb18030[],(UINT8)gb18030[]);
}
else
{
fprintf(table, "0x%X,0x%X, ", (UINT8)gb18030[],(UINT8)gb18030[]);
} cnt ++;
if(cnt == )
{
cnt = ;
fprintf(table, "\n");
}
} fprintf(table, "\n};");
fclose(table);
}

2. 通过查表,将UTF-8转为GB18030

 int zbar_utf8_to_gb18030 (uint8_t* utf8_code, uint32_t utf8_len, uint8_t* gb18030)
{
uint8_t utf8_bytes[];//该数组最大为6个字节,但这里只考虑3个字节的中文编码
uint32_t i = , j = ;
uint16_t unicode_value;
uint8_t* unicode = gb18030; for(i=; i< utf8_len; i+=) {
utf8_bytes[] = utf8_code[i+] & 0x0F;
utf8_bytes[] = utf8_code[i+] & 0x3F;
utf8_bytes[] = utf8_code[i+] & 0x3F; unicode[j] = (utf8_bytes[] >> ) | ((utf8_bytes[]) << );
unicode[j+] = utf8_bytes[] | ((utf8_bytes[] & 0x03) << );
unicode_value = (unicode[j]<<) + unicode[j+];
if(unicode_value>=0x4E00){
gb18030[j] = unicode_to_gb18030_table1[(unicode_value-0x4E00)*];
gb18030[j+] = unicode_to_gb18030_table1[(unicode_value-0x4E00)* + ];
}
j += ;
}
return ;
}

中文字符集和编码转码函数有了,下一步就是替换ZBar源码的编码转换部分。
删掉zbar/qrcode/qrdectxt.c 中iconv相关的代码,将zbar_utf8_to_gb18030函数加入
qr_code_data_list_extract_text函数中:

 int qr_code_data_list_extract_text(const qr_code_data_list *_qrlist,
zbar_image_scanner_t *iscn,
zbar_image_t *img)
{
....
case QR_MODE_BYTE:{
int gb18030_cnt = zbar_utf8_to_gb18030(entry->payload.data.buf, entry->payload.data.len, sa_text+sa_ntext);
sa_ntext += gb18030_cnt;
}
break;
....
}

重新编译运行后

正确输出“http123测试456”

坐等下班,回家过年...................

二维码开源库ZBar-实现中文解码的更多相关文章

  1. 二维码开源库zbar、zxing使用心得

    首先说明我的测试场景是“识别打印在纸上的二维码”,在扫描结果中寻找二维码并进行识别,而不是直接让摄像头对着二维码扫描. zbar和zxing用的都是自己从github上clone的c++源码/接口编译 ...

  2. 二维码开源库ZBar-吐槽篇

    前不久在网上看到一篇文章<QR-Decoder-OV5640 二维码识别> ,是某开发板的教程.记得对应的开发板以前购买过,当初只是为了看OV5640的JPG的输出效果,结果由于公司奇葩的 ...

  3. 二维码开源库ZBar-MDK STM32F429移植

    前两篇文章已经实现ZBar在Windows平台下的编译和使用,本文将介绍如何把ZBar移植到STM32F429,IDE使用MDK. 1. MDK工程设置 (1)不勾选Use MicroLIB ,使用I ...

  4. 二维码开源库ZBar-windows下编译和使用

    源码 下载最新Zbar源码(http://zbar.sourceforge.net/),网站的WIKI是空白的,所以只能在源码包里找使用说明了,很遗憾Windows下怎么编译没说明,只是说明了Wind ...

  5. C++二维码相关库编译

    一.瞎想 坐在地铁上闲来无聊,突然想到了二维码,顺手就百度了下相关的资料,目前C++二维码相关的库不多,也就zbar(开源中国上下了半天也没下载下来).zxing,不过这两个库据说都是解析二维码的,不 ...

  6. Android二维码开源项目zxing用例简化和生成二维码、条形码

    上一篇讲到:Android二维码开源项目zxing编译,编译出来后有一个自带的測试程序:CaptureActivity比較复杂,我仅仅要是把一些不用的东西去掉,用看起来更方便,二维码和条形码的流行性自 ...

  7. 个性二维码开源专题<替换元素点>

    基础方法:ChangeFillShape //修改填充形状 ChangeFillShape(...) // 摘要: // 修改填充形状 // // 参数: // g: // 图形画板 // // Fo ...

  8. 个性二维码开源专题<替换定位点>

    基础方法: ChangeFillShape //修改填充形状 ChangeFillShape(...) // 摘要: // 修改填充形状 // // 参数: // g: // 图形画板 // // F ...

  9. 个性二维码开源专题<液化/圆角/效果>

    基础方法: ChangeFillShape //修改填充形状 ChangeFillShape(...) // 摘要: // 修改填充形状 // // 参数: // g: // 图形画板 // // F ...

随机推荐

  1. [国嵌攻略][060][LCD工作原理解析]

    LCD硬件体系 1.LCD液晶屏 液晶属于一种有机化合物,分子形状为长棒状,在不同的电流作用下,分子会有规律旋转,这样对光线产生一定的控制形成一个像素,而很多像素右可以构成完整的图像. LCD是Liq ...

  2. Git分支管理及常见操作

    众所周知,使用Git分支,我们可以从开发主线上分离开来,然后在不影响主线的同时继续工作. 既然要使用Git分支,这里就涉及到Git分支的管理及常见操作,如列出分支,分支的创建,分支的删除,分支的合并等 ...

  3. Spark高可用集群搭建

    Spark高可用集群搭建 node1    node2    node3   1.node1修改spark-env.sh,注释掉hadoop(就不用开启Hadoop集群了),添加如下语句 export ...

  4. redis常见命令使用

    这篇经验主要介绍了Redis常见用的一些操作命令.这篇例子是在windows上操作的.linux类似.写的一些基础,大神就别看了. 工具/原料   redis windows 方法/步骤   1 可以 ...

  5. Tp-link路由器怎么设置端口映射 内网端口映射听语音

    https://jingyan.baidu.com/article/ca00d56c710ef9e99eebcf85.html 只有一台能上网的电脑就可以自己免费搭建服务器,本经验简单介绍家用tp-l ...

  6. 30分钟学玩转RabbitMQ

    最近在学习RabbitMQ,在网上找了不少资料发现都特高端.动辄集群部署,分布式架构什么的,对于一个初学者实在不够友好.心想求人不如求自己,为什么不自己整理一套资料呢?于是<30分钟学玩转Rab ...

  7. Django之Model组件

    Model组件在django基础篇就已经提到过了,本章介绍更多高级部分. 一.回顾 1.定义表(类) ##单表 from django.db import models class user(mode ...

  8. python3 第十三章 - 数据类型之tuple(元组)

    元组与列表类似,不同之处在于元组的元素不能修改. 元组使用小括号,列表使用方括号. 元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可: language = ('c', 'c++', 'py ...

  9. 如何去掉ul标签的多余空白或多余大距离?

    在css中写入 ul{ margin:; padding:; list-style: none; } 让其内边距和外边距为0,列表样式为空

  10. Servlet--ServletInputStream类,ServletOutputStream类

    ServletInputStream类 定义 public abstract class ServletInputStream extends InputStream 这个类定义了一个用来读取客户端的 ...