二维码的实现原理和实现过程[数据码编码]_gb/t 18284-2000-程序员宅基地

技术标签: cpp  二维码  

数据码编码

在阅读这篇文章前,你需要具备一定的编程能力。

数据码编码,就是将二维码存储的字符转化成二进制。 这些字符可以是数字、字母、中文。 那么数据码编码时,就根据数字模式,数字字母模式,8位字节模式,中文模式进行编码。 8位字节模式可以描述整个计算机世界的字符,而其他模式是量身打造的,所以所需字节比8位字节模式要少。

该教程目前只实现了数字模式和8位字节模式的编码规范。

流程图

教程

模式指示符

GB/T 18284-2000 快速响应矩阵码 表2 模式指示符
模式 指示符
ECI 0111
数字 0001
字母数字 0010
8位字节(Byte) 0100
中国汉字 1101
结构链接 0011
FNC1(第一位置) 0101
FNC1(第二位置) 1001

       模式指示符在数据码字中占4位,是每个数据码字的第一部分。

       查看源码

字符计数指示符

GB/T 18284-2000 快速响应矩阵码 表3 字符计数指示符的位数
版本 数字模式 字母数字模式 8位字节模式 中国汉字模式
1-9 10 9 8 8
10-26 12 11 16 10
27-40 14 13 16 12

       字符计数指示符的位数在数据码字中根据版本和编码模式而有所不同,它计算的是模式编码时,源字符的长度。例如:对"qrcode"进行编码,那么所获得的源字符长度是6,如果编码模式选择的是字母数字模式,版本选择的是1,那么对应的该字符计数指示符的位数是9,而6在二进制中是"110",那么该字符计数指示符是"000000110"。

       查看源码

模式编码

       该方法进行的是根据模式来分发模式编码

   查看源码
数字模式编码

       例1:将"01234567"进行编码,首先要对这些数字进行分割。分割成 012 345 67的形式,即将源字符(纯数字),如果字符长度满足3的倍数,那么正好可以分割成3n的序列形式。但是如果不满足3的倍数,那么就可以用3n+1和3n+2的序列形式来表示。所以示例中是一个标准的3n+2序列形式。

       在二进制中想要表示这些数字,3位的十进制数字,最大为999,二进制中2的10次方[1024]可以涵盖这些数字,2位的十进制数字,最大为99,二进制中2的7次方[128]可以涵盖这些数字,1位的十进制数字,最大为9,二进制中2的4次方[16]可以涵盖这些数字。

       例1:将"01234567"进行编码:

       012->0000001100

       345->0101011001

       67->1000011

       例2:将"0125"进行编码:

       012->0000001100

       5->0101

       查看源码

字母数字模式编码
8位字节编码

       8位字节编码即依据ASCII编码表进行编码。如果你想用8位字节表示中文,那么可以根据GB2312或UTF-8来对中文字符进行处理,具体的GB2312处理方式:

#include<string>
#include<iostream>
int main(){
    
	std::string a = "你";
	std::cout << std::hex << (short)a[0] << std::endl;
	std::cout << std::hex << (short)a[1] << std::endl;
	char p[5] = {
     0xffc4, 0xffe3 };
	std::cout << p;
	std::cin >> a;
}

       以此,可以对照GB2312编码表对中文向8位字节流转换。

       查看源码

中国汉字编码

结束指示符

       我们有义务标识数据码已经结束,并且应该根据二维码定义的数据码长度巧妙得告诉数据码结束了。

       结束指示符:"0000",如果剩余位不足4位,填充满0。

       查看源码

补充0

       我们有义务将数据码补充成完整的8位字节。

       根据数据码[模式指示符+字符计数指示符+模式编码+结束指示符]的长度补充0,直至该长度满足8的倍数。(1byte = 8bit)

       查看源码

补充字节

       我们有义务将数据码补充成与版本模式一致的长度。

       根据数据码[模式指示符+字符计数指示符+模式编码+结束指示符+补充0]的长度轮流补充"11101100","00010001",以此让数据码字符合二维码版本、编码模式、纠错等级规定的数据码字长度。

       查看源码

源码

模式指示符

   教程
/*
* @method mode_indicator
* @params void
* @return void
* @throw()
* @methodState: stable
* This function get the mode indicator to append it to <code>result<code>.
*/
void qrcode::data_encode::DataEncode::mode_indicator(){
    
	this->member_result = "";
	int mode = this->member_basic_information->getMode();
	switch (mode){
    
	case qrcode::settings::mode::sign::NUMBER_MODE:
		this->member_result += "0001";
		break;
	case qrcode::settings::mode::sign::BYTE_MODE:
		this->member_result += "0100";
		break;
	case qrcode::settings::mode::sign::CHINESE_MODE:
		this->member_result += "1101";
		break;
	case qrcode::settings::mode::sign::LETTER_MODE:
		this->member_result += "0010";
		break;
	}
}

字符计数指示符

   教程
/*
* @method character_count_indicator
* @params int count
* @return void
* @throw()
* @methodState: stable
* This function get the character_count_indicator to append it to <code>result<code>
*/
void qrcode::data_encode::DataEncode::character_count_indicator(int length){
    
	int code_length = qrcode::data_encode::settings::character_count_indicator_length(this->member_basic_information);
	std::string binary = qrcode::tools::decimal_to_binary(length);
	int binary_length = binary.length();
	if (code_length > binary.length()){
    
		for (int i = 0; i < code_length - binary_length; i++){
    
			binary.insert(binary.begin(), '0');
		}
	}
	this->member_result += binary;
}

模式编码

   教程
/*
* @method mode_encode
* @params std::string code
* @return void
* @throw()
* @methodState: extendable
* This function is used to dispatch ***_mode_encode,and now just support for
* 4 modes.There are many languages on the earth.And I cannot know them from A to Z.
* if you want encode the language of your motherland
* which is not Chinese(GB2312) or English(ASCII) in this demo,
* please know the rules for encoding and do it yourself.
*/
void qrcode::data_encode::DataEncode::mode_encode(std::string code){
    
	std::string encode;
	int mode = this->member_basic_information->getMode();
	switch (mode){
    
	case qrcode::settings::mode::sign::NUMBER_MODE:
		encode = number_mode_encode(code);
		break;
	case qrcode::settings::mode::sign::CHINESE_MODE:
		encode = chinese_mode_encode(code);
		break;
	case qrcode::settings::mode::sign::BYTE_MODE:
		encode = byte_mode_encode(code);
		break;
	case qrcode::settings::mode::sign::LETTER_MODE:
		encode = letter_mode_encode(code);
		break;
	}
	member_result += encode;
}
/*
* @method number_mode_encode
* @params std::string code
* @return std::string
* @throw
* @methodState: stable
* This function is used to encode the code from number mode.
*/
std::string qrcode::data_encode::DataEncode::number_mode_encode(std::string code){
    
	//original source length
	int length = code.length();
	//result
	std::string result = "";
	//operated_data
	std::string operated_data = "";
	for (int i = 0; i < length; i = i + 3){
    	
		operated_data = code.substr(i, 3);
		if (operated_data.length() < 3){
    
			break;
		}
		char * temp = NULL;
		temp = new char[11];
		int demical = std::stoi(operated_data);
		std::string binary = tools::decimal_to_binary(demical);
		sprintf_s(temp,11,"%010s",binary.data());
		result += temp;
		delete temp;
		temp = NULL;
		operated_data = "";
	}
	//handle the last of the code
	if (operated_data.length() >= 0){
    
		char * temp = NULL;
		if (operated_data.length() == 1){
    
			temp = new char[5];
			int demical = std::stoi(operated_data);
			std::string binary = tools::decimal_to_binary(demical);
			sprintf_s(temp, 5, "%04s", binary.data());
		}
		else if (operated_data.length() == 2){
    
			temp = new char[8];
			int demical = std::stoi(operated_data);
			std::string binary = tools::decimal_to_binary(demical);
			sprintf_s(temp, 8, "%07s", binary.data());
		}
		result += temp;
		delete temp;
		temp = nullptr;
	}
	return result;
}
/*
* @method byte_mode_encode
* @params std::string code
* @return std::string
* @throw
* @methodState: stable
* This function is used to encode the code from byte mode.
*/
std::string qrcode::data_encode::DataEncode::byte_mode_encode(std::string code){
    
	std::string result;
	for (auto item : code){
    
		char * temp=nullptr;
		if (item < 0x7f){
    
			temp = new char[9];
			std::string operated_data = qrcode::tools::decimal_to_binary(item);
			sprintf_s(temp, 9, "%08s", operated_data.data());
			result += temp;
		}
		else{
    
			temp = new char[17];
			std::string operated_data = qrcode::tools::decimal_to_binary(item);
			sprintf_s(temp, 17, "%016s", operated_data.data());
			result += temp;
		}
		delete temp;
		temp = nullptr;
	}
	return result;
}
}

结束指示符

   教程
/*
* @method qrcode::data_encode::DataEncode::end_indicator
* @params void
* @return void
* @throw()
* @methodState: stable
* This function get the end_indicator to append it to<code>result</code>
*/
void qrcode::data_encode::DataEncode::end_indicator(){
    
	int code_length = qrcode::data_encode::settings::code_length(this->member_basic_information);
	// byte_length to bit_length,
	int bit_length = code_length << 3;
	int remain_bit = bit_length - member_result.length();
	switch (remain_bit){
    
	case 1:
		member_result += "0";
		break;
	case 2:
		member_result += "00";
		break;
	case 3:
		member_result += "000";
		break;
	default:
		member_result += "0000";
		break;
	}
}

补充0

   教程
/*
* @method qrcode::data_encode::DataEncode::make_up_to_a_multiple_of_8
* @params void
* @return void
* @throw()
* @methodState: stable
* This function append zeros to result to make up as a multiple of 8.
*/
void qrcode::data_encode::DataEncode::make_up_to_a_multiple_of_8(){
    
	int remain_bit = member_result.length() & 7;
	if (remain_bit){
    
		for (int i = 0; i < 8 - remain_bit; i++){
    
			member_result.push_back('0');
		}
	}
}

补充字节

   教程
/*
* @method qrcode::data_encode::DataEncode::pad_bytes
* @params void
* @return void
* @throw()
* @methodState: stable
* This function append a string of 8 bits to make up <code>result</code>
* as the final result.
*/
void qrcode::data_encode::DataEncode::pad_bytes(){
    
	int byte_length = member_result.length() >> 3;
	int code_length = qrcode::data_encode::settings::code_length(this->member_basic_information);
	int remain_byte = code_length - byte_length;
	bool turn = true;
	while (remain_byte > 0){
    
		if (turn){
    
			member_result.append("11101100");
			turn = false;
		}
		else{
    
			member_result.append("00010001");
			turn = true;
		}
		remain_byte--;
	}
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/bosaidongmomo/article/details/103195498

智能推荐

5个超厉害的资源搜索网站,每一款都可以让你的资源满满!_最全资源搜索引擎-程序员宅基地

文章浏览阅读1.6w次,点赞8次,收藏41次。生活中我们无时不刻不都要在网站搜索资源,但就是缺少一个趁手的资源搜索网站,如果有一个比较好的资源搜索网站可以帮助我们节省一大半时间!今天小编在这里为大家分享5款超厉害的资源搜索网站,每一款都可以让你的资源丰富精彩!网盘传奇一款最有效的网盘资源搜索网站你还在为找网站里面的资源而烦恼找不到什么合适的工具而烦恼吗?这款网站传奇网站汇聚了4853w个资源,并且它每一天都会持续更新资源;..._最全资源搜索引擎

Book类的设计(Java)_6-1 book类的设计java-程序员宅基地

文章浏览阅读4.5k次,点赞5次,收藏18次。阅读测试程序,设计一个Book类。函数接口定义:class Book{}该类有 四个私有属性 分别是 书籍名称、 价格、 作者、 出版年份,以及相应的set 与get方法;该类有一个含有四个参数的构造方法,这四个参数依次是 书籍名称、 价格、 作者、 出版年份 。裁判测试程序样例:import java.util.*;public class Main { public static void main(String[] args) { List <Book>_6-1 book类的设计java

基于微信小程序的校园导航小程序设计与实现_校园导航微信小程序系统的设计与实现-程序员宅基地

文章浏览阅读613次,点赞28次,收藏27次。相比于以前的传统手工管理方式,智能化的管理方式可以大幅降低学校的运营人员成本,实现了校园导航的标准化、制度化、程序化的管理,有效地防止了校园导航的随意管理,提高了信息的处理速度和精确度,能够及时、准确地查询和修正建筑速看等信息。课题主要采用微信小程序、SpringBoot架构技术,前端以小程序页面呈现给学生,结合后台java语言使页面更加完善,后台使用MySQL数据库进行数据存储。微信小程序主要包括学生信息、校园简介、建筑速看、系统信息等功能,从而实现智能化的管理方式,提高工作效率。

有状态和无状态登录

传统上用户登陆状态会以 Session 的形式保存在服务器上,而 Session ID 则保存在前端的 Cookie 中;而使用 JWT 以后,用户的认证信息将会以 Token 的形式保存在前端,服务器不需要保存任何的用户状态,这也就是为什么 JWT 被称为无状态登陆的原因,无状态登陆最大的优势就是完美支持分布式部署,可以使用一个 Token 发送给不同的服务器,而所有的服务器都会返回同样的结果。有状态和无状态最大的区别就是服务端会不会保存客户端的信息。

九大角度全方位对比Android、iOS开发_ios 开发角度-程序员宅基地

文章浏览阅读784次。发表于10小时前| 2674次阅读| 来源TechCrunch| 19 条评论| 作者Jon EvansiOSAndroid应用开发产品编程语言JavaObjective-C摘要:即便Android市场份额已经超过80%,对于开发者来说,使用哪一个平台做开发仍然很难选择。本文从开发环境、配置、UX设计、语言、API、网络、分享、碎片化、发布等九个方面把Android和iOS_ios 开发角度

搜索引擎的发展历史

搜索引擎的发展历史可以追溯到20世纪90年代初,随着互联网的快速发展和信息量的急剧增加,人们开始感受到了获取和管理信息的挑战。这些阶段展示了搜索引擎在技术和商业模式上的不断演进,以满足用户对信息获取的不断增长的需求。

随便推点

控制对象的特性_控制对象特性-程序员宅基地

文章浏览阅读990次。对象特性是指控制对象的输出参数和输入参数之间的相互作用规律。放大系数K描述控制对象特性的静态特性参数。它的意义是:输出量的变化量和输入量的变化量之比。时间常数T当输入量发生变化后,所引起输出量变化的快慢。(动态参数) ..._控制对象特性

FRP搭建内网穿透(亲测有效)_locyanfrp-程序员宅基地

文章浏览阅读5.7w次,点赞50次,收藏276次。FRP搭建内网穿透1.概述:frp可以通过有公网IP的的服务器将内网的主机暴露给互联网,从而实现通过外网能直接访问到内网主机;frp有服务端和客户端,服务端需要装在有公网ip的服务器上,客户端装在内网主机上。2.简单的图解:3.准备工作:1.一个域名(www.test.xyz)2.一台有公网IP的服务器(阿里云、腾讯云等都行)3.一台内网主机4.下载frp,选择适合的版本下载解压如下:我这里服务器端和客户端都放在了/usr/local/frp/目录下4.执行命令# 服务器端给执_locyanfrp

UVA 12534 - Binary Matrix 2 (网络流‘最小费用最大流’ZKW)_uva12534-程序员宅基地

文章浏览阅读687次。题目:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=93745#problem/A题意:给出r*c的01矩阵,可以翻转格子使得0表成1,1变成0,求出最小的步数使得每一行中1的个数相等,每一列中1的个数相等。思路:网络流。容量可以保证每一行和每一列的1的个数相等,费用可以算出最小步数。行向列建边,如果该格子是_uva12534

免费SSL证书_csdn alphassl免费申请-程序员宅基地

文章浏览阅读504次。1、Let's Encrypt 90天,支持泛域名2、Buypass:https://www.buypass.com/ssl/resources/go-ssl-technical-specification6个月,单域名3、AlwaysOnSLL:https://alwaysonssl.com/ 1年,单域名 可参考蜗牛(wn789)4、TrustAsia5、Alpha..._csdn alphassl免费申请

测试算法的性能(以选择排序为例)_算法性能测试-程序员宅基地

文章浏览阅读1.6k次。测试算法的性能 很多时候我们需要对算法的性能进行测试,最简单的方式是看算法在特定的数据集上的执行时间,简单的测试算法性能的函数实现见testSort()。【思想】:用clock_t计算某排序算法所需的时间,(endTime - startTime)/ CLOCKS_PER_SEC来表示执行了多少秒。【关于宏CLOCKS_PER_SEC】:以下摘自百度百科,“CLOCKS_PE_算法性能测试

Lane Detection_lanedetectionlite-程序员宅基地

文章浏览阅读1.2k次。fromhttps://towardsdatascience.com/finding-lane-lines-simple-pipeline-for-lane-detection-d02b62e7572bIdentifying lanes of the road is very common task that human driver performs. This is important ..._lanedetectionlite

推荐文章

热门文章

相关标签