美文网首页
QR二维码编码器

QR二维码编码器

作者: 客昂康 | 来源:发表于2021-03-08 12:32 被阅读0次

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

测试程序运行效果(没办法二维码不遮挡文章被锁定):



附加几张表:


各个版本容量表.png
计数所占位数表.png
模式指示标记表.png
字符模式索引表.png

相关文章

网友评论

      本文标题:QR二维码编码器

      本文链接:https://www.haomeiwen.com/subject/lxwjqltx.html