C++实现编写二维码的示例代码
二维码图片好像违规了,直接给链接吧网址链接
如果你扫了这个二维码就会得到一个网址,该网址是我写代码的参考,该网站讲述了如何编写一个二维码,很详细,我没有实现汉字的编码,实现了三种模式的编码,这个网址给的很详细,我也就不写了,如果再写就跟抄人家的没区别了。
下面给出生成的代码,其中有一些我自己写的工具,我会做出说明,如果不想看人家网站的话,代码中也有注释。
1.Matrix这个模板类是我做的一个二维数组的套壳,里面用的是动态申请空间,析构时自动释放
2.每个静态的值都是按照顺序来的,一般我都给了对应关系和索引如何计算
3.此类计算出来的二维码,在版本特别高时,我用微信没识别出来,没特别仔细的测试,300个2能识别(用直接跳转12306公众号了,不知道为啥),3000个2二维码已经密到有点看不清了(这个用微信扫没反应)
4.图像是使用我写的另外一个类来生成位图的,没用JPEG是因为转换没写
5.宽字节编码没写实现
6.没有解析二维码的实现
7.源代码在此这个啥都有
环境&工具
Windows11 gcc 8.1.0 vscode cmake
QrEncode.h
#pragma once #include <cmath> #include <functional> #include <stdint.h> #include <string> #include <vector> #include <map> #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_
QrEncode.cpp
#include "QrEncode.h" #include "Image.h" #include "Matrix.h" #include "Util.h" #include <algorithm> #include <bitset> #include <iostream> #include <list> #include <stack> #include <cstdlib> #include <cstring> #include <string> #include <vector> 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<<code<<endl; // 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<<t<<" "; } // cout<<endl; vector<int> CurrentCodeWords = getErrorCurrentWords(group[i][blockOfGroup], ErrorCurrentTable[row][codeWordsCol],row); currentWords.push_back(CurrentCodeWords); maxCurrentCodeWordsLen=max(maxCurrentCodeWordsLen,(int)CurrentCodeWords.size()); } } // cout<<endl; // for(auto items : currentWords){ // for(int item : items){ // cout<<item<<" "; // } // cout<<endl; // } // cout<<endl; //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<<group[j][k][i]<<" "; } } } // cout<<endl<<endl; //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<<"("<<j<<","<<i<<") "; code.append(bitset<8>(currentWords[j][i]).to_string()); // cout<<currentWords[j][i]<<" "; } } // cout<<endl; //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<<res<<endl; } } // 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<<"("<<r<<","<<c<<") "; 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<<dataMatrix[i]<<endl; int t=Evaluate(dataMatrix[i]); if(t<minScore){ minScore=t; minScorePos=i; } // cout<<t<<" "; } // cout<<endl; 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()
QrCode_test.cpp
#include "Image.h" #include "QrEncode.h" #include <cstdint> #include <fstream> #include <list> #include <string> #define _CRT_SECURE_NO_WARNINGS #include <iostream> #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> rgb=qr.encoding("01234567890123456789012345678901234567890"); // Matrix<RGB> 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; }
以上就是C++实现编写二维码的示例代码的详细内容,更多关于C++编写二维码的资料请关注脚本之家其它相关文章!
最新评论