在阅读这篇文章前,你需要具备一定的编程能力。
数据码编码,就是将二维码存储的字符转化成二进制。 这些字符可以是数字、字母、中文。 那么数据码编码时,就根据数字模式,数字字母模式,8位字节模式,中文模式进行编码。 8位字节模式可以描述整个计算机世界的字符,而其他模式是量身打造的,所以所需字节比8位字节模式要少。
该教程目前只实现了数字模式和8位字节模式的编码规范。
模式 | 指示符 |
ECI | 0111 |
数字 | 0001 |
字母数字 | 0010 |
8位字节(Byte) | 0100 |
中国汉字 | 1101 |
结构链接 | 0011 |
FNC1(第一位置) | 0101 |
FNC1(第二位置) | 1001 |
模式指示符在数据码字中占4位,是每个数据码字的第一部分。
查看源码
版本 | 数字模式 | 字母数字模式 | 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位字节编码即依据ASCII编码表进行编码。如果你想用8位字节表示中文,那么可以根据GB2312或UTF-8来对中文字符进行处理,具体的GB2312处理方式:
#include
#include
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。
查看源码
我们有义务将数据码补充成完整的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 result.
*/
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 result
*/
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 toresult
*/
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;
}
}
/*
* @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 result
* 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--;
}
}