QR.h:
//==============================================================================
// Copyright (C) 2019 王小康. All rights reserved.
//
// 作者: 王小康
// 描述: QR编码器
// 日期: 2019-07-19
//
//==============================================================================
#ifndef _QR_ENCODER_H_
#define _QR_ENCODER_H_
#define QR_LEVEL_L 0 //纠错等级L
#define QR_LEVEL_M 1 //纠错等级M
#define QR_LEVEL_Q 2 //纠错等级Q
#define QR_LEVEL_H 3 //纠错等级H
#ifdef __cplusplus
extern "C" {
#endif
// 扫描数据,选择最合适的二维码尺寸,返回二维码矩阵的边长。
// 例如如果最合适的version是3,那么返回29。
// 矩阵的边长可以用来分配内存,例如29的话,分配 29*29+1 = 842 字节的内存。
// 如果能确保足够的内存的话,不需要调用此接口。
// 所需最大内存是 177*177+1 = 31330 字节。
// 数据太多返回负值。
int QR_getSize(unsigned char *data, unsigned int dataSize, unsigned int level);
// QR编码,输出二维码矩阵,返回二维码矩阵的边长。
// 数据太多或内部 malloc() 失败返回负值。
// 二维码矩阵用字符串表示,字符总个数 = 边长 x 边长,尾部以 0 结束。
// 假设矩阵边长是5,字符串是 "0100110001110000101010101",那么矩阵如下:
// 0 1 0 0 1
// 1 0 0 0 1
// 1 1 0 0 0
// 0 1 0 1 0
// 1 0 1 0 1
// 字符'0'表示白点,字符'1'表示黑点。
// outBuffer是输出地址,可以借助 QR_getSize() 来为之分配输出内存。
int QR_encode(char *outBuffer, unsigned char *data, unsigned int dataSize, unsigned int level);
#ifdef __cplusplus
}
#endif
#endif
QR.c:
//==============================================================================
// Copyright (C) 2019 王小康. All rights reserved.
//
// 作者: 王小康
// 描述: QR编码器
// 日期: 2019-07-19
//
//==============================================================================
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "QR.h"
#define ENCODE_MODE_NUME 0x01 //数字模式
#define ENCODE_MODE_ALPH 0x02 //字符模式
#define ENCODE_MODE_BYTE 0x04 //字节模式
// 各个版本各个纠错等级的容量表,单位是bit。41x4x2 = 328 字节。
static unsigned short capacityTable[41][4] = {
{0, 0, 0, 0}, //占位
{152, 128, 104, 72}, //v1
{272, 224, 176, 128}, //v2
{440, 352, 272, 208}, //v3
{640, 512, 384, 288}, //v4
{864, 688, 496, 368}, //v5
{1088, 864, 608, 480}, //v6
{1248, 992, 704, 528}, //v7
{1552, 1232, 880, 688}, //v8
{1856, 1456, 1056, 800}, //v9
{2192, 1728, 1232, 976}, //v10
{2592, 2032, 1440, 1120}, //v11
{2960, 2320, 1648, 1264}, //v12
{3424, 2672, 1952, 1440}, //v13
{3688, 2920, 2088, 1576}, //v14
{4184, 3320, 2360, 1784}, //v15
{4712, 3624, 2600, 2024}, //v16
{5176, 4056, 2936, 2264}, //v17
{5768, 4504, 3176, 2504}, //v18
{6360, 5016, 3560, 2728}, //v19
{6888, 5352, 3880, 3080}, //v20
{7456, 5712, 4096, 3248}, //v21
{8048, 6256, 4544, 3536}, //v22
{8752, 6880, 4912, 3712}, //v23
{9392, 7312, 5312, 4112}, //v24
{10208, 8000, 5744, 4304}, //v25
{10960, 8496, 6032, 4768}, //v26
{11744, 9024, 6464, 5024}, //v27
{12248, 9544, 6968, 5288}, //v28
{13048, 10136, 7288, 5608}, //v29
{13880, 10984, 7880, 5960}, //v30
{14744, 11640, 8264, 6344}, //v31
{15640, 12328, 8920, 6760}, //v32
{16568, 13048, 9368, 7208}, //v33
{17528, 13800, 9848, 7688}, //v34
{18448, 14496, 10288, 7888}, //v35
{19472, 15312, 10832, 8432}, //v36
{20528, 15936, 11408, 8768}, //v37
{21616, 16816, 12016, 9136}, //v38
{22496, 17728, 12656, 9776}, //v39
{23648, 18672, 13328, 10208} //v40
};
// 字符编码模式索引表。60字节。
static unsigned char alphanumericModeIndexTable[60] = {
36, 45, 46, 47, 37, 38, 48, 49, 50, 51, // SP ! " # $ % & ' ( )
39, 40, 52, 41, 42, 43, 0, 1, 2, 3, // * + , - . / 0 1 2 3
4, 5, 6, 7, 8, 9, 44, 53, 54, 55, // 4 5 6 7 8 9 : ; < =
56, 57, 58, 10, 11, 12, 13, 14, 15, 16, // > ? @ A B C D E F G
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, // H I J K L M N O P Q
27, 28, 29, 30, 31, 32, 33, 34, 35, 59 // R S T U V W X Y Z [
};
typedef struct {
unsigned char ECCodewordsPerBlock[4]; //每个块中纠错码字的个数
unsigned char BlocksInGroup1[4]; //第1个分组中的块数
unsigned char DataCodewordsPerBlockInGroup1[4]; //第1个分组中每个块中数据码字的个数
unsigned char BlocksInGroup2[4]; //第2个分组中的块数
unsigned char DataCodewordsPerBlockInGroup2[4]; //第2个分组中每个块中数据码字的个数
} BLOCK_INFO;
// 各个版本各个纠错等级的分块信息表。41x5x4 = 820 字节。
static BLOCK_INFO blockInfoTable[41] = {
{{ 0, 0, 0, 0}, { 0, 0, 0, 0}, { 0, 0, 0, 0}, { 0, 0, 0, 0}, { 0, 0, 0, 0}}, //占位
{{ 7,10,13,17}, { 1, 1, 1, 1}, { 19, 16, 13, 9}, { 0, 0, 0, 0}, { 0, 0, 0, 0}}, //V1
{{10,16,22,28}, { 1, 1, 1, 1}, { 34, 28, 22, 16}, { 0, 0, 0, 0}, { 0, 0, 0, 0}}, //V2
{{15,26,18,22}, { 1, 1, 2, 2}, { 55, 44, 17, 13}, { 0, 0, 0, 0}, { 0, 0, 0, 0}}, //V3
{{20,18,26,16}, { 1, 2, 2, 4}, { 80, 32, 24, 9}, { 0, 0, 0, 0}, { 0, 0, 0, 0}}, //V4
{{26,24,18,22}, { 1, 2, 2, 2}, {108, 43, 15, 11}, { 0, 0, 2, 2}, { 0, 0, 16, 12}}, //V5
{{18,16,24,28}, { 2, 4, 4, 4}, { 68, 27, 19, 15}, { 0, 0, 0, 0}, { 0, 0, 0, 0}}, //V6
{{20,18,18,26}, { 2, 4, 2, 4}, { 78, 31, 14, 13}, { 0, 0, 4, 1}, { 0, 0, 15, 14}}, //V7
{{24,22,22,26}, { 2, 2, 4, 4}, { 97, 38, 18, 14}, { 0, 2, 2, 2}, { 0, 39, 19, 15}}, //V8
{{30,22,20,24}, { 2, 3, 4, 4}, {116, 36, 16, 12}, { 0, 2, 4, 4}, { 0, 37, 17, 13}}, //V9
{{18,26,24,28}, { 2, 4, 6, 6}, { 68, 43, 19, 15}, { 2, 1, 2, 2}, { 69, 44, 20, 16}}, //V10
{{20,30,28,24}, { 4, 1, 4, 3}, { 81, 50, 22, 12}, { 0, 4, 4, 8}, { 0, 51, 23, 13}}, //V11
{{24,22,26,28}, { 2, 6, 4, 7}, { 92, 36, 20, 14}, { 2, 2, 6, 4}, { 93, 37, 21, 15}}, //V12
{{26,22,24,22}, { 4, 8, 8,12}, {107, 37, 20, 11}, { 0, 1, 4, 4}, { 0, 38, 21, 12}}, //V13
{{30,24,20,24}, { 3, 4,11,11}, {115, 40, 16, 12}, { 1, 5, 5, 5}, {116, 41, 17, 13}}, //V14
{{22,24,30,24}, { 5, 5, 5,11}, { 87, 41, 24, 12}, { 1, 5, 7, 7}, { 88, 42, 25, 13}}, //V15
{{24,28,24,30}, { 5, 7,15, 3}, { 98, 45, 19, 15}, { 1, 3, 2,13}, { 99, 46, 20, 16}}, //V16
{{28,28,28,28}, { 1,10, 1, 2}, {107, 46, 22, 14}, { 5, 1,15,17}, {108, 47, 23, 15}}, //V17
{{30,26,28,28}, { 5, 9,17, 2}, {120, 43, 22, 14}, { 1, 4, 1,19}, {121, 44, 23, 15}}, //V18
{{28,26,26,26}, { 3, 3,17, 9}, {113, 44, 21, 13}, { 4, 11,4,16}, {114, 45, 22, 14}}, //V19
{{28,26,30,28}, { 3, 3,15,15}, {107, 41, 24, 15}, { 5, 13,5,10}, {108, 42, 25, 16}}, //V20
{{28,26,28,30}, { 4,17,17,19}, {116, 42, 22, 16}, { 4, 0, 6, 6}, {117, 0, 23, 17}}, //V21
{{28,28,30,24}, { 2,17, 7,34}, {111, 46, 24, 13}, { 7, 0,16, 0}, {112, 0, 25, 0}}, //V22
{{30,28,30,30}, { 4, 4,11,16}, {121, 47, 24, 15}, { 5,14,14,14}, {122, 48, 25, 16}}, //V23
{{30,28,30,30}, { 6, 6,11,30}, {117, 45, 24, 16}, { 4,14,16, 2}, {118, 46, 25, 17}}, //V24
{{26,28,30,30}, { 8, 8, 7,22}, {106, 47, 24, 15}, { 4,13,22,13}, {107, 48, 25, 16}}, //V25
{{28,28,28,30}, {10,19,28,33}, {114, 46, 22, 16}, { 2, 4, 6, 4}, {115, 47, 23, 17}}, //V26
{{30,28,30,30}, { 8,22, 8,12}, {122, 45, 23, 15}, { 4, 3,26,28}, {123, 46, 24, 16}}, //V27
{{30,28,30,30}, { 3, 3, 4,11}, {117, 45, 24, 15}, {10,23,31,31}, {118, 46, 25, 16}}, //V28
{{30,28,30,30}, { 7,21, 1,19}, {116, 45, 23, 15}, { 7, 7,37,26}, {117, 46, 24, 16}}, //V29
{{30,28,30,30}, { 5,19,15,23}, {115, 47, 24, 15}, {10,10,25,25}, {116, 48, 25, 16}}, //V30
{{30,28,30,30}, {13, 2,42,23}, {115, 46, 24, 15}, { 3,29, 1,28}, {116, 47, 25, 16}}, //V31
{{30,28,30,30}, {17,10,10,19}, {115, 46, 24, 15}, { 0,23,35,35}, { 0, 47, 25, 16}}, //V32
{{30,28,30,30}, {17,14,29,11}, {115, 46, 24, 15}, { 1,21,19,46}, {116, 47, 25, 16}}, //V33
{{30,28,30,30}, {13,14,44,59}, {115, 46, 24, 16}, { 6,23, 7, 1}, {116, 47, 25, 17}}, //V34
{{30,28,30,30}, {12,12,39,22}, {121, 47, 24, 15}, { 7,26,14,41}, {122, 48, 25, 16}}, //V35
{{30,28,30,30}, { 6, 6,46, 2}, {121, 47, 24, 15}, {14,34,10,64}, {122, 48, 25, 16}}, //V36
{{30,28,30,30}, {17,29,49,24}, {122, 46, 24, 15}, { 4,14,10,46}, {123, 47, 25, 16}}, //V37
{{30,28,30,30}, { 4,13,48,42}, {122, 46, 24, 15}, {18,32,14,32}, {123, 47, 25, 16}}, //V38
{{30,28,30,30}, {20,40,43,10}, {117, 47, 24, 15}, { 4, 7,22,67}, {118, 48, 25, 16}}, //V39
{{30,28,30,30}, {19,18,34,20}, {118, 47, 24, 15}, { 6,31,34,61}, {119, 48, 25, 16}} //V40
};
// GF256 对数表。256字节。
static unsigned char gf256LogTable[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
};
// GF256 反对数表。256字节。
static unsigned char gf256AntilogTable[256] = {
0, 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
};
// 可以使用这两个函数生成对数表和反对数表。
// static unsigned char logTable[256];
// static unsigned char antilogTable[256];
// static unsigned int GF256(unsigned int n){
// unsigned int value = 1;
// while(n--){
// value <<= 1;
// if(value >= 256) value ^= 285;
// }
// return value;
// }
// static void makeLogAndAntilogTable(void){
// unsigned int n, value;
// for(n=0; n<256; n++){
// value = GF256(n);
// logTable[n] = value & 0xff;
// antilogTable[value] = n & 0xff;
// }
// antilogTable[1] = 0;
// }
// 13种QR用到的 生成器多项式 的系数。7+10+13+15+16+17+18+20+22+24+26+28+30 = 246 字节。
static unsigned char generator7 [] = {87,229,146,149,238,102,21};
static unsigned char generator10[] = {251,67,46,61,118,70,64,94,32,45};
static unsigned char generator13[] = {74,152,176,100,86,100,106,104,130,218,206,140,78};
static unsigned char generator15[] = {8,183,61,91,202,37,51,58,58,237,140,124,5,99,105};
static unsigned char generator16[] = {120,104,107,109,102,161,76,3,91,191,147,169,182,194,225,120};
static unsigned char generator17[] = {43,139,206,78,43,239,123,206,214,147,24,99,150,39,243,163,136};
static unsigned char generator18[] = {215,234,158,94,184,97,118,170,79,187,152,148,252,179,5,98,96,153};
static unsigned char generator20[] = {17,60,79,50,61,163,26,187,202,180,221,225,83,239,156,164,212,212,188,190};
static unsigned char generator22[] = {210,171,247,242,93,230,14,109,221,53,200,74,8,172,98,80,219,134,160,105,165,231};
static unsigned char generator24[] = {229,121,135,48,211,117,251,126,159,180,169,152,192,226,228,218,111,0,117,232,87,96,227,21};
static unsigned char generator26[] = {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};
static unsigned char generator28[] = {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};
static unsigned char generator30[] = {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};
// 矩阵对其标记位置表。41x8 = 328 字节。
static unsigned char alignmentTable[41][8] = {
{ 0,0,0,0,0,0,0,0}, //占位
{0, 0,0,0,0,0,0,0}, //V1
{2, 6,18, 0,0,0,0,0}, //V2
{2, 6,22, 0,0,0,0,0}, //V3
{2, 6,26, 0,0,0,0,0}, //V4
{2, 6,30, 0,0,0,0,0}, //V5
{2, 6,34, 0,0,0,0,0}, //V6
{3, 6,22,38, 0,0,0,0}, //V7
{3, 6,24,42, 0,0,0,0}, //V8
{3, 6,26,46, 0,0,0,0}, //V9
{3, 6,28,50, 0,0,0,0}, //V10
{3, 6,30,54, 0,0,0,0}, //V11
{3, 6,32,58, 0,0,0,0}, //V12
{3, 6,34,62, 0,0,0,0}, //V13
{4, 6,26,46,66, 0,0,0}, //V14
{4, 6,26,48,70, 0,0,0}, //V15
{4, 6,26,50,74, 0,0,0}, //V16
{4, 6,30,54,78, 0,0,0}, //V17
{4, 6,30,56,82, 0,0,0}, //V18
{4, 6,30,58,86, 0,0,0}, //V19
{4, 6,34,62,90, 0,0,0}, //V20
{5, 6,28,50,72, 94, 0,0}, //V21
{5, 6,26,50,74, 98, 0,0}, //V22
{5, 6,30,54,78,102, 0,0}, //V23
{5, 6,28,54,80,106, 0,0}, //V24
{5, 6,32,58,84,110, 0,0}, //V25
{5, 6,30,58,86,114, 0,0}, //V26
{5, 6,34,62,90,118, 0,0}, //V27
{6, 6,26,50,74, 98,122, 0}, //V28
{6, 6,30,54,78,102,126, 0}, //V29
{6, 6,26,52,78,104,130, 0}, //V30
{6, 6,30,56,82,108,134, 0}, //V31
{6, 6,34,60,86,112,138, 0}, //V32
{6, 6,30,58,86,114,142, 0}, //V33
{6, 6,34,62,90,118,146, 0}, //V34
{7, 6,30,54,78,102,126,150}, //V35
{7, 6,24,50,76,102,128,154}, //V36
{7, 6,28,54,80,106,132,158}, //V37
{7, 6,32,58,84,110,136,162}, //V38
{7, 6,26,54,82,110,138,166}, //V39
{7, 6,30,58,86,114,142,170} //V40
};
// 格式信息字符串表。4x8x16 = 512 字节。
static char* formatInfoTable[4][8] = {
{
"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"
}
};
// 版本信息字符串表。34x19 = 646 字节。
static char* versionInfoTable[] = {
"000111110010010100", //V7
"001000010110111100", //V8
"001001101010011001", //V9
"001010010011010011", //V10
"001011101111110110", //V11
"001100011101100010", //V12
"001101100001000111", //V13
"001110011000001101", //V14
"001111100100101000", //V15
"010000101101111000", //V16
"010001010001011101", //V17
"010010101000010111", //V18
"010011010100110010", //V19
"010100100110100110", //V20
"010101011010000011", //V21
"010110100011001001", //V22
"010111011111101100", //V23
"011000111011000100", //V24
"011001000111100001", //V25
"011010111110101011", //V26
"011011000010001110", //V27
"011100110000011010", //V28
"011101001100111111", //V29
"011110110101110101", //V30
"011111001001010000", //V31
"100000100111010101", //V32
"100001011011110000", //V33
"100010100010111010", //V34
"100011011110011111", //V35
"100100101100001011", //V36
"100101010000101110", //V37
"100110101001100100", //V38
"100111010101000001", //V39
"101000110001101001" //V40
};
// 以上各种表总大小 328+60+820+256+256+246+328+512+646 = 3452 字节。
////////////////////////////////////////////////////////////////////////////////////////////////////
// 扫描数据,选择合适的编码模式。
// 只区分 数字模式、字符模式、字节模式,除数字模式和字符模式外,其他都用字节模式。
static unsigned int getModeIndicator(
unsigned char *data,
unsigned int dataSize
){
unsigned int mode = ENCODE_MODE_NUME;
while(dataSize){
if((*data < '0') || (*data > '9')){
mode = ENCODE_MODE_ALPH;
break;
}
dataSize -= 1;
data += 1;
}
while(dataSize){
if(
(*data < ' ') ||
(*data > ' ' && *data < '$') ||
(*data > '%' && *data < '*') ||
(*data == ',') ||
(*data > ':' && *data < 'A') ||
(*data > 'Z')
){
return ENCODE_MODE_BYTE;
}
dataSize -= 1;
data += 1;
}
return mode;
}
// 根据 编码模式、纠错等级、数据量 选择最合适的 version。
static unsigned int getMinVersion(
unsigned int mode,
unsigned int level,
unsigned int num
){
unsigned int version, maxBitNum, bitNum, maxNum;
for(version=1; version<=40; version++){
maxBitNum = capacityTable[version][level];
if(mode == ENCODE_MODE_NUME){
if(version <= 9){
bitNum = maxBitNum - (4+10);
}
else if(version <= 26){
bitNum = maxBitNum - (4+12);
}
else{
bitNum = maxBitNum - (4+14);
}
maxNum = (bitNum / 10) * 3;
if(bitNum%10 >= 4) maxNum += 1;
if(bitNum%10 >= 7) maxNum += 1;
}
else if(mode == ENCODE_MODE_ALPH){
if(version <= 9){
bitNum = maxBitNum - (4+9);
}
else if(version <= 26){
bitNum = maxBitNum - (4+11);
}
else{
bitNum = maxBitNum - (4+13);
}
maxNum = (bitNum / 11) * 2;
if(bitNum%11 >= 6) maxNum += 1;
}
else{
if(version <= 9){
bitNum = maxBitNum - (4+8);
}
else{
bitNum = maxBitNum - (4+16);
}
maxNum = bitNum / 8;
}
if(maxNum >= num) return version;
}
return 0;
}
// 将整数转换成位流
static unsigned int valueToBit(
unsigned char *bit,
unsigned int value,
unsigned int bitNum
){
unsigned int ret = bitNum;
while(bitNum){
bitNum -= 1;
*bit = (value & (1<<bitNum)) ? 1 : 0;
bit += 1;
}
return ret;
}
// 将位流转换成字节流
static unsigned int bitToByte(
unsigned char *byte,
unsigned char *bit,
unsigned int bitNum
){
unsigned int byteNum = 0;
while(bitNum >= 8){
byte[byteNum] = (bit[0]<<7)|(bit[1]<<6)|(bit[2]<<5)|(bit[3]<<4)|(bit[4]<<3)|(bit[5]<<2)|(bit[6]<<1)|bit[7];
byteNum += 1;
bitNum -= 8;
bit += 8;
}
return byteNum;
}
// 将字节流转换成位流
static unsigned int byteToBit(
unsigned char *bit,
unsigned char *byte,
unsigned int byteNum
){
unsigned int bitNum = byteNum * 8;
while(byteNum--){
bit[0] = (byte[0]&0x80) ? 1 : 0;
bit[1] = (byte[0]&0x40) ? 1 : 0;
bit[2] = (byte[0]&0x20) ? 1 : 0;
bit[3] = (byte[0]&0x10) ? 1 : 0;
bit[4] = (byte[0]&0x08) ? 1 : 0;
bit[5] = (byte[0]&0x04) ? 1 : 0;
bit[6] = (byte[0]&0x02) ? 1 : 0;
bit[7] = (byte[0]&0x01) ? 1 : 0;
byte += 1;
bit += 8;
}
return bitNum;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// 生成数字模式码字
static unsigned int makeNumericModeCodeword(
unsigned char *buffer,
unsigned char *data,
unsigned int dataNum,
unsigned int version
){
unsigned int offset = valueToBit(buffer, ENCODE_MODE_NUME, 4);
if(version <= 9){
offset += valueToBit(buffer+offset, dataNum, 10);
}
else if(version <= 26){
offset += valueToBit(buffer+offset, dataNum, 12);
}
else{
offset += valueToBit(buffer+offset, dataNum, 14);
}
unsigned int value;
for(;;){
if(dataNum >= 3){
value = (100 * (data[0] - '0')) + (10 * (data[1] - '0')) + (data[2] - '0');
offset += valueToBit(buffer+offset, value, 10);
dataNum -= 3;
data += 3;
}
else if(dataNum == 2){
value = (10 * (data[0] - '0')) + (data[1] - '0');
offset += valueToBit(buffer+offset, value, 7);
break;
}
else if(dataNum == 1){
value = (data[0] - '0');
offset += valueToBit(buffer+offset, value, 4);
break;
}
else{
break;
}
}
return offset;
}
// 生成字符模式码字
static unsigned int makeAlphanumericModeCodeword(
unsigned char *buffer,
unsigned char *data,
unsigned int dataNum,
unsigned int version
){
unsigned int offset = valueToBit(buffer, ENCODE_MODE_ALPH, 4);
if(version <= 9){
offset += valueToBit(buffer+offset, dataNum, 9);
}
else if(version <= 26){
offset += valueToBit(buffer+offset, dataNum, 11);
}
else{
offset += valueToBit(buffer+offset, dataNum, 13);
}
unsigned int value;
for(;;){
if(dataNum >= 2){
value = 45 * alphanumericModeIndexTable[data[0]-' '] + alphanumericModeIndexTable[data[1]-' '];
offset += valueToBit(buffer+offset, value, 11);
dataNum -= 2;
data += 2;
}
else if(dataNum == 1){
value = alphanumericModeIndexTable[data[0]-' '];
offset += valueToBit(buffer+offset, value, 6);
break;
}
else{
break;
}
}
return offset;
}
// 生成字节模式码字
static unsigned int makeByteModeCodeword(
unsigned char *buffer,
unsigned char *data,
unsigned int dataNum,
unsigned int version
){
unsigned int offset = valueToBit(buffer, ENCODE_MODE_BYTE, 4);
if(version <= 9){
offset += valueToBit(buffer+offset, dataNum, 8);
}
else{
offset += valueToBit(buffer+offset, dataNum, 16);
}
while(dataNum){
offset += valueToBit(buffer+offset, data[0], 8);
dataNum -= 1;
data += 1;
}
return offset;
}
// 生成数据码字
static unsigned int makeDataCodeword(
unsigned char *buffer,
unsigned int outNum,
unsigned char *data,
unsigned int dataNum,
unsigned int version,
unsigned int mode
){
unsigned int offset;
if(mode == ENCODE_MODE_NUME){
offset = makeNumericModeCodeword(buffer, data, dataNum, version);
}
else if(mode == ENCODE_MODE_ALPH){
offset = makeAlphanumericModeCodeword(buffer, data, dataNum, version);
}
else{
offset = makeByteModeCodeword(buffer, data, dataNum, version);
}
//最多写入4个终止位0,并补齐到8的整数倍。
if(outNum-offset >= 4){
offset += valueToBit(buffer+offset, 0, 4);
}
else{
offset += valueToBit(buffer+offset, 0, outNum-offset);
}
if(offset%8){
offset += valueToBit(buffer+offset, 0, 8-offset%8);
}
//如果还没满,交替填充 "11101100" 和 "00010001" 直至填满
unsigned int i, paddingByte = (outNum - offset) / 8;
for(i=0; i<paddingByte; i++){
offset += valueToBit(buffer+offset, (i&1)?0x011:0x0ec, 8);
}
return offset;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// 选择 生成器多项式 系数
static unsigned char* getGenerator(
unsigned int num
){
switch(num){
case 7: return generator7;
case 10: return generator10;
case 13: return generator13;
case 15: return generator15;
case 16: return generator16;
case 17: return generator17;
case 18: return generator18;
case 20: return generator20;
case 22: return generator22;
case 24: return generator24;
case 26: return generator26;
case 28: return generator28;
case 30: return generator30;
default: return NULL;
}
}
static unsigned int divideMessagePolynomial(
unsigned char *outBuffer,
unsigned char *generator,
unsigned int generatorNum,
unsigned char *data,
unsigned int dataNum
){
//如果第一个字节等于0,忽略此次运算。
if(data[0] == 0){
memcpy(outBuffer, data+1, dataNum-1);
return dataNum-1;
}
//第一步,用第一个数据乘以生成器的每一项。
unsigned int i, leadTerm = gf256AntilogTable[data[0]];
for(i=0; i<generatorNum; i++){
outBuffer[i] = gf256LogTable[(leadTerm + generator[i]) % 255];
}
dataNum -= 1;
data += 1;
//第二步,用第一步的结果与剩余数据一一进行XOR运算,数据不够就与0进行XOR。
unsigned int xorNum = dataNum >= generatorNum ? generatorNum : dataNum;
for(i=0; i<xorNum; i++){
outBuffer[i] ^= data[i];
}
if(dataNum > generatorNum){
for(i=xorNum; i<dataNum; i++){
outBuffer[i] = data[i];
}
return dataNum;
}
return generatorNum;
}
// 为一个块生成纠错码
static unsigned int makeBlockCorrectionCodeword(
unsigned char *outBuffer,
unsigned int outNum,
unsigned char *data,
unsigned int dataNum
){
unsigned char buffer[2][256];
unsigned char *generator = getGenerator(outNum);
if(generator == NULL) return 0;
if(dataNum < 1) return 0;
unsigned int cycleNum = dataNum-2;
unsigned char *input = data;
unsigned char *output = buffer[1];
dataNum = divideMessagePolynomial(output, generator, outNum, input, dataNum);
unsigned int i; for(i=0; i<cycleNum; i++){
input = output;
output = buffer[i%2];
dataNum = divideMessagePolynomial(output, generator, outNum, input, dataNum);
}
input = output;
output = outBuffer;
dataNum = divideMessagePolynomial(output, generator, outNum, input, dataNum);
return dataNum;
}
//添加纠错码,返回总码字数,总码字数包括数据码字和纠错码字。
static unsigned int addCorrectionCodeword(
unsigned char *outBuffer,
unsigned char *tmpBuffer,
unsigned char *data,
unsigned int version,
unsigned int level
){
unsigned int ECCNum = blockInfoTable[version].ECCodewordsPerBlock[level];
unsigned int BlockNum1 = blockInfoTable[version].BlocksInGroup1[level];
unsigned int DataNum1 = blockInfoTable[version].DataCodewordsPerBlockInGroup1[level];
unsigned int BlockNum2 = blockInfoTable[version].BlocksInGroup2[level];
unsigned int DataNum2 = blockInfoTable[version].DataCodewordsPerBlockInGroup2[level];
//计算每个块的纠错码
unsigned int i;
unsigned int ECCOffset = 0;
unsigned int dataOffset = 0;
for(i=0; i<BlockNum1; i++){
makeBlockCorrectionCodeword(tmpBuffer+ECCOffset, ECCNum, data+dataOffset, DataNum1);
dataOffset += DataNum1;
ECCOffset += ECCNum;
}
for(i=0; i<BlockNum2; i++){
makeBlockCorrectionCodeword(tmpBuffer+ECCOffset, ECCNum, data+dataOffset, DataNum2);
dataOffset += DataNum2;
ECCOffset += ECCNum;
}
//对数据码字进行交叉输出
unsigned int j, outNum = 0;
unsigned int maxDataNum = DataNum1 > DataNum2 ? DataNum1 : DataNum2;
for(i=0; i<maxDataNum; i++){
dataOffset = i;
for(j=0; j<BlockNum1; j++){
if(i < DataNum1){
outBuffer[outNum++] = data[dataOffset];
}
dataOffset += DataNum1;
}
for(j=0; j<BlockNum2; j++){
if(i < DataNum2){
outBuffer[outNum++] = data[dataOffset];
}
dataOffset += DataNum2;
}
}
//对纠错码字进行交叉输出
unsigned int blockNum = BlockNum1 + BlockNum2;
for(i=0; i<ECCNum; i++){
ECCOffset = i;
for(j=0; j<blockNum; j++){
outBuffer[outNum++] = tmpBuffer[ECCOffset];
ECCOffset += ECCNum;
}
}
//有些version需要补充几位0以填满,最多的是补充7个0,这里都补充8个0。
outBuffer[outNum++] = 0;
return outNum;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// 八种不同的mask函数
static unsigned char mask0(unsigned int x, unsigned int y){ return (x+y)%2 == 0;}
static unsigned char mask1(unsigned int x, unsigned int y){ return y%2 == 0;}
static unsigned char mask2(unsigned int x, unsigned int y){ return x%3 == 0;}
static unsigned char mask3(unsigned int x, unsigned int y){ return (x+y)%3 == 0;}
static unsigned char mask4(unsigned int x, unsigned int y){ return ((x/3)+(y/2))%2 == 0;}
static unsigned char mask5(unsigned int x, unsigned int y){ return (((x*y)%2)+((x*y)%3)) == 0;}
static unsigned char mask6(unsigned int x, unsigned int y){ return (((x*y)%2)+((x*y)%3))%2 == 0;}
static unsigned char mask7(unsigned int x, unsigned int y){ return (((x+y)%2)+((x*y)%3))%2 == 0;}
static unsigned char (*maskList[])(unsigned,unsigned) = {
mask0,
mask1,
mask2,
mask3,
mask4,
mask5,
mask6,
mask7
};
// 画点
static void drawPoint(
unsigned char *buffer,
unsigned int scanLine,
unsigned int x,
unsigned int y,
unsigned char value
){
buffer[scanLine * y + x] = value;
}
// 获取点的值
static unsigned char getPoint(
unsigned char *buffer,
unsigned int scanLine,
unsigned int x,
unsigned int y
){
return buffer[scanLine * y + x];
}
// 横向画连续多个点
static void drawLine_h(
unsigned char *buffer,
unsigned int scanLine,
unsigned int x,
unsigned int y,
unsigned int len,
unsigned char value
){
buffer += scanLine * y + x;
while(len--){
*buffer = value;
buffer += 1;
}
}
// 竖向画连续多个点
static void drawLine_v(
unsigned char *buffer,
unsigned int scanLine,
unsigned int x,
unsigned int y,
unsigned int len,
unsigned char value
){
buffer += scanLine * y + x;
while(len--){
*buffer = value;
buffer += scanLine;
}
}
// 画上查看器
static void drawFinder(
unsigned char *buffer,
unsigned int scanLine,
unsigned int x,
unsigned int y
){
drawLine_h(buffer, scanLine, x, y, 7, 1);
drawLine_h(buffer, scanLine, x+1, y+1, 5, 2);
drawLine_h(buffer, scanLine, x+2, y+2, 3, 1);
drawLine_h(buffer, scanLine, x+2, y+3, 3, 1);
drawLine_h(buffer, scanLine, x+2, y+4, 3, 1);
drawLine_h(buffer, scanLine, x+1, y+5, 5, 2);
drawLine_h(buffer, scanLine, x, y+6, 7, 1);
drawLine_v(buffer, scanLine, x, y+1, 5, 1);
drawLine_v(buffer, scanLine, x+1, y+2, 3, 2);
drawLine_v(buffer, scanLine, x+5, y+2, 3, 2);
drawLine_v(buffer, scanLine, x+6, y+1, 5, 1);
}
// 画上查看器的分割线
static void drawSeparators(
unsigned char *buffer,
unsigned int scanLine
){
drawLine_h(buffer, scanLine, 0, 7, 8, 2);
drawLine_v(buffer, scanLine, 7, 0, 7, 2);
drawLine_h(buffer, scanLine, scanLine-8, 7, 8, 2);
drawLine_v(buffer, scanLine, scanLine-8, 0, 7, 2);
drawLine_h(buffer, scanLine, 0, scanLine-8, 8, 2);
drawLine_v(buffer, scanLine, 7, scanLine-7, 7, 2);
}
// 画一个对其标记
static void drawAlignment(
unsigned char *buffer,
unsigned int scanLine,
unsigned int x,
unsigned int y
){
x -= 2; y -= 2;
drawLine_h(buffer, scanLine, x, y, 5, 1);
drawLine_h(buffer, scanLine, x+1, y+1, 3, 2);
drawLine_h(buffer, scanLine, x+1, y+3, 3, 2);
drawLine_h(buffer, scanLine, x, y+4, 5, 1);
drawLine_v(buffer, scanLine, x, y+1, 3, 1);
drawLine_v(buffer, scanLine, x+4, y+1, 3, 1);
drawPoint(buffer, scanLine, x+1, y+2, 2);
drawPoint(buffer, scanLine, x+2, y+2, 1);
drawPoint(buffer, scanLine, x+3, y+2, 2);
}
// 画上所有对其标记
static void drawAllAlignment(
unsigned char *buffer,
unsigned int version,
unsigned int scanLine
){
unsigned int alignNum = alignmentTable[version][0];
unsigned char *aligns = &alignmentTable[version][1];
unsigned int i, j;
for(i=0; i<alignNum; i++){
for(j=0; j<alignNum; j++){
if(
((i == 0) && (j == 0)) ||
((i == alignNum-1) && (j == 0)) ||
((i == 0) && (j == alignNum-1))
){
;
}
else{
drawAlignment(buffer, scanLine, aligns[i], aligns[j]);
}
}
}
}
// 画上 Timing 和 Dark
static void drawTimingAndDark(
unsigned char *buffer,
unsigned int scanLine
){
unsigned int i, num = scanLine - 16;
for(i=0; i<num; i++){
drawPoint(buffer, scanLine, i+8, 6, (i&1)?2:1);
drawPoint(buffer, scanLine, 6, i+8, (i&1)?2:1);
}
//画上 Dark
drawPoint(buffer, scanLine, 8, scanLine-8, 1);
}
// 画上 format 预留区和 version 预留区。
static void drawReserve(
unsigned char *buffer,
unsigned int version,
unsigned int scanLine
){
//画上format预留区
drawLine_h(buffer, scanLine, 0, 8, 6, 2);
drawLine_h(buffer, scanLine, 7, 8, 2, 2);
drawLine_v(buffer, scanLine, 8, 0, 6, 2);
drawPoint(buffer, scanLine, 8, 7, 2);
drawLine_h(buffer, scanLine, scanLine-8, 8, 8, 2);
drawLine_v(buffer, scanLine, 8, scanLine-7, 7, 2);
//画上version预留区
if(version >= 7){
drawLine_v(buffer, scanLine, scanLine-9, 0, 6, 2);
drawLine_v(buffer, scanLine, scanLine-10, 0, 6, 2);
drawLine_v(buffer, scanLine, scanLine-11, 0, 6, 2);
drawLine_h(buffer, scanLine, 0, scanLine-11, 6, 2);
drawLine_h(buffer, scanLine, 0, scanLine-10, 6, 2);
drawLine_h(buffer, scanLine, 0, scanLine-9, 6, 2);
}
}
// 画上最终的点
static unsigned int drawFinalPoint(
unsigned char *buffer,
unsigned int scanLine,
unsigned int x,
unsigned int y,
unsigned int maskId,
unsigned char data
){
unsigned char flag = getPoint(buffer, scanLine, x, y);
if(flag == 0){
if(maskList[maskId](x,y)){
drawPoint(buffer, scanLine, x, y, data?0:1);
}
else{
drawPoint(buffer, scanLine, x, y, data?1:0);
}
return 1;
}
if(flag == 2) drawPoint(buffer, scanLine, x, y, 0);
return 0;
}
// 画上数据位
static void drawDataBit(
unsigned char *buffer,
unsigned int scanLine,
unsigned char *data,
unsigned int maskId
){
unsigned int x = scanLine-1;
unsigned int y = scanLine-1;
for(;;){
if(y){
for(;;){
data += drawFinalPoint(buffer, scanLine, x, y, maskId, data[0]);
data += drawFinalPoint(buffer, scanLine, x-1, y, maskId, data[0]);
if(y == 0) break;
y--;
}
}
else{
for(;;){
data += drawFinalPoint(buffer, scanLine, x, y, maskId, data[0]);
data += drawFinalPoint(buffer, scanLine, x-1, y, maskId, data[0]);
if(y == scanLine-1) break;
y++;
}
}
if(x <= 1) break;
x -= 2;
if(x == 6){
x = 5;
}
}
}
// 清理 Timing 残留
static void cleanTiming(
unsigned char *buffer,
unsigned int scanLine
){
unsigned int y, end = scanLine - 8;
for(y=7; y<=end; y+=2){
drawPoint(buffer, scanLine, 6, y, 0);
}
}
// 画上 format 信息
static void drawFormat(
unsigned char *buffer,
unsigned int scanLine,
unsigned int level,
unsigned int maskId
){
char *format = formatInfoTable[level][maskId];
unsigned int x, y;
y = 8;
x = 0; drawPoint(buffer, scanLine, x, y, format[0] -'0');
x += 1; drawPoint(buffer, scanLine, x, y, format[1] -'0');
x += 1; drawPoint(buffer, scanLine, x, y, format[2] -'0');
x += 1; drawPoint(buffer, scanLine, x, y, format[3] -'0');
x += 1; drawPoint(buffer, scanLine, x, y, format[4] -'0');
x += 1; drawPoint(buffer, scanLine, x, y, format[5] -'0');
x += 2; drawPoint(buffer, scanLine, x, y, format[6] -'0');
x += 1; drawPoint(buffer, scanLine, x, y, format[7] -'0');
y -= 1; drawPoint(buffer, scanLine, x, y, format[8] -'0');
y -= 2; drawPoint(buffer, scanLine, x, y, format[9] -'0');
y -= 1; drawPoint(buffer, scanLine, x, y, format[10]-'0');
y -= 1; drawPoint(buffer, scanLine, x, y, format[11]-'0');
y -= 1; drawPoint(buffer, scanLine, x, y, format[12]-'0');
y -= 1; drawPoint(buffer, scanLine, x, y, format[13]-'0');
y -= 1; drawPoint(buffer, scanLine, x, y, format[14]-'0');
x = 8;
y = scanLine-1; drawPoint(buffer, scanLine, x, y, format[0] -'0');
y -= 1; drawPoint(buffer, scanLine, x, y, format[1] -'0');
y -= 1; drawPoint(buffer, scanLine, x, y, format[2] -'0');
y -= 1; drawPoint(buffer, scanLine, x, y, format[3] -'0');
y -= 1; drawPoint(buffer, scanLine, x, y, format[4] -'0');
y -= 1; drawPoint(buffer, scanLine, x, y, format[5] -'0');
y -= 1; drawPoint(buffer, scanLine, x, y, format[6] -'0');
y = 8;
x = scanLine-8; drawPoint(buffer, scanLine, x, y, format[7] -'0');
x += 1; drawPoint(buffer, scanLine, x, y, format[8] -'0');
x += 1; drawPoint(buffer, scanLine, x, y, format[9] -'0');
x += 1; drawPoint(buffer, scanLine, x, y, format[10]-'0');
x += 1; drawPoint(buffer, scanLine, x, y, format[11]-'0');
x += 1; drawPoint(buffer, scanLine, x, y, format[12]-'0');
x += 1; drawPoint(buffer, scanLine, x, y, format[13]-'0');
x += 1; drawPoint(buffer, scanLine, x, y, format[14]-'0');
}
// 画上 version 信息
static void drawVersion(
unsigned char *buffer,
unsigned int scanLine,
unsigned int version
){
char *versionInfo = versionInfoTable[version-7];
int i; for(i=5; i>=0; i--){
drawPoint(buffer, scanLine, i, scanLine-9, versionInfo[0]-'0');
drawPoint(buffer, scanLine, i, scanLine-10, versionInfo[1]-'0');
drawPoint(buffer, scanLine, i, scanLine-11, versionInfo[2]-'0');
drawPoint(buffer, scanLine, scanLine-9, i, versionInfo[0]-'0');
drawPoint(buffer, scanLine, scanLine-10, i, versionInfo[1]-'0');
drawPoint(buffer, scanLine, scanLine-11, i, versionInfo[2]-'0');
versionInfo += 3;
}
}
// 生成二维码矩阵
static void makeMatrix(
unsigned char *buffer,
unsigned char *data,
unsigned int maskId,
unsigned int version,
unsigned int level
){
unsigned int scanLine = version * 4 + 17;
memset(buffer, 0, scanLine*scanLine);
//画上三个查看器
drawFinder(buffer, scanLine, 0, 0);
drawFinder(buffer, scanLine, scanLine-7, 0);
drawFinder(buffer, scanLine, 0, scanLine-7);
//画上三个查看器的分割线
drawSeparators(buffer, scanLine);
//画上所有对其标记
drawAllAlignment(buffer, version, scanLine);
//画上 Timing 和 Dark。
drawTimingAndDark(buffer, scanLine);
//画上预留区
drawReserve(buffer, version, scanLine);
//画上数据位
drawDataBit(buffer, scanLine, data, maskId);
//清除残留的Timing标记
cleanTiming(buffer, scanLine);
//画上格式
drawFormat(buffer, scanLine, level, maskId);
//画上version
if(version >= 7){
drawVersion(buffer, scanLine, version);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// 查找一行上所有连续色条,长度超过5就扣分。
static unsigned int have5x1_h(
unsigned char *buffer,
unsigned int scanLine,
unsigned int y
){
buffer += scanLine * y;
unsigned int score = 0;
unsigned int i, length = 1;
unsigned char lastColor = buffer[0];
for(i=1; i<scanLine; i++){
if(lastColor == buffer[i]){
length += 1;
}
else{
lastColor = buffer[i];
if(length >= 5) score += (length - 2);
length = 1;
}
}
if(length >= 5) score += (length - 2);
return score;
}
// 查找一列上所有连续色条,长度超过5就扣分。
static unsigned int have5x1_v(
unsigned char *buffer,
unsigned int scanLine,
unsigned int x
){
buffer += x;
unsigned int score = 0;
unsigned int i, length = 1;
unsigned char lastColor = buffer[0];
buffer += scanLine;
for(i=1; i<scanLine; i++){
if(lastColor == buffer[0]){
length += 1;
}
else{
lastColor = buffer[0];
if(length >= 5) score += (length - 2);
length = 1;
}
buffer += scanLine;
}
if(length >= 5) score += (length - 2);
return score;
}
// 第一项评分标准,横向或竖向出现5个以上连续色块扣分,越长扣得越多。
static unsigned int evaluationCondition1(
unsigned char *buffer,
unsigned int scanLine
){
unsigned int i;
unsigned int score = 0;
for(i=0; i<scanLine; i++){
score += have5x1_h(buffer, scanLine, i);
score += have5x1_v(buffer, scanLine, i);
}
return score;
}
// 是不是2x2的连续色块
static unsigned int is2x2block(
unsigned char *buffer,
unsigned int scanLine,
unsigned int x,
unsigned int y
){
buffer += (y * scanLine + x);
if(
(buffer[0] == buffer[1]) &&
(buffer[0] == buffer[scanLine]) &&
(buffer[0] == buffer[scanLine+1])
){
return 3;
}
else{
return 0;
}
}
// 第二项评分标准,每出现一个 2x2 的色块扣3分。
static unsigned int evaluationCondition2(
unsigned char *buffer,
unsigned int scanLine
){
unsigned int x, y;
unsigned int score = 0;
for(y=0; y<scanLine-1; y++){
for(x=0; x<scanLine-1; x++){
score += is2x2block(buffer, scanLine, x, y);
}
}
return score;
}
// 第三项评分标准,略。
static unsigned int evaluationCondition3(
unsigned char *buffer,
unsigned int scanLine
){
return 0;
}
// 第四项评分标准,按黑白点数量评分,数量差越大扣分越多。
static unsigned int evaluationCondition4(
unsigned char *buffer,
unsigned int scanLine
){
unsigned int whiteNum, blackNum = 0;
unsigned int totalNum = scanLine * scanLine;
while(totalNum){
if(*buffer) blackNum += 1;
totalNum -= 1;
buffer += 1;
}
totalNum = scanLine * scanLine;
whiteNum = totalNum - blackNum;
if(whiteNum >= blackNum){
return (whiteNum - blackNum) / 2;
}
else{
return (blackNum - whiteNum) / 2;
}
}
// 对二维码矩阵进行四项评分
static unsigned int makeScore(
unsigned char *buffer,
unsigned int scanLine
){
unsigned int totalScore = 0;
totalScore += evaluationCondition1(buffer, scanLine);
totalScore += evaluationCondition2(buffer, scanLine);
totalScore += evaluationCondition3(buffer, scanLine);
totalScore += evaluationCondition4(buffer, scanLine);
return totalScore;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
int QR_getSize(unsigned char *data, unsigned int dataSize, unsigned int level){
unsigned int mode = getModeIndicator(data, dataSize);
unsigned int version = getMinVersion(mode, level, dataSize);
if(version == 0) return -1;
return version * 4 + 17;
}
int QR_encode(char *outBuffer, unsigned char *data, unsigned int dataSize, unsigned int level){
// 第一步,确定编码模式和最合适的version。
unsigned int mode = getModeIndicator(data, dataSize);
unsigned int version = getMinVersion(mode, level, dataSize);
if(version == 0) return -1;
// 准备两块临时内存
unsigned int scanLine = version * 4 + 17;
unsigned char *tmpBuffer1 = malloc(scanLine*scanLine);
unsigned char *tmpBuffer2 = malloc(scanLine*scanLine);
if((tmpBuffer1 == NULL) || (tmpBuffer2 == NULL)){
if(tmpBuffer1) free(tmpBuffer1);
if(tmpBuffer2) free(tmpBuffer2);
return -2;
}
//第二步,对数据编码。
unsigned int dataCodewordBitNum = capacityTable[version][level];
makeDataCodeword(tmpBuffer1, dataCodewordBitNum, data, dataSize, version, mode);
//第三步,添加纠错码。
unsigned int number = bitToByte(tmpBuffer2, tmpBuffer1, dataCodewordBitNum);
number = addCorrectionCodeword(tmpBuffer1, tmpBuffer2+number, tmpBuffer2, version, level);
number = byteToBit(tmpBuffer2, tmpBuffer1, number);
//第四步,为每一种mask都生成二维码矩阵,并逐个评分。
unsigned int scoreList[8];
unsigned int maskId;
for(maskId=0; maskId<8; maskId++){
makeMatrix(tmpBuffer1, tmpBuffer2, maskId, version, level);
scoreList[maskId] = makeScore(tmpBuffer1, scanLine);
}
//第五步,选择分数最低的mask,生成最终矩阵
unsigned int minScoreMaskId = 0;
for(maskId=1; maskId<8; maskId++){
if(scoreList[maskId] < scoreList[minScoreMaskId]){
minScoreMaskId = maskId;
}
}
makeMatrix(tmpBuffer1, tmpBuffer2, minScoreMaskId, version, level);
//第六步,输出。
unsigned int offset = 0;
number = scanLine * scanLine;
while(offset < number){
outBuffer[offset] = '0' + tmpBuffer1[offset];
offset += 1;
}
outBuffer[offset] = 0;
free(tmpBuffer1);
free(tmpBuffer2);
return scanLine;
}
测试程序test.c:
//==============================================================================
// Copyright (C) 2019 王小康. All rights reserved.
//
// 作者: 王小康
// 描述: QR编码器测试程序
// 日期: 2019-07-19
//
//==============================================================================
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "QR.h"
static void help(char *name){
printf("Usage : %s L|M|Q|H STRING\n", name);
printf("Example: %s H \"https://www.baidu.com\"\n", name);
}
static void printMatrix(char *buffer, unsigned int scanLine){
unsigned int i, j;
printf("\e[47m ");
for(j=0; j<scanLine; j++) printf(" ");
printf(" \e[0m\n");
for(i=0; i<scanLine; i++){
printf("\e[47m ");
for(j=0; j<scanLine; j++){
if(buffer[j] == '1') printf("\e[40m ");
else printf("\e[47m ");
}
printf("\e[47m \e[0m\n");
buffer += scanLine;
}
printf("\e[47m ");
for(j=0; j<scanLine; j++) printf(" ");
printf(" \e[0m\n");
}
int main(int argc, char* argv[]){
if(argc < 3){
help(argv[0]);
return -1;
}
if(argv[1][1]){
help(argv[0]);
return -1;
}
unsigned int level;
if (argv[1][0] == 'L') level = QR_LEVEL_L;
else if(argv[1][0] == 'M') level = QR_LEVEL_M;
else if(argv[1][0] == 'Q') level = QR_LEVEL_Q;
else if(argv[1][0] == 'H') level = QR_LEVEL_H;
else{
help(argv[0]);
return -1;
}
char levels[] = {'L','M','Q','H'};
char buffer[177*177+1];
unsigned int dataLen = strlen(argv[2]);
int scanLine = QR_encode(buffer, (unsigned char*)argv[2], dataLen, level);
if(scanLine < 21){
return -2;
}
printf("QR:version = %u, level = %c, size = %u x %u\n", (scanLine-17)/4, levels[level], scanLine, scanLine);
printMatrix(buffer, scanLine);
return 0;
}
测试程序运行效果(没办法二维码不遮挡文章被锁定):
![](https://img.haomeiwen.com/i15764796/b4b7d2ed4a4c0c84.png)
附加几张表:
![](https://img.haomeiwen.com/i15764796/87daaa5ca7cdc329.png)
![](https://img.haomeiwen.com/i15764796/d6bfdc4fb9c96d6a.png)
![](https://img.haomeiwen.com/i15764796/79d174f83c09e304.png)
![](https://img.haomeiwen.com/i15764796/7e57901d8ea59783.png)
网友评论