首先来展示一下成果:
二维码图片好像违规了,直接给链接吧网址链接
如果你扫了这个二维码就会得到一个网址,该网址是我写代码的参考,该网站讲述了如何编写一个二维码,很详细,我没有实现汉字的编码,实现了三种模式的编码,这个网址给的很详细,我也就不写了,如果再写就跟抄人家的没区别了。
下面给出生成的代码,其中有一些我自己写的工具,我会做出说明,如果不想看人家网站的话,代码中也有注释。
1.Matrix这个模板类是我做的一个二维数组的套壳,里面用的是动态申请空间,析构时自动释放
2.每个静态的值都是按照顺序来的,一般我都给了对应关系和索引如何计算
3.此类计算出来的二维码,在版本特别高时,我用微信没识别出来,没特别仔细的测试,300个2能识别(用直接跳转12306公众号了,不知道为啥),3000个2二维码已经密到有点看不清了(这个用微信扫没反应)
4.图像是使用我写的另外一个类来生成位图的,没用JPEG是因为转换没写
5.宽字节编码没写实现
6.没有解析二维码的实现
7.源代码在此这个啥都有
Windows11 gcc 8.1.0 vscode cmake
#pragma once
#include
#include
#include
#include
#include
#include
#ifndef _QR_ENCODE_
#define _QR_ENCODE_
#include "Util.h"
#include "Matrix.h"
#include "Image.h"
NAME_SPACE_START(myUtil)
using namespace std;
// Step 1: Choose the Error Correction Level
// Step 2: Determine the Smallest Version for the Data
// Step 3: Add the Mode Indicator
// Step 4: Add the Character Count Indicator
// The character count indicator must be placed after the mode indicator.
// Step 3: Encode Using the Selected Mode
// Step 4: Break Up into 8-bit Codewords and Add Pad Bytes if Necessary
#define VERSION_COUNT 40
#define MODE_INDICATOR_BIT_LENGTH 4
#define AMPLIFY_LEVEL 4
// #define DEBUG
//对应第几行
enum ErrorCorrectionLevel{
L = 0, // Recovers 7% of data
M = 1, // Recovers 15% of data
Q = 2, // Recovers 25% of data
H = 3 // Recovers 30% of data
};
//对应第几列
enum DataType{
NumMode=0,
AlpNumMode,
ByteMode,
KanjiMode
};
// Mode Indicator Character Count Indicator Encoded Data
//QRCode Mode Indicator 对应DataType, 此编码长度为MODE_INDICATOR_BIT_LENGTH
//The encoded data must start with the appropriate mode indicator
//that specifies the mode being used for the bits that come after it.
const static int ModeIndicator[]={
//NumMode AlpNumMode ByteMode KanjiMode ECIMode
1,2,4,8,7
};
// 将编码数据的长度编译为对应长度的二进制位,共有三种长度,每种长度中对应4种DataType
// The character count indicator is a string of bits that
// represents the number of characters that are being encoded.
const static int CharCountIndicator[3][4]{
{10,9,8,8}, // version 1~9
{12,11,16,10}, // version 10~26
{14,13,16,12}, // version 27~40
};
//Character Capacities by Version, Mode, and Error Correction
const static int CharCapTable[40][4][4]={
//L M Q H
//Numeric mode,Alphanumeric mode,Byte mode,Kanji mode
{{41,25,17,10},{34,20,14,8},{27,16,11,7},{17,10,7,4}},
{{77,47,32,20},{63,38,26,16},{48,29,20,12},{34,20,14,8}},
{{127,77,53,32},{101,61,42,26},{77,47,32,20},{58,35,24,15}},
{{187,114,78,48},{149,90,62,38},{111,67,46,28},{82,50,34,21}},
{{255,154,106,65},{202,122,84,52},{144,87,60,37},{106,64,44,27}},
{{322,195,134,82},{255,154,106,65},{178,108,74,45},{139,84,58,36}},
{{370,224,154,95},{293,178,122,75},{207,125,86,53},{154,93,64,39}},
{{461,279,192,118},{365,221,152,93},{259,157,108,66},{202,122,84,52}},
{{552,335,230,141},{432,262,180,111},{312,189,130,80},{235,143,98,60}},
{{652,395,271,167},{513,311,213,131},{364,221,151,93},{288,174,119,74}},
{{772,468,321,198},{604,366,251,155},{427,259,177,109},{331,200,137,85}},
{{883,535,367,226},{691,419,287,177},{489,296,203,125},{374,227,155,96}},
{{1022,619,425,262},{796,483,331,204},{580,352,241,149},{427,259,177,109}},
{{1101,667,458,282},{871,528,362,223},{621,376,258,159},{468,283,194,120}},
{{1250,758,520,320},{991,600,412,254},{703,426,292,180},{530,321,220,136}},
{{1408,854,586,361},{1082,656,450,277},{775,470,322,198},{602,365,250,154}},
{{1548,938,644,397},{1212,734,504,310},{876,531,364,224},{674,408,280,173}},
{{1725,1046,718,442},{1346,816,560,345},{948,574,394,243},{746,452,310,191}},
{{1903,1153,792,488},{1500,909,624,384},{1063,644,442,272},{813,493,338,208}},
{{2061,1249,858,528},{1600,970,666,410},{1159,702,482,297},{919,557,382,235}},
{{2232,1352,929,572},{1708,1035,711,438},{1224,742,509,314},{969,587,403,248}},
{{2409,1460,1003,618},{1872,1134,779,480},{1358,823,565,348},{1056,640,439,270}},
{{2620,1588,1091,672},{2059,1248,857,528},{1468,890,611,376},{1108,672,461,284}},
{{2812,1704,1171,721},{2188,1326,911,561},{1588,963,661,407},{1228,744,511,315}},
{{3057,1853,1273,784},{2395,1451,997,614},{1718,1041,715,440},{1286,779,535,330}},
{{3283,1990,1367,842},{2544,1542,1059,652},{1804,1094,751,462},{1425,864,593,365}},
{{3517,2132,1465,902},{2701,1637,1125,692},{1933,1172,805,496},{1501,910,625,385}},
{{3669,2223,1528,940},{2857,1732,1190,732},{2085,1263,868,534},{1581,958,658,405}},
{{3909,2369,1628,1002},{3035,1839,1264,778},{2181,1322,908,559},{1677,1016,698,430}},
{{4158,2520,1732,1066},{3289,1994,1370,843},{2358,1429,982,604},{1782,1080,742,457}},
{{4417,2677,1840,1132},{3486,2113,1452,894},{2473,1499,1030,634},{1897,1150,790,486}},
{{4686,2840,1952,1201},{3693,2238,1538,947},{2670,1618,1112,684},{2022,1226,842,518}},
{{4965,3009,2068,1273},{3909,2369,1628,1002},{2805,1700,1168,719},{2157,1307,898,553}},
{{5253,3183,2188,1347},{4134,2506,1722,1060},{2949,1787,1228,756},{2301,1394,958,590}},
{{5529,3351,2303,1417},{4343,2632,1809,1113},{3081,1867,1283,790},{2361,1431,983,605}},
{{5836,3537,2431,1496},{4588,2780,1911,1176},{3244,1966,1351,832},{2524,1530,1051,647}},
{{6153,3729,2563,1577},{4775,2894,1989,1224},{3417,2071,1423,876},{2625,1591,1093,673}},
{{6479,3927,2699,1661},{5039,3054,2099,1292},{3599,2181,1499,923},{2735,1658,1139,701}},
{{6743,4087,2809,1729},{5313,3220,2213,1362},{3791,2298,1579,972},{2927,1774,1219,750}},
{{7089,4296,2953,1817},{5596,3391,2331,1435},{3993,2420,1663,1024},{3057,1852,1273,784}},
};
static map<uint8_t,uint8_t> AlpValMappingTable={
{'0',0},{'1',1},{'2',2},{'3',3},{'4',4},{'5',5},{'6',6},{'7',7},{'8',8},{'9',9},
{'A',10},{'B',11},{'C',12},{'D',13},{'E',14},{'F',15},{'G',16},{'H',17},{'I',18},
{'J',19},{'K',20},{'L',21},{'M',22},{'N',23},{'O',24},{'P',25},{'Q',26},{'R',27},
{'S',28},{'T',29},{'U',30},{'V',31},{'W',32},{'X',33},{'Y',34},{'Z',35},{' ',36},
{'$',37},{'%',38},{'*',39},{'+',40},{'-',41},{'.',42},{'/',43},{':',44}
};
//value for exponent of alpha, index = EC Codewords Per Block - 7
const static int GeneratorPolynomialCoff[24][31]={
{0,87,229,146,149,238,102,21},
{0,175,238,208,249,215,252,196,28},
{0,95,246,137,231,235,149,11,123,36},
{0,251,67,46,61,118,70,64,94,32,45},
{0,220,192,91,194,172,177,209,116,227,10,55},
{0,102,43,98,121,187,113,198,142,131,87,157,86},
{0,74,152,176,100,86,100,106,104,130,218,206,140,78},
{0,199,249,155,48,190,124,218,137,216,87,207,59,22,91},
{0,8,183,61,91,202,37,51,58,58,237,140,124,5,99,105},
{0,120,104,107,109,102,161,76,3,91,191,147,169,182,194,225,120},
{0,43,139,206,78,43,239,123,206,214,147,24,99,150,39,243,163,136},
{0,215,234,158,94,184,97,118,170,79,187,152,148,252,179,5,98,96,153},
{0,67,3,105,153,52,90,83,17,150,159,44,128,153,133,252,222,138,220,171},
{0,17,60,79,50,61,163,26,187,202,180,221,225,83,239,156,164,212,212,188,190},
{0,240,233,104,247,181,140,67,98,85,200,210,115,148,137,230,36,122,254,148,175,210},
{0,210,171,247,242,93,230,14,109,221,53,200,74,8,172,98,80,219,134,160,105,165,231},
{0,171,102,146,91,49,103,65,17,193,150,14,25,183,248,94,164,224,192,1,78,56,147,253},
{0,229,121,135,48,211,117,251,126,159,180,169,152,192,226,228,218,111,0,117,232,87,96,227,21},
{0,231,181,156,39,170,26,12,59,15,148,201,54,66,237,208,99,167,144,182,95,243,129,178,252,45},
{0,173,125,158,2,103,182,118,17,145,201,111,28,165,53,161,21,245,142,13,102,48,227,153,145,218,70},
{0,79,228,8,165,227,21,180,29,9,237,70,99,45,58,138,135,73,126,172,94,216,193,157,26,17,149,96},
{0,168,223,200,104,224,234,108,180,110,190,195,147,205,27,232,201,21,43,245,87,42,195,212,119,242,37,9,123},
{0,156,45,183,29,151,219,54,96,249,24,136,5,241,175,189,28,75,234,150,148,23,9,202,162,68,250,140,24,151},
{0,41,173,145,152,216,31,179,182,50,48,110,86,239,96,222,125,42,173,226,193,224,130,156,37,251,216,238,40,192,180},
};
// index = (version-1)*4+(int)level
// Total Number of Data Codewords for this Version and EC Level
// EC Codewords Per Block
// Number of Blocks in Group 1
// Number of Data Codewords in Each of Group 1's Blocks
// Number of Blocks in Group 2
// Number of Data Codewords in Each of Group 2's Blocks
const static int ErrorCurrentTable[][6]={
{19,7,1,19,0,0},
{16,10,1,16,0,0},
{13,13,1,13,0,0},
{9,17,1,9,0,0},
{34,10,1,34,0,0},
{28,16,1,28,0,0},
{22,22,1,22,0,0},
{16,28,1,16,0,0},
{55,15,1,55,0,0},
{44,26,1,44,0,0},
{34,18,2,17,0,0},
{26,22,2,13,0,0},
{80,20,1,80,0,0},
{64,18,2,32,0,0},
{48,26,2,24,0,0},
{36,16,4,9,0,0},
{108,26,1,108,0,0},
{86,24,2,43,0,0},
{62,18,2,15,2,16},
{46,22,2,11,2,12},
{136,18,2,68,0,0},
{108,16,4,27,0,0},
{76,24,4,19,0,0},
{60,28,4,15,0,0},
{156,20,2,78,0,0},
{124,18,4,31,0,0},
{88,18,2,14,4,15},
{66,26,4,13,1,14},
{194,24,2,97,0,0},
{154,22,2,38,2,39},
{110,22,4,18,2,19},
{86,26,4,14,2,15},
{232,30,2,116,0,0},
{182,22,3,36,2,37},
{132,20,4,16,4,17},
{100,24,4,12,4,13},
{274,18,2,68,2,69},
{216,26,4,43,1,44},
{154,24,6,19,2,20},
{122,28,6,15,2,16},
{324,20,4,81,0,0},
{254,30,1,50,4,51},
{180,28,4,22,4,23},
{140,24,3,12,8,13},
{370,24,2,92,2,93},
{290,22,6,36,2,37},
{206,26,4,20,6,21},
{158,28,7,14,4,15},
{428,26,4,107,0,0},
{334,22,8,37,1,38},
{244,24,8,20,4,21},
{180,22,12,11,4,12},
{461,30,3,115,1,116},
{365,24,4,40,5,41},
{261,20,11,16,5,17},
{197,24,11,12,5,13},
{523,22,5,87,1,88},
{415,24,5,41,5,42},
{295,30,5,24,7,25},
{223,24,11,12,7,13},
{589,24,5,98,1,99},
{453,28,7,45,3,46},
{325,24,15,19,2,20},
{253,30,3,15,13,16},
{647,28,1,107,5,108},
{507,28,10,46,1,47},
{367,28,1,22,15,23},
{283,28,2,14,17,15},
{721,30,5,120,1,121},
{563,26,9,43,4,44},
{397,28,17,22,1,23},
{313,28,2,14,19,15},
{795,28,3,113,4,114},
{627,26,3,44,11,45},
{445,26,17,21,4,22},
{341,26,9,13,16,14},
{861,28,3,107,5,108},
{669,26,3,41,13,42},
{485,30,15,24,5,25},
{385,28,15,15,10,16},
{932,28,4,116,4,117},
{714,26,17,42,0,0},
{512,28,17,22,6,23},
{406,30,19,16,6,17},
{1006,28,2,111,7,112},
{782,28,17,46,0,0},
{568,30,7,24,16,25},
{442,24,34,13,0,0},
{1094,30,4,121,5,122},
{860,28,4,47,14,48},
{614,30,11,24,14,25},
{464,30,16,15,14,16},
{1174,30,6,117,4,118},
{914,28,6,45,14,46},
{664,30,11,24,16,25},
{514,30,30,16,2,17},
{1276,26,8,106,4,107},
{1000,28,8,47,13,48},
{718,30,7,24,22,25},
{538,30,22,15,13,16},
{1370,28,10,114,2,115},
{1062,28,19,46,4,47},
{754,28,28,22,6,23},
{596,30,33,16,4,17},
{1468,30,8,122,4,123},
{1128,28,22,45,3,46},
{808,30,8,23,26,24},
{628,30,12,15,28,16},
{1531,30,3,117,10,118},
{1193,28,3,45,23,46},
{871,30,4,24,31,25},
{661,30,11,15,31,16},
{1631,30,7,116,7,117},
{1267,28,21,45,7,46},
{911,30,1,23,37,24},
{701,30,19,15,26,16},
{1735,30,5,115,10,116},
{1373,28,19,47,10,48},
{985,30,15,24,25,25},
{745,30,23,15,25,16},
{1843,30,13,115,3,116},
{1455,28,2,46,29,47},
{1033,30,42,24,1,25},
{793,30,23,15,28,16},
{1955,30,17,115,0,0},
{1541,28,10,46,23,47},
{1115,30,10,24,35,25},
{845,30,19,15,35,16},
{2071,30,17,115,1,116},
{1631,28,14,46,21,47},
{1171,30,29,24,19,25},
{901,30,11,15,46,16},
{2191,30,13,115,6,116},
{1725,28,14,46,23,47},
{1231,30,44,24,7,25},
{961,30,59,16,1,17},
{2306,30,12,121,7,122},
{1812,28,12,47,26,48},
{1286,30,39,24,14,25},
{986,30,22,15,41,16},
{2434,30,6,121,14,122},
{1914,28,6,47,34,48},
{1354,30,46,24,10,25},
{1054,30,2,15,64,16},
{2566,30,17,122,4,123},
{1992,28,29,46,14,47},
{1426,30,49,24,10,25},
{1096,30,24,15,46,16},
{2702,30,4,122,18,123},
{2102,28,13,46,32,47},
{1502,30,48,24,14,25},
{1142,30,42,15,32,16},
{2812,30,20,117,4,118},
{2216,28,40,47,7,48},
{1582,30,43,24,22,25},
{1222,30,10,15,67,16},
{2956,30,19,118,6,119},
{2334,28,18,47,31,48},
{1666,30,34,24,34,25},
{1276,30,20,15,61,16}
};
//index for integer
//element fro exponent of alpha
const static int AntiLogTable[256]={
-1,0,1,25,2,50,26,198,3,223,51,238,27,104,199,75,
4,100,224,14,52,141,239,129,28,193,105,248,200,8,
76,113,5,138,101,47,225,36,15,33,53,147,142,218,240,
18,130,69,29,181,194,125,106,39,249,185,201,154,9,120,
77,228,114,166,6,191,139,98,102,221,48,253,226,152,37,
179,16,145,34,136,54,208,148,206,143,150,219,189,241,210,
19,92,131,56,70,64,30,66,182,163,195,72,126,110,107,58,40,84,
250,133,186,61,202,94,155,159,10,21,121,43,78,212,229,172,115,
243,167,87,7,112,192,247,140,128,99,13,103,74,222,237,49,197,
254,24,227,165,153,119,38,184,180,124,17,68,146,217,35,32,137,
46,55,63,209,91,149,188,207,205,144,135,151,178,220,252,190,97,
242,86,211,171,20,42,93,158,132,60,57,83,71,109,65,162,31,45,67,
216,183,123,164,118,196,23,73,236,127,12,111,246,108,161,59,82,41,
157,85,170,251,96,134,177,187,204,62,90,203,89,95,176,156,169,160,81,11,245,22,
235,122,117,44,215,79,174,213,233,230,231,173,232,116,214,244,234,168,80,88,175
};
//index for exponent of alpha
//element for integer
const static int LogTable[256]={
1,2,4,8,16,32,64,128,29,58,116,232,205,135,19,38,76,
152,45,90,180,117,234,201,143,3,6,12,24,48,96,192,157,
39,78,156,37,74,148,53,106,212,181,119,238,193,159,35,70,
140,5,10,20,40,80,160,93,186,105,210,185,111,222,161,95,
190,97,194,153,47,94,188,101,202,137,15,30,60,120,240,253,
231,211,187,107,214,177,127,254,225,223,163,91,182,113,226,217,
175,67,134,17,34,68,136,13,26,52,104,208,189,103,206,129,
31,62,124,248,237,199,147,59,118,236,197,151,51,102,204,133,
23,46,92,184,109,218,169,79,158,33,66,132,21,42,84,168,
77,154,41,82,164,85,170,73,146,57,114,228,213,183,115,230,
209,191,99,198,145,63,126,252,229,215,179,123,246,241,255,227,
219,171,75,150,49,98,196,149,55,110,220,165,87,174,65,130,
25,50,100,200,141,7,14,28,56,112,224,221,167,83,166,81,
162,89,178,121,242,249,239,195,155,43,86,172,69,138,9,18,
36,72,144,61,122,244,245,247,243,251,235,203,139,11,22,44,
88,176,125,250,233,207,131,27,54,108,216,173,71,142,1
};
//List of Versions and Required Remainder Bits
const static int RemainderBits[40]={
0,7,7,7,7,7,0,0,0,0,0,0,0,3,3,3,3,3,3,3,4,4,4,4,4,4,4,3,3,3,3,3,3,3,0,0,0,0,0,0
};
//Alignment Pattern Locations Table
const static int AlignmentPatternLocal[][7]={
{0,0,0,0,0,0,0},
{0,0,0,0,0,0,0},
{6,18,0,0,0,0,0},
{6,22,0,0,0,0,0},
{6,26,0,0,0,0,0},
{6,30,0,0,0,0,0},
{6,34,0,0,0,0,0},
{6,22,38,0,0,0,0},
{6,24,42,0,0,0,0},
{6,26,46,0,0,0,0},
{6,28,50,0,0,0,0},
{6,30,54,0,0,0,0},
{6,32,58,0,0,0,0},
{6,34,62,0,0,0,0},
{6,26,46,66,0,0,0},
{6,26,48,70,0,0,0},
{6,26,50,74,0,0,0},
{6,30,54,78,0,0,0},
{6,30,56,82,0,0,0},
{6,30,58,86,0,0,0},
{6,34,62,90,0,0,0},
{6,28,50,72,94,0,0},
{6,26,50,74,98,0,0},
{6,30,54,78,102,0,0},
{6,28,54,80,106,0,0},
{6,32,58,84,110,0,0},
{6,30,58,86,114,0,0},
{6,34,62,90,118,0,0},
{6,26,50,74,98,122,0},
{6,30,54,78,102,126,0},
{6,26,52,78,104,130,0},
{6,30,56,82,108,134,0},
{6,34,60,86,112,138,0},
{6,30,58,86,114,142,0},
{6,34,62,90,118,146,0},
{6,30,54,78,102,126,150},
{6,24,50,76,102,128,154},
{6,28,54,80,106,132,158},
{6,32,58,84,110,136,162},
{6,26,54,82,110,138,166},
{6,30,58,86,114,142,170}
};
// List of all Format Information Strings
const static string FormatInfoList[32]={
//index=level*7+Mask Pattern index
"111011111000100","111001011110011","111110110101010","111100010011101","110011000101111","110001100011000","110110001000001",
"110100101110110","101010000010010","101000100100101","101111001111100","101101101001011","100010111111001","100000011001110",
"100111110010111","100101010100000","011010101011111","011000001101000","011111100110001","011101000000110","010010010110100",
"010000110000011","010111011011010","010101111101101","001011010001001","001001110111110","001110011100111","001100111010000",
"000011101100010","000001001010101","000110100001100","000100000111011"
};
//Version Information Strings
const static string VersionInfoList[]={
"000111110010010100","001000010110111100","001001101010011001","001010010011010011",
"001011101111110110","001100011101100010","001101100001000111","001110011000001101",
"001111100100101000","010000101101111000","010001010001011101","010010101000010111",
"010011010100110010","010100100110100110","010101011010000011","010110100011001001",
"010111011111101100","011000111011000100","011001000111100001","011010111110101011",
"011011000010001110","011100110000011010","011101001100111111","011110110101110101",
"011111001001010000","100000100111010101","100001011011110000","100010100010111010",
"100011011110011111","100100101100001011","100101010000101110","100110101001100100",
"100111010101000001","101000110001101001"
};
//获取纠错码字
vector<int> getErrorCurrentWords(int* coefficient,int cofLen,int ErrorCurrentTableIndex);
class QREncode{
public:
QREncode(){}
~QREncode(){}
//编码单字节
Matrix<RGB> encoding(const string& encodeData);
//编码双字节
Matrix<RGB> encoding(const wstring& encodeWData);
string decoding(const string& outputPath);
int getSideLen() { return 21 + 4 * (version - 1); }
protected:
bool init();
string NumModeEncoding();
string AlpNumModeEncoding();
string ByteModeEncoding();
string KanjiModeEncoding();
void fillEncodeData(string& code);
void errorCurrentEncoding(string& code);
//得到编码的二维矩阵
Matrix<int> MatrixCode(const string& code);
void FormatAndVersionInfo(Matrix<int>& matrix, int maskIndex);
private:
string encodeData;
wstring encodeWData;
string _imageFilePath;
ErrorCorrectionLevel level{L};
DataType type{KanjiMode};
int version{0}; //matrix sideLen: 21+4*(version-1)
int charCount{0};
Matrix<RGB> *imgData{nullptr};
};
NAME_SPACE_END()
#endif //!_QR_ENCODE_
#include "QrEncode.h"
#include "Image.h"
#include "Matrix.h"
#include "Util.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
NAME_SPACE_START(myUtil)
#define BACKGROUND_COLOR RGB_WHITE
void print(string& code){
for(int i=0;i<code.size();i++){
if(i%8==0) cout<<" ";
cout<<code[i];
}
cout<<endl;
}
vector<function<bool(int,int)>> MaskFunctions={
[](int row,int column)->int{
return (row+column)%2==0;
},
[](int row,int column)->int{
return row%2==0;
},
[](int row,int column)->int{
return column%3==0;
},
[](int row,int column)->int{
return (row+column)%3==0;
},
[](int row,int column)->int{
return ((int)floor(row/2.0)+(int)floor(column/3.0))%2==0;
},
[](int row,int column)->int{
return ((row*column)%2+(row*column)%3)==0;
},
[](int row,int column)->int{
return ((row*column)%2+(row*column)%3)%2==0;
},
[](int row,int column)->int{
return ((row+column)%2+(row*column)%3)%2==0;
}
};
vector<Matrix<int>> getMaskList(const Matrix<int>& data){
vector<Matrix<int>> res;
res.resize(8);
for(int i=0;i<MaskFunctions.size();i++){
Matrix<int> temp(data);
for(int r=0;r<temp.row;r++){
for(int c=0;c<temp.col;c++){
if((temp.getValue(r, c)==5||temp.getValue(r, c)==6)&&MaskFunctions[i](r,c)){
temp.setValue(r, c, 6-temp.getValue(r, c));
}
else if(temp.getValue(r, c)==5||temp.getValue(r, c)==6){
temp.setValue(r, c, temp.getValue(r, c)-5);
}
}
}
res[i]=temp;
}
return res;
}
vector<int> Next(string pattern){
vector<int> next;
next.push_back(0); //next容器的首位必定为0
for (int i = 1, j = 0; i < pattern.length(); i++)
{
while (j > 0 && pattern[j] != pattern[i])
{
j = next[j - 1];
}
if (pattern[i] == pattern[j])
{
j++;
}
next.push_back(j);
}
return next;
}
int KMPCount(const string& target,const string& pattern){
int res=0;
auto next=Next(pattern);
for (int i = 0, j = 0; i < target.length(); i++)
{
while (j > 0 && target[i] != pattern[j])
{
j = next[j - 1];
}
if (target[i] == pattern[j])
{
j++;
}
if (j == pattern.length())
{
res++;
j = next[j - 1];
}
}
return res;
}
// The first rule gives the QR code a penalty for each group of five or more same-colored modules in a row (or column).
int Rule1(const Matrix<int>& data){
// row
int sum=0;
for(int i=0;i<data.row;i++){
int ContinueCount=1;
for(int j=1;j<data.col;j++){
if(data.getValue(i, j)==data.getValue(i, j-1)) ContinueCount++;
else if(ContinueCount>=5){
sum+=ContinueCount-3;
ContinueCount=1;
}
else{
ContinueCount=1;
}
}
if(ContinueCount>=5) sum+=ContinueCount-3;
}
// col
for(int i=0;i<data.col;i++){
int ContinueCount=1;
for(int j=1;j<data.row;j++){
if(data.getValue(j, i)==data.getValue(j-1, i)) ContinueCount++;
else if(ContinueCount>=5){
sum+=ContinueCount-3;
ContinueCount=1;
}
else{
ContinueCount=1;
}
}
if(ContinueCount>=5) sum+=ContinueCount-3;
}
return sum;
}
// The second rule gives the QR code a penalty for each 2x2 area of same-colored modules in the matrix.
int Rule2(const Matrix<int>& data){
int sum=0;
for(int r=0;r<data.row-1;r++){
for(int c=0;c<data.col-1;c++){
if(data.getValue(r, c)==data.getValue(r, c+1)&&
data.getValue(r, c+1)==data.getValue(r+1, c)&&
data.getValue(r+1, c)==data.getValue(r+1, c+1)){
sum+=3;
}
}
}
return sum;
}
// The third rule gives the QR code a large penalty if there are patterns that look similar to the finder patterns.
int Rule3(const Matrix<int>& data){
int sum=0;
//row
for(int r=0;r<data.row;r++){
string temp="";
for(int c=0;c<data.col;c++){
temp.append(string(1,'0'+data.getValue(r, c)));
}
sum+=40*KMPCount(temp, "10111010000");
sum+=40*KMPCount(temp, "00001011101");
}
//col
for(int c=0;c<data.col;c++){
string temp="";
for(int r=0;r<data.row;r++){
temp.append(string(1,'0'+data.getValue(r, c)));
}
sum+=40*KMPCount(temp, "10111010000");
sum+=40*KMPCount(temp, "00001011101");
}
return sum;
}
// The fourth rule gives the QR code a penalty if more than half of the modules are dark or light, with a larger penalty for a larger difference.
int Rule4(const Matrix<int>& data){
int sum=0,darkCount=0,total=data.row*data.col;
for(int r=0;r<data.row;r++){
for(int c=0;c<data.col;c++){
if(data.getValue(r, c)==1) darkCount++;
}
}
int number=ceil((1.0*darkCount)/total);
int bigTemp=number%10>5?(10-number%10):(5-number%10);
int smallTemp=number%10>5?(number%10-5):number%10;
int big=abs(number+bigTemp-50)/5,small=abs(number-smallTemp-50)/5;
sum=min(big,small)*10;
return sum;
}
int Evaluate(const Matrix<int>& data){
int sum=0;
sum+=Rule1(data);
sum+=Rule2(data);
sum+=Rule3(data);
sum+=Rule4(data);
return sum;
}
int* getErrorCurrentVersion(ErrorCorrectionLevel level,int maskIndex){
int LevelBitSequences[]={1,0,3,2};
int cur=LevelBitSequences[(int)level],curMaskIndex=maskIndex;
int polynomial[11]={1,0,1,0,0,1,1,0,1,1,1};
int maskPattern[]={1,0,1,0,1,0,0,0,0,0,1,0,0,1,0};
int *code=new int[15];
memset(code, 0, sizeof(int)*15);
for(int i=1;i>=0;i--){
code[i]=cur%2;
cur>>=1;
}
for(int i=4;i>1;i--){
code[i]=curMaskIndex%2;
curMaskIndex>>=1;
}
int pos=0;
while(pos<5){
while(code[pos]==0) pos++;
for(int i=pos;i<15;i++){
int temp=polynomial[i-pos];
if(i-pos>10) temp=0;
code[i]=code[i]^temp;
}
while(code[pos]==0) pos++;
}
cur=LevelBitSequences[(int)level],curMaskIndex=maskIndex;
for(int i=1;i>=0;i--){
code[i]=cur%2;
cur>>=1;
}
for(int i=4;i>1;i--){
code[i]=curMaskIndex%2;
curMaskIndex>>=1;
}
for(int i=0;i<15;i++){
code[i]=code[i]^maskPattern[i];
}
return code;
}
//获取纠错码字
vector<int> getErrorCurrentWords(int* coefficient,int cofLen,int ErrorCurrentTableIndex){
int polynomialLen=ErrorCurrentTable[ErrorCurrentTableIndex][1]+1;
int* coeff=new int[cofLen + polynomialLen - 1];
memset(coeff, 0, sizeof(int)*(cofLen + polynomialLen - 1));
memcpy_s(coeff, sizeof(int)*cofLen, coefficient, sizeof(int)*cofLen);
for(int i=0;i<cofLen;i++){
// 1.Multiply the Generator Polynomial by the Lead Term of the XOR result from the previous step
// 2.XOR the result with the result from step 14b
int exponent=AntiLogTable[coeff[i]];
for(int j=0;j<max(cofLen-i,polynomialLen);j++){
int cof=LogTable[(exponent+GeneratorPolynomialCoff[polynomialLen-8][j])%255];
if(j>=polynomialLen) cof=0;
coeff[i+j] = coeff[i+j] ^ cof;
}
}
vector<int> res(polynomialLen-1,0);
for(int i=0;i<polynomialLen-1;i++) res[i]=coeff[cofLen+i];
delete [] coeff;
return res;
}
Matrix<RGB> QREncode::encoding(const string &encodeData){
this->encodeData=encodeData;
if(!init()) return Matrix<RGB>();
imgData=new Matrix<RGB>(getSideLen(),getSideLen(),BACKGROUND_COLOR);
// char encoding
string code=bitset<MODE_INDICATOR_BIT_LENGTH>(ModeIndicator[(int)type]).to_string();
code.append(bitset<16>(encodeData.size()).to_string().substr(16-charCount));
if(type==DataType::NumMode) code.append(NumModeEncoding());
else if(type==DataType::AlpNumMode) code.append(AlpNumModeEncoding());
else if(type==DataType::ByteMode) code.append(ByteModeEncoding());
else if(type==DataType::KanjiMode) code.append(KanjiModeEncoding());
fillEncodeData(code);
// print(code);
errorCurrentEncoding(code);
// cout<
// print(code);
Matrix<int> source = MatrixCode(code);
imgData->setValByArray(source, vector<RGB>{RGB_BLACK}, 0, 0);
return imgData==nullptr?Matrix<RGB>():*imgData;
}
Matrix<RGB> QREncode::encoding(const wstring& encodeWData){
this->encodeWData=encodeWData;
if(!init()) return Matrix<RGB>();
imgData=new Matrix<RGB>(getSideLen(),getSideLen(),RGB_WHITE);
return imgData==nullptr?Matrix<RGB>():*imgData;
}
//默认找最小的版本
bool QREncode::init(){
int NumMode=0,AlpNumMode=0,ByteMode=0;
for_each(encodeData.begin(), encodeData.end(), [&](char ch){
if(ch<='9'&&ch>='0') NumMode++;
else if((ch<='z'&&ch>='a')) ByteMode++;
else if(ch<='Z'&&ch>='A') AlpNumMode++;
});
if(ByteMode!=0) type=DataType::ByteMode;
else if(AlpNumMode!=0) type=DataType::AlpNumMode;
else if(NumMode!=0) type=DataType::NumMode;
else type=DataType::KanjiMode;
int len=encodeData.size();
if (len > 7089 && type == DataType::NumMode ||
len > 4296 && type == DataType::AlpNumMode ||
len > 2953 && type == DataType::ByteMode ||
len > 1817 && type == DataType::KanjiMode)
return false;
for(int i=0;i<VERSION_COUNT;i++){
for(int j=3;j>=0;j--){
if(CharCapTable[i][j][(int)type]>len){
version=i+1;
level=(ErrorCorrectionLevel)j;
if(version>=1&&version<=9)
charCount=CharCountIndicator[0][(int)type];
else if(version>=10&&version<=26)
charCount=CharCountIndicator[1][(int)type];
else if(version>=27&&version<=40)
charCount=CharCountIndicator[2][(int)type];
return true;
}
}
}
return false;
}
string QREncode::NumModeEncoding(){
string res="";
//分为3个一组,最后会出现2个一组或者一个一组的
//都转为10进制,然后3位的转为10位二进制,两位转为7位,一位转为4位
for (int i = 0; i < encodeData.size(); i += 3) {
int t=0, bitCount=4;
if (i < encodeData.size()) t += encodeData[i] - '0';
if (i + 1 < encodeData.size()){
t = t * 10 + encodeData[i + 1] - '0';
bitCount=7;
}
if (i + 2 < encodeData.size()){
t = t * 10 + encodeData[i + 2] - '0';
bitCount=10;
}
if(bitCount==4) res.append(bitset<4>(t).to_string());
else if(bitCount==7) res.append(bitset<7>(t).to_string());
else if(bitCount==10) res.append(bitset<10>(t).to_string());
}
return res;
}
string QREncode::AlpNumModeEncoding(){
string res="";
//两位转11位二进制 一位转6位二进制
for(int i=0;i<encodeData.size();i+=2){
int t=0, bitCount=6;
if(i<encodeData.size())
t = AlpValMappingTable[encodeData[i]];
if(i+1<encodeData.size()){
t = t*45 + AlpValMappingTable[encodeData[i+1]];
bitCount=11;
}
if(bitCount==6) res.append(bitset<6>(t).to_string());
else if(bitCount==11) res.append(bitset<11>(t).to_string());
}
return res;
}
string QREncode::ByteModeEncoding(){
// 1.Convert to ISO 8859-1 or UTF-8
// 2.Split the String into 8-bit Bytes
// 3.Convert Each Byte into Binary
// 4.Next: Finish the Data Encoding Step
string res="";
for(int i=0;i<encodeData.size();i++){
res.append(bitset<8>(encodeData[i]).to_string());
}
return res;
}
string QREncode::KanjiModeEncoding(){
// 1.Only for Double-Byte Shift JIS Characters
// 2.Convert to Bytes
// 3.Encode the Bytes with Kanji Mode
// For characters whose bytes are in the range 0x8140 to 0x9FFC
// for example: 0x89D7
// 1. 0x89D7 - 0x8140 = 0x0897
// 2. (0x08 * 0xC0) + 0x97 = (0x600) + 0x97 = 0x697
// 3. 0x697 -> binary(13bit)
// For characters whose bytes are in the range 0xE040 to 0xEBBF
// for example: 0xE4AA
// 1. 0xE4AA - 0xC140 = 0x236A
// 2. (0x23 * 0xC0) + 0x6A = (0x1A40) + 0x6A = 0x1AAA
// 3. 0x1AAA -> binary(13bit)
// 4.Put the 13-bit Binary Numbers Together
// 5.Next: Finish the Data Encoding Step
string res="";
for(int i=0;i<encodeWData.size();i++){
}
return res;
}
void QREncode::fillEncodeData(string& code){
// 1. Determine the Required Number of Bits for this QR Code
// 2. Add a Terminator of 0s if Necessary
// 3. Add More 0s to Make the Length a Multiple of 8
// 4. Add Pad Bytes if the String is Still too Short
// 11101100 00010001//两字节循环填入
// code string bit length
int maxLen=ErrorCurrentTable[(version-1)*4+(int)level][0]*8;
int diff=maxLen-code.size();
if(diff<0) return;
// Add a Terminator
if(diff>4) code.append("0000");
else if(diff<=4) code.append(string(diff,'0'));
// Add More 0s to Make the Length a Multiple of 8
int eightDiff = 8-code.size()%8;
code.append(string(eightDiff,'0'));
// Add Pad Bytes
if(maxLen-code.size()<8) return;
int n=(maxLen-code.size())/8;
for(int i=0;i<n;i++){
if(i%2==0) code.append("11101100");
else code.append("00010001");
}
}
void QREncode::errorCurrentEncoding(string& code){
// Step 1: Break Data Codewords into Blocks if Necessary
// Step 2: Understand Polynomial Long Division
// Step 3: Understand The Galois Field
// Step 4: Understand Galois Field Arithmetic
// Step 5: Generate Powers of 2 using Byte-Wise Modulo 100011101
// Step 6: Understand Multiplication with Logs and Antilogs
// Step 7: Understanding The Generator Polynomial
// Step 8: Generating Error Correction Codewords
// Step 9: Divide the Message Polynomial by the Generator Polynomial
int row=(version-1)*4+(int)level,codePos=0;
int groupCount = ErrorCurrentTable[row][4]==0?1:2;
int*** group=new int**[groupCount];
vector<vector<int>> currentWords;
int maxCodeWordsLen=0,maxCurrentCodeWordsLen=0;
for(int i=0;i<groupCount;i++){
int blockCol=2,codeWordsCol=3;
if(i==1){
blockCol=4;
codeWordsCol=5;
}
group[i]=new int*[ErrorCurrentTable[row][blockCol]];
for(int blockOfGroup=0;blockOfGroup<ErrorCurrentTable[row][blockCol];blockOfGroup++){
group[i][blockOfGroup]=new int[ErrorCurrentTable[row][codeWordsCol]];
maxCodeWordsLen=max(maxCodeWordsLen,ErrorCurrentTable[row][codeWordsCol]);
for(int blocks=0;blocks<ErrorCurrentTable[row][codeWordsCol]&&codePos<=code.size();blocks++){
int t=0;
for(int k=0;k<8;k++){
t<<=1;
t+=code[codePos+k]-'0';
}
group[i][blockOfGroup][blocks]=t;
codePos+=8;
// cout<
}
// cout<
vector<int> CurrentCodeWords = getErrorCurrentWords(group[i][blockOfGroup], ErrorCurrentTable[row][codeWordsCol],row);
currentWords.push_back(CurrentCodeWords);
maxCurrentCodeWordsLen=max(maxCurrentCodeWordsLen,(int)CurrentCodeWords.size());
}
}
// cout<
// for(auto items : currentWords){
// for(int item : items){
// cout<-
// }
// cout<
// }
// cout<
//Structure Final Message
code = "";
//Interleave the Blocks
for(int i=0;i<maxCodeWordsLen;i++){
for(int j=0;j<groupCount;j++){
int blockCol=2,codeWordsCol=3;
if(j==1){
blockCol=4;
codeWordsCol=5;
}
for(int k=0;k<ErrorCurrentTable[row][blockCol];k++){
int dataLen=ErrorCurrentTable[row][codeWordsCol];
if(i>=dataLen) continue;
code.append(bitset<8>(group[j][k][i]).to_string());
// cout<
}
}
}
// cout<
//Interleave the Error Correction Codewords
for(int i=0;i<maxCurrentCodeWordsLen;i++){
for(int j=0;j<currentWords.size();j++){
if(i>=currentWords[j].size()) continue;
// cout<<"("<
code.append(bitset<8>(currentWords[j][i]).to_string());
// cout<
}
}
// cout<
//Add Remainder Bits
code.append(string(RemainderBits[version-1],'0'));
}
vector<vector<int>> FinderPatterns={
{1,1,1,1,1,1,1},
{1,2,2,2,2,2,1},
{1,2,1,1,1,2,1},
{1,2,1,1,1,2,1},
{1,2,1,1,1,2,1},
{1,2,2,2,2,2,1},
{1,1,1,1,1,1,1}
};
vector<vector<int>> AlignmentPatterns={
{1,1,1,1,1},
{1,2,2,2,1},
{1,2,1,2,1},
{1,2,2,2,1},
{1,1,1,1,1}
};
Matrix<int> QREncode::MatrixCode(const string& code){
Matrix<int> res(getSideLen(),getSideLen(),-1);
Matrix<int> finder(7,7,FinderPatterns),
alignment(5,5,AlignmentPatterns);
vector<int> val{1,0};//默认是白色,1为黑色
int ReserveArea=1;
// Step 1: Add the Finder Patterns
res.setValByArray(finder, val, 0, 0);
res.setValByArray(finder, val, 0, getSideLen()-7);
res.setValByArray(finder, val, getSideLen()-7, 0);
// Step 2: Add the Separators
for(int i=0;i<8;i++){
//左上
res.setValue(7, i, 0);
res.setValue(i, 7, 0);
//左下
res.setValue(getSideLen()-1-i, 7, 0);
res.setValue(getSideLen()-8, i, 0);
//右上
res.setValue(7, getSideLen()-1-i, 0);
res.setValue(i, getSideLen()-8, 0);
}
// Step 3: Add the Alignment Patterns
for(int i=0;i<7&&version!=1;i++){
for(int j=0;j<7;j++){
if(AlignmentPatternLocal[version][i]==0||
AlignmentPatternLocal[version][j]==0) continue;
int row=AlignmentPatternLocal[version][i],
col=AlignmentPatternLocal[version][j];
//判断是否与finder重合
if((row-2<8&&col-2<8)||
(row-2<8&&col+2>getSideLen()-9)||
(row+2>getSideLen()-9&&col-2<8)) continue;
res.setValByArray(alignment, val, row-2, col-2);
// cout<
}
}
// Step 4: Add the Timing Patterns
for(int i=8;i<getSideLen()-8;i+=2){
if(res.getValue(i, 6)==-1) res.setValue(i, 6, 1);
if(res.getValue(6, i)==-1) res.setValue(6, i, 1);
if(res.getValue(i+1, 6)==-1) res.setValue(i+1, 6, 0);
if(res.getValue(6, i+1)==-1) res.setValue(6, i+1, 0);
}
// Step 5: Add the Dark Module and Reserved Areas
// Dark Module
res.setValue(4*version+9, 8, 1);
// Reserve the Format Information Area set value 2
for(int i=0;i<9;i++){
//左上
if(res.getValue(8, i)==-1) res.setValue(8, i, 2);
if(res.getValue(i, 8)==-1) res.setValue(i, 8, 2);
//左下
if(res.getValue(getSideLen()-1-i, 8)==-1&&i<7) res.setValue(getSideLen()-1-i, 8, 2);
//右上
if(res.getValue(8, getSideLen()-1-i)==-1&&i<8) res.setValue(8, getSideLen()-1-i, 2);
}
// QR codes versions 7 and larger must contain two areas where version information bits are placed. Each of area 6×3. set value 3
for(int i=0;i<3&&version>=7;i++){
for(int j=0;j<6;j++){
res.setValue(getSideLen()-9-i, j, 3);
res.setValue(j, getSideLen()-9-i, 3);
}
}
// Step 6: Place the Data Bits
int r=getSideLen()-1,c=getSideLen()-1,codePos=0;
bool upWard=true,right=true;
while(r>=0&&r<getSideLen()&&c>=0&&c<getSideLen()&&codePos<code.size()){
// cout<<"("<
if(res.getValue(r, c)==-1){
res.setValue(r, c, code[codePos++]-'0'+5);//此处赋值将数据值赋值为5和6,目的是使后面mask方便
// else
// res.setValue(r, c, 5);
}
if(upWard){
if(right) {right=!right; c-=1;}
else {
right=!right;
if (r-1<0) {c-=1;r=0;right=true; upWard=!upWard;}
else{ c+=1; r-=1;}
}
}
else{
if(c==6) {c=5; right=true;}
if(right) {right=!right; c-=1;}
else {
right=!right;
if(r+1>=getSideLen()){c-=1;r=getSideLen()-1;right=true; upWard=!upWard;}
else {c+=1; r+=1; }
}
}
}
int a=code.size();
// mask evaluate
auto dataMatrix=getMaskList(res);
int minScore=INT_MAX, minScorePos=0;
for(int i=0;i<dataMatrix.size();i++){
//设置保留位
FormatAndVersionInfo(dataMatrix[i],i);
#ifdef DEBUG
Matrix<RGB> rgb(getSideLen()+8,getSideLen()+8,BACKGROUND_COLOR);
rgb.setValByArray(dataMatrix[i], vector<RGB>{RGB_BLACK}, 4, 4);
BMPData bmp(AmplifyMatrix<RGB>(rgb,AMPLIFY_LEVEL),rgb.col*AMPLIFY_LEVEL,rgb.row*AMPLIFY_LEVEL,true);
bmp.GrayEncoder();
bmp.saveBMP("qr"+string(1,'1'+i)+".bmp");
#endif
// cout<
int t=Evaluate(dataMatrix[i]);
if(t<minScore){
minScore=t;
minScorePos=i;
}
// cout<
}
// cout<
res=dataMatrix[minScorePos];
return res;
}
void QREncode::FormatAndVersionInfo(Matrix<int>& matrix, int maskIndex){
// Format String
// int *CurrentCode=getErrorCurrentVersion(level, maskIndex);
string CurrentCode=FormatInfoList[((int)level)*8+maskIndex];
for(int i=0;i<7;i++){
int t=0;
if(i>=6) t=1;
matrix.setValue(8, i+t, CurrentCode[i]-'0');
// left down
matrix.setValue(getSideLen()-1-i, 8, CurrentCode[i]-'0');
}
for(int i=0;i<8;i++){
// right up
matrix.setValue(8, getSideLen()-1-i, CurrentCode[14-i]-'0');
int t=0;
if(i>=6) t=1;
matrix.setValue(i+t, 8, CurrentCode[14-i]-'0');
}
// Version Information
if(version>=7){
string CurrentInfo=VersionInfoList[version-7];
int pos=0;
for(int i=0;i<3;i++){
for(int j=0;j<6;j++){
matrix.setValue(getSideLen()-11+i, j, CurrentInfo[pos]-'0');
matrix.setValue(j, getSideLen()-11+i, CurrentInfo[pos++]-'0');
}
}
}
}
NAME_SPACE_END()
#include "Image.h"
#include "QrEncode.h"
#include
#include
#include
#include
#define _CRT_SECURE_NO_WARNINGS
#include
#include "Matrix.h"
using namespace std;
using namespace myUtil;
int main(int argc,char * argv[]){
if(argc>3){
cout<<"param error\n";
return 0;
}
if(string(argv[1])=="--help"){
cout<<"[content] [resultName] out resultName.bmp QRcode\n\n";
return 0;
}
QREncode qr;
Matrix<RGB> rgb=qr.encoding(argv[1]);
// Matrix rgb=qr.encoding("01234567890123456789012345678901234567890");
// Matrix rgb=qr.encoding("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
BMPData bmp(AmplifyMatrix<RGB>(rgb,AMPLIFY_LEVEL),rgb.col*AMPLIFY_LEVEL,rgb.row*AMPLIFY_LEVEL,true);
bmp.GrayEncoder();
bmp.saveBMP(string(argv[2])+".bmp");
return 0;
}