二维码的实现原理和实现过程[数据码编码]

数据码编码

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

数据码编码,就是将二维码存储的字符转化成二进制。 这些字符可以是数字、字母、中文。 那么数据码编码时,就根据数字模式,数字字母模式,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--;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章