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;
}

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咩~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值