VC实现二维码(qrcode)编码源码

来源:互联网 发布:深圳奥萨制药 知乎 编辑:程序博客网 时间:2024/05/01 01:26

二维码流行起来了,到处可见,好像报纸广告上面没个二维码就不上档次是的,所以好奇,略研究了一下,搜出了不少都是ZXING的C#版,或是java, 还有JS的,但暂没收到 VC MFC方面的,所以做个体力劳动,将java版的批量转换了一下, 望网友指正, 同时在我的资源下载中我提供一个DLL用于其它非MFC开发程序用:

二维码的关键点:

      数据表示:     全是数字的,0-9的数

                              数字与大字字母混合的

                             全是汉字或日文字的

                             以上三种都不是的,直接以8BIT字符来存数据

 

    容错等级:

                   H      是高           撕掉30%都无所谓,照读得出来 ,所以现在好多二维码中间搞了logo,很牛的样子

                   M       20%

                   Q    15%

                    L      5%

   版本:     1-40,    基本上1-10就够用了,本文暂实现1-10,要扩展只要增加定义就行

源码一个qrcode.h,一个qrcode.cpp, 

用法:

a)直接画在dc上 

 CQrcode *qrcode = CQrcode::getMinimumQRCode("http://www.csdn.net", ErrorCorrectLevel_H);
  qrcode->Draw(pDC, 4, 4);

b)保存为bmp图像:

CQrcode *qrcode = CQrcode::getMinimumQRCode("http://www.csdn.net", ErrorCorrectLevel_H);
qrcode->SaveToBmp("c:\\csdn.bmp", 4, 4);

 

//qrcode.h:

class CQrcodeBitBuffer 
{
public:
 void put(BOOL bit);
 void put(int num, int length);
 BOOL get(int index);
 CString toString();
 int getLengthInBits();
 BYTE* getBuffer();
 CQrcodeBitBuffer();
 virtual ~CQrcodeBitBuffer();
private:
 BYTE *buffer;
 int buffer_len;
 int length;
 int inclements;
};

class CQrcodePolynomial 
{
public:
 CQrcodePolynomial mod(CQrcodePolynomial &e);
 CQrcodePolynomial multiply(CQrcodePolynomial &e);
 CString toLogString();
 CString toString();
 int getLength();
 int get(int idx);
 //
 CQrcodePolynomial(CUIntArray& nums, int shift);
 CQrcodePolynomial(const CQrcodePolynomial &p);
 CQrcodePolynomial& operator=(const CQrcodePolynomial &p);

 virtual ~CQrcodePolynomial();

 CUIntArray m_nums;
};

class CQrcodeUtil 
{
public:
 static int unsignedRightShift(int v, int n);
 static int getBCHTypeNumber(int data);
 static int getBCHTypeInfo(int data);
 static int getBCHDigit(int data);
 static BOOL isHanZi(CString s);
 static BOOL isAlphaNum(CString s);
 static BOOL isNumber(CString s);
 static int getMode(CString s);
 static BOOL getMask(int maskPattern, int i, int j);
 static CQrcodePolynomial getErrorCorrectPolynomial(int errorCorrectLength);
 static void getPatternPosition(int typeNumber, CUIntArray &p);
 static int getMaxLength(int typeNumber, int mode, int errorCorrectLevel);

 CQrcodeUtil();
 virtual ~CQrcodeUtil();

};

 

class CQrcodeMath 
{
public:
 int gexp(int n);
 int glog(int n);

 static CQrcodeMath * getInstance();

 CQrcodeMath();
 virtual ~CQrcodeMath();


private:
 CUIntArray EXP_TABLE;
 CUIntArray LOG_TABLE;
};


class CQrcodeData  : public CObject
{
public:
 int getLengthInBits(int type);
 virtual void write(CQrcodeBitBuffer &buffer);
 virtual int getLength();

 int getMode();
 CQrcodeData(int mode, CString data);
 virtual ~CQrcodeData();

 CString data;

private:
 int mode;
};

class CQrcodeNumber : public CQrcodeData 
{
public:
 virtual void write(CQrcodeBitBuffer &buffer);
 int parseInt(CString s);
 CQrcodeNumber(CString data);
 virtual ~CQrcodeNumber();

};


 

class CQrcodeAlphaNum : public CQrcodeData 
{
public:
 int getCode(char c);
 virtual void write(CQrcodeBitBuffer &buffer);
 CQrcodeAlphaNum(CString data);
 virtual ~CQrcodeAlphaNum();

};

class CQrcodeHanzi : public CQrcodeData 
{
public:
 virtual void write(CQrcodeBitBuffer &buffer);
 virtual int getLength();
 CQrcodeHanzi(CString data);
 virtual ~CQrcodeHanzi();

};

 

class CQrcode8BitByte : public CQrcodeData 
{
public:
 virtual void write(CQrcodeBitBuffer &buffer);
 CQrcode8BitByte(CString data);
 virtual ~CQrcode8BitByte();

};

 

class CQrcode2DIntArray 
{
public:
 CUIntArray * GetIntArray(int r);
 int GetAt(int r,int c);
 void SetAt(int r,int c,int v);
 CQrcode2DIntArray();
 virtual ~CQrcode2DIntArray();
private:
 CObArray a;
};

 

class CQrcodeRSBlock  : public CObject
{
public:
 CQrcodeRSBlock(int totalCount, int dataCount);
 virtual ~CQrcodeRSBlock();

 int getDataCount();
 int getTotalCount();
 static void getRsBlockTable(int typeNumber, int errorCorrectLevel, CUIntArray &a);
 static void getRSBlocks(int typeNumber, int errorCorrectLevel, CObArray &RBSlocks);

private:
 int totalCount;
 int dataCount;

};


class CQrcode
{
public:
 void SaveToBmp(CString filename, int cellSize, int margin);
 void Draw(CDC *pdc,int cellSize, int margin);
 static CQrcode* getMinimumQRCode(CString data, int errorCorrectLevel);
 void mapData(BYTE* bytes,int bytes_size, int maskPattern);
 static BYTE* createData(int typeNumber, int errorCorrectLevel, CObArray &dataArray, int* bytesSize);
 static BYTE* createBytes(CQrcodeBitBuffer &buffer, CObArray &rsBlocks, int* bytesSize);
 void setupTypeNumber(BOOL test);
 void setupTypeInfo(BOOL test, int maskPattern);
 void setupTimingPattern();
 void setupPositionAdjustPattern();
 void setupPositionProbePattern(int row, int col);
 static int getLostPoint(CQrcode *qrcode);
 int getBestMaskPattern();
 void make();
 void make(BOOL test, int maskPattern);
 int getModuleCount();
 BOOL isDark(int row, int col);
 CQrcodeData * getData(int index);
 int getDataCount();
 void clearData();
 void addData(CString data, int mode);
 void addData(CString data);
 void setErrorCorrectLevel(int errorCorrectLevel);
 void setTypeNumber(int typeNumber);
 CQrcode();
 virtual ~CQrcode();

private:
 BYTE *modules;
 int moduleCount;
 int typeNumber;
 int errorCorrectLevel;
 CObArray qrDataList;

};

#define ErrorCorrectLevel_L  1
#define ErrorCorrectLevel_M  0
#define ErrorCorrectLevel_Q  3
#define ErrorCorrectLevel_H  2

 

//qrcode.cpp

#include "qrcode.h"

#define MODE_NUMBER  (1<<0)
#define MODE_ALPHA_NUM (1<<1)
#define MODE_8BIT_BYTE (1<<2)
#define MODE_HANZI (1<<3)
#define PATTERN000 0
#define PATTERN001 1
#define PATTERN010 2
#define PATTERN011 3
#define PATTERN100 4
#define PATTERN101 5
#define PATTERN110 6
#define PATTERN111 7
#define PAD0   0xEC
#define PAD1   0x11
#define G15 ((1<<10)|(1<<8)|(1<<5)|(1<<4)|(1<<2)|(1<<1)|(1<<0))
#define G18 ((1<<12)|(1<<11)|(1<<10)|(1<<9)|(1<<8)|(1<<5)|(1<<2)|(1<<0))
#define G15_MASK ((1<<14)|(1<<12)|(1<<10)|(1<<4)|(1<<1))

int RS_BLOCK_TABLE[40][6]  = {

  // L =1
  // M =0
  // Q =3
  // H =2

  // 1
  {1, 26, 19,0,0,0},
  {1, 26, 16,0,0,0},
  {1, 26, 13,0,0,0},
  {1, 26, 9,0,0,0},
 
  // 2
  {1, 44, 34,0,0,0},
  {1, 44, 28,0,0,0},
  {1, 44, 22,0,0,0},
  {1, 44, 16,0,0,0},

  // 3
  {1, 70, 55,0,0,0},
  {1, 70, 44,0,0,0},
  {2, 35, 17,0,0,0},
  {2, 35, 13,0,0,0},

  // 4 
  {1, 100, 80,0,0,0},
  {2, 50, 32,0,0,0},
  {2, 50, 24,0,0,0},
  {4, 25, 9,0,0,0},
 
  // 5
  {1, 134, 108,0,0,0},
  {2, 67, 43,0,0,0},
  {2, 33, 15, 2, 34, 16},
  {2, 33, 11, 2, 34, 12},
 
  // 6
  {2, 86, 68,0,0,0},
  {4, 43, 27,0,0,0},
  {4, 43, 19,0,0,0},
  {4, 43, 15,0,0,0},
 
  // 7 
  {2, 98, 78,0,0,0},
  {4, 49, 31,0,0,0},
  {2, 32, 14, 4, 33, 15},
  {4, 39, 13, 1, 40, 14},
 
  // 8
  {2, 121, 97,0,0,0},
  {2, 60, 38, 2, 61, 39},
  {4, 40, 18, 2, 41, 19},
  {4, 40, 14, 2, 41, 15},
 
  // 9
  {2, 146, 116,0,0,0},
  {3, 58, 36, 2, 59, 37},
  {4, 36, 16, 4, 37, 17},
  {4, 36, 12, 4, 37, 13},
 
  // 10 
  {2, 86, 68, 2, 87, 69},
  {4, 69, 43, 1, 70, 44},
  {6, 43, 19, 2, 44, 20},
  {6, 43, 15, 2, 44, 16}

 };

 

 int PATTERN_POSITION_TABLE[40][7] ={
  {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}
 };
 int MAX_LENGTH[10][4][4] = {
      //L N   A    8B  Han           M                         Q                     H
        { {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} }
    };


 

CQrcodeBitBuffer::CQrcodeBitBuffer()
{
 inclements = 32;
 buffer = (BYTE*)malloc(inclements);
 memset(buffer, 0, inclements);
 buffer_len = inclements;
 length = 0;
}

CQrcodeBitBuffer::~CQrcodeBitBuffer()
{
 free(buffer);
}

BYTE* CQrcodeBitBuffer::getBuffer()
{
 return buffer;
}

int CQrcodeBitBuffer::getLengthInBits()
{
 return length;
}

CString CQrcodeBitBuffer::toString()
{
 CString s;
 for (int i = 0; i < getLengthInBits(); i++) {
  s += get(i) ? "1" : "0";
 }
 return s;
}

BOOL CQrcodeBitBuffer::get(int index)
{
 int n = CQrcodeUtil::unsignedRightShift(buffer[index / 8], 7 - index % 8);
 return (n&1) == 1;
}

void CQrcodeBitBuffer::put(int num, int length)
{
 int t;
 for (int i = 0; i < length; i++) {
  t = CQrcodeUtil::unsignedRightShift(num, length-i-1);
  put(  (t & 1) == 1);
 }
}

void CQrcodeBitBuffer::put(BOOL bit)
{
 if (length == buffer_len * 8) {
  BYTE* newBuffer = (BYTE*)malloc(buffer_len + inclements);
  memset(newBuffer, 0, buffer_len + inclements);
  memcpy(newBuffer, buffer, buffer_len);
  free(buffer);
  buffer = newBuffer;
  buffer_len += inclements;
 }

 if (bit) {
  buffer[length / 8] |= CQrcodeUtil::unsignedRightShift(0x80, length % 8);
 }

 length++;
}


 

CQrcodeUtil::CQrcodeUtil()
{

}

CQrcodeUtil::~CQrcodeUtil()
{

}


void CQrcodeUtil::getPatternPosition(int typeNumber, CUIntArray &p)
{
 int *pp = PATTERN_POSITION_TABLE[typeNumber - 1];
 for(int i=0;i<7;i++)
 {
  if (pp[i] == 0) break;
  p.Add(pp[i]);
 }
}
int CQrcodeUtil::getMaxLength(int typeNumber, int mode, int errorCorrectLevel)
{
    int t = typeNumber - 1;
    int e = 0;
    int m = 0;

    switch(errorCorrectLevel) {
    case ErrorCorrectLevel_L : e = 0; break;
    case ErrorCorrectLevel_M : e = 1; break;
    case ErrorCorrectLevel_Q : e = 2; break;
    case ErrorCorrectLevel_H : e = 3; break;
    default :
        return 0;
    }

    switch(mode) {
    case MODE_NUMBER    : m = 0; break;
    case MODE_ALPHA_NUM : m = 1; break;
    case MODE_8BIT_BYTE : m = 2; break;
    case MODE_HANZI    : m = 3; break;
    default :
        return 0;
    }

    return MAX_LENGTH[t][e][m];
}

CQrcodePolynomial CQrcodeUtil::getErrorCorrectPolynomial(int errorCorrectLength)
{
 CUIntArray tnums;
 tnums.Add(1);
 CQrcodePolynomial a(tnums,0);
 CQrcodeMath *qrmath = CQrcodeMath::getInstance();
 for (int i = 0; i < errorCorrectLength; i++) {
  tnums.RemoveAll();
  tnums.Add(1);
  tnums.Add(qrmath->gexp(i));
  CQrcodePolynomial b(tnums,0);
  a = a.multiply(b);
 }

 return a;
}

BOOL CQrcodeUtil::getMask(int maskPattern, int i, int j)
{
 switch (maskPattern) {
 case PATTERN000 : return (i + j) % 2 == 0;
 case PATTERN001 : return i % 2 == 0;
 case PATTERN010 : return j % 3 == 0;
 case PATTERN011 : return (i + j) % 3 == 0;
 case PATTERN100 : return (i / 2 + j / 3) % 2 == 0;
 case PATTERN101 : return (i * j) % 2 + (i * j) % 3 == 0;
 case PATTERN110 : return ( (i * j) % 2 + (i * j) % 3) % 2 == 0;
 case PATTERN111 : return ( (i * j) % 3 + (i + j) % 2) % 2 == 0;
 default :
  return FALSE;
 }
 return FALSE;
}

int CQrcodeUtil::getMode(CString s)
{
 if (isAlphaNum(s) ) {
  if (isNumber(s) ) {
   return MODE_NUMBER;
  }
  return MODE_ALPHA_NUM;
 } else if (isHanZi(s) ) {
  return MODE_HANZI;
 } else {
  return MODE_8BIT_BYTE;
 }
}

BOOL CQrcodeUtil::isNumber(CString s)
{
 for (int i = 0; i < s.GetLength(); i++) {
  char c = s.GetAt(i);
  if (!('0' <= c && c <= '9') ) {
   return FALSE;
  }
 }
 return TRUE;
}

BOOL CQrcodeUtil::isAlphaNum(CString s)
{
 CString othersAlpha = " $%*+-./:";
 for (int i = 0; i < s.GetLength(); i++) {
  char c = s.GetAt(i);
  if (!('0' <= c && c <= '9') && !('A' <= c && c <= 'Z') && othersAlpha.Find(c) == -1) {
   return FALSE;
  }
 }
 return TRUE;
}

BOOL CQrcodeUtil::isHanZi(CString s)
{
 //byte[] data = s.getBytes(QRUtil.getJISEncoding() );

 int i = 0;
 int dLen = s.GetLength();

 while (i + 1 < dLen) {
 
  int c = ( (0xff & s[i]) << 8) | (0xff & s[i + 1]);

  if (!(0x8140 <= c && c <= 0x9FFC) && !(0xE040 <= c && c <= 0xEBBF) ) {
   return FALSE;
  }
 
  i += 2;
 }

 if (i < dLen) {
  return FALSE;
 }
 
 return TRUE;
}

int CQrcodeUtil::getBCHDigit(int data)
{
 int digit = 0;

 while (data != 0) {
  digit++;
  data = unsignedRightShift(data, 1);  //data >>>= 1;
 }

 return digit;
}

int CQrcodeUtil::getBCHTypeInfo(int data)
{
 int d = data << 10;
 while (getBCHDigit(d) - getBCHDigit(G15) >= 0) {
  d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15) ) ); 
 }
 return ( (data << 10) | d) ^ G15_MASK;
}

int CQrcodeUtil::getBCHTypeNumber(int data)
{
 int d = data << 12;
 while (getBCHDigit(d) - getBCHDigit(G18) >= 0) {
  d ^= (G18 << (getBCHDigit(d) - getBCHDigit(G18) ) ); 
 }
 return (data << 12) | d;
}
//
//无符号右移运算符>>> 针对8byte应该没问题
int CQrcodeUtil::unsignedRightShift(int v, int n)
{
 int t = v >> n;
 return t & 0x7FFFFFF;
}


 

 

CQrcodePolynomial::CQrcodePolynomial(const CQrcodePolynomial &p)
{
 if(this == &p)  return;
 m_nums.RemoveAll();
 for(int i=0;i<p.m_nums.GetSize();i++) m_nums.Add(p.m_nums.GetAt(i));
}
CQrcodePolynomial& CQrcodePolynomial::operator=(const CQrcodePolynomial &p)
{    
 if(this == &p)  return *this;
 m_nums.RemoveAll();
 for(int i=0;i<p.m_nums.GetSize();i++) m_nums.Add(p.m_nums.GetAt(i));
 return *this;
}
//
CQrcodePolynomial::CQrcodePolynomial(CUIntArray& nums, int shift)
{
 int length = nums.GetSize();
 int offset = 0;

 while (offset < length && nums[offset] == 0) {
  offset++;
 }

 int i;
 //this.num = new int[length - offset + shift];
 m_nums.RemoveAll();
 for ( i=0;i<length - offset + shift;i++) m_nums.Add(0);
 //System.arraycopy(num, offset, this.num, 0, num.length - offset);
 for ( i=offset;i<length;i++) m_nums[i-offset] = nums[i];
}

CQrcodePolynomial::~CQrcodePolynomial()
{

}

int CQrcodePolynomial::get(int idx)
{
 return m_nums[idx];
}

int CQrcodePolynomial::getLength()
{
 return m_nums.GetSize();
}

CString CQrcodePolynomial::toString()
{
 CString s,t;
 for (int i = 0; i < getLength(); i++) {
  if (i > 0) {
   s += ",";
  }
  t.Format("%d", get(i) );
  s += t;
 }
 return s;
}

CString CQrcodePolynomial::toLogString()
{
 CString s,t;
 CQrcodeMath *qrmath = CQrcodeMath::getInstance();
 for (int i = 0; i < getLength(); i++) {
  if (i > 0) {
   s += ",";
  }
  t.Format("%d", qrmath->glog(get(i)) ); //QRMath.glog(get(i) )
  s += t;
 }
 return s;
}

CQrcodePolynomial CQrcodePolynomial::multiply(CQrcodePolynomial &e)
{
  CUIntArray tnums;
  int i;
  for( i=0;i<getLength() + e.getLength() - 1;i++)
  {
   tnums.Add(0);
  }
  CQrcodeMath *qrmath = CQrcodeMath::getInstance();
  for ( i = 0; i < getLength(); i++) {
   for (int j = 0; j < e.getLength(); j++) {
    tnums[i + j] ^= qrmath->gexp(qrmath->glog(get(i) ) + qrmath->glog(e.get(j) ) );
   }
  }

  return CQrcodePolynomial(tnums,0);
}

CQrcodePolynomial CQrcodePolynomial::mod(CQrcodePolynomial &e)
{
 if (getLength() - e.getLength() < 0) {
  return (*this);
 }

 CQrcodeMath *qrmath = CQrcodeMath::getInstance();
 //
 int ratio = qrmath->glog(get(0));
 ratio -= qrmath->glog(e.get(0));

 //
 //int[] num = new int[getLength()];
 CUIntArray tnums;
 int i;
 for(  i=0;i<getLength();i++) tnums.Add(0);
 for ( i = 0; i < getLength(); i++) {
  tnums[i] = get(i);
 }
 
 //
 for ( i = 0; i < e.getLength(); i++) {
  tnums[i] ^= qrmath->gexp(qrmath->glog(e.get(i)) + ratio);
 }

 //
 CQrcodePolynomial pt(tnums,0);
 return pt.mod(e);
}


 

CQrcodeMath *pQrmath = NULL;

CQrcodeMath::CQrcodeMath()
{
 int i;
 for ( i = 0; i < 256; i++) EXP_TABLE.Add(0);
 for ( i = 0; i < 8; i++) {
  EXP_TABLE[i] = 1 << i;
 }
 for ( i = 8; i < 256; i++) EXP_TABLE[i] =  EXP_TABLE[i - 4]^ EXP_TABLE[i - 5]^ EXP_TABLE[i - 6]^ EXP_TABLE[i - 8];
 for ( i = 0; i < 256; i++)  LOG_TABLE.Add(0);
 for ( i = 0; i < 255; i++)  LOG_TABLE[EXP_TABLE[i]] = i;
}

CQrcodeMath::~CQrcodeMath()
{

}

CQrcodeMath * CQrcodeMath::getInstance()
{
 if (pQrmath!=NULL){
  return pQrmath;
 }
 pQrmath = new CQrcodeMath();
 return pQrmath;
}

int CQrcodeMath::glog(int n)
{
 if (n < 1) {
  return 0;
 }
 
 return LOG_TABLE[n];
}

int CQrcodeMath::gexp(int n)
{
 while (n < 0) {
  n += 255;
 }

 while (n >= 256) {
  n -= 255;
 }

 return EXP_TABLE[n];
}


 

CQrcodeRSBlock::CQrcodeRSBlock(int totalCount, int dataCount)
{
  this->totalCount = totalCount;
  this->dataCount  = dataCount;
}

CQrcodeRSBlock::~CQrcodeRSBlock()
{

}

void CQrcodeRSBlock::getRsBlockTable(int typeNumber, int errorCorrectLevel, CUIntArray &a)
{
 int *p = NULL;
 switch(errorCorrectLevel) {
 case ErrorCorrectLevel_L :
  p = RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
  break;
 case ErrorCorrectLevel_M :
  p =  RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
  break;
 case ErrorCorrectLevel_Q :
  p =  RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
  break;
 case ErrorCorrectLevel_H :
  p = RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
 default :
  break;
 }
 if (p!=NULL){
  for (int i=0;i<6;i++){
   if (p[i] == 0) break;
   a.Add(p[i]);
  }
 }
}


void CQrcodeRSBlock::getRSBlocks(int typeNumber, int errorCorrectLevel, CObArray &RBSlocks)
{
 CUIntArray rsBlock;
 getRsBlockTable(typeNumber, errorCorrectLevel, rsBlock);
 int length = rsBlock.GetSize() / 3;
 // 
 for (int i = 0; i < length; i++) {

  int count = rsBlock[i * 3 + 0];
  int totalCount = rsBlock[i * 3 + 1];
  int dataCount  = rsBlock[i * 3 + 2];

  for (int j = 0; j < count; j++) {
   RBSlocks.Add(new CQrcodeRSBlock(totalCount, dataCount) );
  }
 }
}

int CQrcodeRSBlock::getDataCount() {
 return dataCount;
}
 
int CQrcodeRSBlock::getTotalCount() {
 return totalCount;
}


CQrcode2DIntArray::CQrcode2DIntArray()
{

}

CQrcode2DIntArray::~CQrcode2DIntArray()
{

}

void CQrcode2DIntArray::SetAt(int r, int c, int v)
{
 for(int i=a.GetSize()-1;i<r;i++) a.Add(new CUIntArray());
 CUIntArray *p = (CUIntArray*) a.GetAt(r);
 for(int j=p->GetSize()-1;j<c;j++) p->Add(0);
 p->SetAt(c, v);
}

int CQrcode2DIntArray::GetAt(int r, int c)
{
 CUIntArray *p = (CUIntArray*) a.GetAt(r);
 return p->GetAt(c);
}

CUIntArray * CQrcode2DIntArray::GetIntArray(int r)
{
 return (CUIntArray*) a.GetAt(r);
}

 

CQrcode8BitByte::CQrcode8BitByte(CString data) : CQrcodeData(MODE_8BIT_BYTE, data)
{

}

CQrcode8BitByte::~CQrcode8BitByte()
{

}

void CQrcode8BitByte::write(CQrcodeBitBuffer &buffer)
{
 for (int i = 0; i < data.GetLength(); i++) {
  buffer.put(data[i], 8);
 }
}

CQrcodeAlphaNum::CQrcodeAlphaNum(CString data) : CQrcodeData(MODE_ALPHA_NUM, data)
{

}

CQrcodeAlphaNum::~CQrcodeAlphaNum()
{

}

void CQrcodeAlphaNum::write(CQrcodeBitBuffer &buffer)
{
 int i = 0;
 int len = data.GetLength();

 while (i + 1 < len) {
  buffer.put(getCode(data[i]) * 45 + getCode(data[i + 1]), 11);
  i += 2;
 }
 
 if (i < len) {
  buffer.put(getCode(data[i]), 6);
 }
}

int CQrcodeAlphaNum::getCode(char c)
{
  if ('0' <= c && c <= '9') {
   return c - '0';
  } else if ('A' <= c && c <= 'Z') {
   return c - 'A' + 10;
  } else {
   switch (c) {
   case ' ' : return 36;
   case '$' : return 37;
   case '%' : return 38;
   case '*' : return 39;
   case '+' : return 40;
   case '-' : return 41;
   case '.' : return 42;
   case '/' : return 43;
   case ':' : return 44;
   default :
     return 36;
   }
  }
}

CQrcodeData::CQrcodeData(int mode, CString data)
{
 this->mode = mode;
 this->data = data;
}

CQrcodeData::~CQrcodeData()
{

}

int CQrcodeData::getMode()
{
 return mode;
}


int CQrcodeData::getLength()
{
 return data.GetLength();
}

void CQrcodeData::write(CQrcodeBitBuffer &buffer)
{

}

int CQrcodeData::getLengthInBits(int type)
{
  if (1 <= type && type < 10) {

   // 1 - 9

   switch(mode) {
   case MODE_NUMBER   : return 10;
   case MODE_ALPHA_NUM  : return 9;
   case MODE_8BIT_BYTE : return 8;
   case MODE_HANZI    : return 8;
   default :
    return 8;
   }

  } else if (type < 27) {

   // 10 - 26

   switch(mode) {
   case MODE_NUMBER   : return 12;
   case MODE_ALPHA_NUM  : return 11;
   case MODE_8BIT_BYTE : return 16;
   case MODE_HANZI    : return 10;
   default :
    return 10;
   }

  } else if (type < 41) {

   // 27 - 40

   switch(mode) {
   case MODE_NUMBER   : return 14;
   case MODE_ALPHA_NUM : return 13;
   case MODE_8BIT_BYTE : return 16;
   case MODE_HANZI    : return 12;
   default :
    return 12;
   }

  } else {
   return 8;
  }
}

CQrcodeHanzi::CQrcodeHanzi(CString data) : CQrcodeData(MODE_HANZI, data)
{

}

CQrcodeHanzi::~CQrcodeHanzi()
{

}

int CQrcodeHanzi::getLength()
{
 return data.GetLength()/2;
}

void CQrcodeHanzi::write(CQrcodeBitBuffer &buffer)
{

 int dlen = data.GetLength();
   int i = 0;

   while (i + 1 < dlen) {
   
    int c = ( (0xff & data[i]) << 8) | (0xff & data[i + 1]);

    if (0x8140 <= c && c <= 0x9FFC) {
     c -= 0x8140;
    } else if (0xE040 <= c && c <= 0xEBBF) {
     c -= 0xC140;
    } else {
     i += 2;
     continue;
    }
   
    c = ( CQrcodeUtil::unsignedRightShift(c, 8) & 0xff) * 0xC0 + (c & 0xff);

    buffer.put(c, 13);
   
    i += 2;
   }

   if (i < dlen) {
   }
}


CQrcodeNumber::CQrcodeNumber(CString data) : CQrcodeData(MODE_NUMBER, data)
{
}

CQrcodeNumber::~CQrcodeNumber()
{

}


int CQrcodeNumber::parseInt(CString s)
{
 int num = 0;
 for (int i = 0; i < s.GetLength(); i++) {
  num = num * 10 + (s.GetAt(i) - '0');
 }
 //CString ss;ss.Format("%d",num);AfxMessageBox(ss);
 return num;
}


void CQrcodeNumber::write(CQrcodeBitBuffer &buffer)
{
 int i = 0;
 int dataLen = data.GetLength();
 int num;

 while (i + 2 < dataLen  ) {
  num = parseInt(data.Mid(i, 3));//数字类型的数据,每三位数 变成一个10位的二进制,如果256  变成 0010000000
  buffer.put(num, 10);
  i += 3;
 }
 
 if (i < dataLen ) {
 
  if (dataLen - i == 1) {
   num = parseInt(data.Mid(i, 1));
   buffer.put(num, 4);
  } else if (dataLen - i == 2) {
   num = parseInt(data.Mid(i, 2));
   buffer.put(num, 7);
  }

 }
}


 

CQrcode::CQrcode()
{
 modules = NULL;
  typeNumber = 1;
 errorCorrectLevel = ErrorCorrectLevel_H;
}

CQrcode::~CQrcode()
{
 clearData();
}

void CQrcode::setTypeNumber(int typeNumber)
{
 this->typeNumber = typeNumber;
}

void CQrcode::setErrorCorrectLevel(int errorCorrectLevel)
{
 this->errorCorrectLevel = errorCorrectLevel;
}

void CQrcode::addData(CString data)
{
 addData(data, CQrcodeUtil::getMode(data) );
}

void CQrcode::addData(CString data, int mode)
{
  switch(mode) {

  case MODE_NUMBER :
   qrDataList.Add(new CQrcodeNumber(data) );
   break;

  case MODE_ALPHA_NUM :
   qrDataList.Add(new CQrcodeAlphaNum(data) );
   break;

  case MODE_8BIT_BYTE :
   qrDataList.Add(new CQrcode8BitByte(data) );
   break;

  case MODE_HANZI :
   qrDataList.Add(new CQrcodeHanzi(data) );
   break;

  default :
   ;
  }
}

void CQrcode::clearData()
{
 for(int i=0;i<qrDataList.GetSize();i++){
  delete qrDataList.GetAt(i);
 }
 qrDataList.RemoveAll();
}

int CQrcode::getDataCount()
{
 return qrDataList.GetSize();
}

CQrcodeData * CQrcode::getData(int index)
{
 return (CQrcodeData*) qrDataList.GetAt(index);
}

BOOL CQrcode::isDark(int row, int col)
{
 if (modules[row*moduleCount + col] != 0 ) {
  return (modules[row*moduleCount + col] == 1) ? TRUE : FALSE; //1==true 2==false
 } else {
  return FALSE;
 }
 return TRUE;
}

int CQrcode::getModuleCount()
{
 return moduleCount;
}

void CQrcode::make(BOOL test, int maskPattern)
{
  //二维码方框像数大小
  moduleCount = typeNumber * 4 + 17;
  //modules = new Boolean[moduleCount][moduleCount];
  modules = (BYTE*)malloc(moduleCount*moduleCount);
  memset(modules, 0, moduleCount*moduleCount);

  //
  setupPositionProbePattern(0, 0);
  setupPositionProbePattern(moduleCount - 7, 0);
  setupPositionProbePattern(0, moduleCount - 7);
 
  setupPositionAdjustPattern();
  setupTimingPattern();

  setupTypeInfo(test, maskPattern);

  if (typeNumber >= 7) {
   setupTypeNumber(test);
  }
 
  //QRData[] dataArray = (QRData[])qrDataList.toArray(new QRData[qrDataList.size()]);
  //byte[] data = createData(typeNumber, errorCorrectLevel, dataArray);
  //mapData(data, maskPattern);

  int bytes_len = 0;
  BYTE* bytes = createData(typeNumber, errorCorrectLevel, qrDataList, &bytes_len);
  mapData(bytes, bytes_len, maskPattern);
}

void CQrcode::make()
{
 make(FALSE, getBestMaskPattern() );
}

int CQrcode::getBestMaskPattern()
{
  int minLostPoint = 0;
  int pattern = 0;

  for (int i = 0; i < 8; i++) {

   make(true, i);

   int lostPoint = getLostPoint(this);

   if (i == 0 || minLostPoint >  lostPoint) {
    minLostPoint = lostPoint;
    pattern = i;
   }
  }

  return pattern;
}

int CQrcode::getLostPoint(CQrcode *qrcode)
{
  int moduleCount = qrcode->getModuleCount();
 
  int lostPoint = 0;
 
  int row;

  // LEVEL1
 
  for ( row = 0; row < moduleCount; row++) {

   for (int col = 0; col < moduleCount; col++) {

    int sameCount = 0;
    BOOL dark = qrcode->isDark(row, col);
   
    for (int r = -1; r <= 1; r++) {

     if (row + r < 0 || moduleCount <= row + r) {
      continue;
     }

     for (int c = -1; c <= 1; c++) {

      if (col + c < 0 || moduleCount <= col + c) {
       continue;
      }

      if (r == 0 && c == 0) {
       continue;
      }

      if (dark == qrcode->isDark(row + r, col + c) ) {
       sameCount++;
      }
     }
    }

    if (sameCount > 5) {
     lostPoint += (3 + sameCount - 5);
    }
   }
  }

  // LEVEL2

  for ( row = 0; row < moduleCount - 1; row++) {
   for (int col = 0; col < moduleCount - 1; col++) {
    int count = 0;
    if (qrcode->isDark(row,     col    ) ) count++;
    if (qrcode->isDark(row + 1, col    ) ) count++;
    if (qrcode->isDark(row,     col + 1) ) count++;
    if (qrcode->isDark(row + 1, col + 1) ) count++;
    if (count == 0 || count == 4) {
     lostPoint += 3;
    }
   }
  }

  // LEVEL3

  for ( row = 0; row < moduleCount; row++) {
   for (int col = 0; col < moduleCount - 6; col++) {
    if (qrcode->isDark(row, col)
      && !qrcode->isDark(row, col + 1)
      &&  qrcode->isDark(row, col + 2)
      &&  qrcode->isDark(row, col + 3)
      &&  qrcode->isDark(row, col + 4)
      && !qrcode->isDark(row, col + 5)
      &&  qrcode->isDark(row, col + 6) ) {
     lostPoint += 40;
    }
   }
  }

  int col;
  for ( col = 0; col < moduleCount; col++) {
   for (int row = 0; row < moduleCount - 6; row++) {
    if (qrcode->isDark(row, col)
      && !qrcode->isDark(row + 1, col)
      &&  qrcode->isDark(row + 2, col)
      &&  qrcode->isDark(row + 3, col)
      &&  qrcode->isDark(row + 4, col)
      && !qrcode->isDark(row + 5, col)
      &&  qrcode->isDark(row + 6, col) ) {
     lostPoint += 40;
    }
   }
  }

  // LEVEL4
 
  int darkCount = 0;

  for ( col = 0; col < moduleCount; col++) {
   for (int row = 0; row < moduleCount; row++) {
    if (qrcode->isDark(row, col) ) {
     darkCount++;
    }
   }
  }
 
  int ratio = abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
  lostPoint += ratio * 10;
 
  return lostPoint; 
}

void CQrcode::setupPositionProbePattern(int row, int col)
{
 for (int r = -1; r <= 7; r++) {

  for (int c = -1; c <= 7; c++) {

   if (row + r <= -1 || moduleCount <= row + r
     || col + c <= -1 || moduleCount <= col + c) {
    continue;
   }
   
   if ( (0 <= r && r <= 6 && (c == 0 || c == 6) )
     || (0 <= c && c <= 6 && (r == 0 || r == 6) )
     || (2 <= r && r <= 4 && 2 <= c && c <= 4) ) {
    //modules[row + r][col + c] = new Boolean(true);
    modules[(row + r) * moduleCount + (col + c)] = 1; //01
   } else {
    //modules[row + r][col + c] = new Boolean(false);
    modules[(row + r) * moduleCount + (col + c)] = 2; //10
   }
  } 
 }
}

void CQrcode::setupPositionAdjustPattern()
{
 CUIntArray pos;

 // int[] pos = QRUtil.getPatternPosition(typeNumber);
 CQrcodeUtil::getPatternPosition(typeNumber, pos);
 int row,col;

 int pos_length = pos.GetSize();
 for (int i = 0; i < pos_length; i++)
 {
  for (int j = 0; j < pos_length; j++)
  {
   row = pos[i];
   col = pos[j];
  
   //if (modules[row][col] != null) {
   if (modules[row*moduleCount+col] != 0) {
    continue;
   }
  
   for (int r = -2; r <= 2; r++) {

    for (int c = -2; c <= 2; c++) {

     if (r == -2 || r == 2 || c == -2 || c == 2 || (r == 0 && c == 0) ) {
      //modules[row + r][col + c] = new Boolean(true);
      modules[(row+r)*moduleCount + col + c] = 1;//01
     } else {
      //modules[row + r][col + c] = new Boolean(false);
      modules[(row+r)*moduleCount + col + c] = 2;//10
     }
    }
   }

  }
 }
}

void CQrcode::setupTimingPattern()
{
 for (int r = 8; r < moduleCount - 8; r++) {
  //if (modules[r][6] != null) {
  if (modules[r*moduleCount + 6] != 0) {
   continue;
  }
  //modules[r][6] = new Boolean(r % 2 == 0);
  modules[r*moduleCount + 6] = (r % 2) == 0 ? 1 : 2;
 }
 for (int c = 8; c < moduleCount - 8; c++) {
  if (modules[6*moduleCount+ c] != 0) {
   continue;
  }
  //modules[6][c] = new Boolean(c % 2 == 0);
  modules[6*moduleCount+ c] = (c % 2) == 0 ? 1 : 2;
 }
}

void CQrcode::setupTypeInfo(BOOL test, int maskPattern)
{
  int data = (errorCorrectLevel << 3) | maskPattern;
  int bits = CQrcodeUtil::getBCHTypeInfo(data);

  BOOL mod = FALSE;
  int i;
  // 縦方向 
  for ( i = 0; i < 15; i++) {

   //Boolean mod = new Boolean(!test && ( (bits >> i) & 1) == 1);
   mod = FALSE;if (!test && ( (bits >> i) & 1) == 1) mod = TRUE;

   if (i < 6) {
    //modules[i][8] = mod;
    modules[i*moduleCount + 8] = mod ? 1:2;
   } else if (i < 8) {
    //modules[i + 1][8] = mod;
    modules[(i+1)*moduleCount + 8] = mod ? 1:2;
   } else {
    //modules[moduleCount - 15 + i][8] = mod;
    modules[(moduleCount - 15 + i)*moduleCount + 8] = mod ? 1:2;
   }
  }

  // 横方向
  for ( i = 0; i < 15; i++) {

   //Boolean mod = new Boolean(!test && ( (bits >> i) & 1) == 1);
   mod = FALSE;if (!test && ( (bits >> i) & 1) == 1) mod = TRUE;
  
   if (i < 8) {
    //modules[8][moduleCount - i - 1] = mod;
    modules[8*moduleCount + moduleCount - i - 1] = mod ? 1:2;
   } else if (i < 9) {
    //modules[8][15 - i - 1 + 1] = mod;
    modules[8*moduleCount + 15 - i - 1 + 1] = mod ? 1:2;
   } else {
    //modules[8][15 - i - 1] = mod;
    modules[8*moduleCount + 15 - i - 1] = mod ? 1:2;
   }
  }

  // 固定
  //modules[moduleCount - 8][8] = new Boolean(!test);
  modules[(moduleCount - 8)*moduleCount + 8] = !test ? 1:2;
}

void CQrcode::setupTypeNumber(BOOL test)
{
 int bits = CQrcodeUtil::getBCHTypeNumber(typeNumber);
 BOOL mod = FALSE;
 int i;
 for ( i = 0; i < 18; i++) {
  //Boolean mod = new Boolean(!test && ( (bits >> i) & 1) == 1);
  mod = FALSE;if (!test && ( (bits >> i) & 1) == 1) mod = TRUE;
  //modules[i / 3][i % 3 + moduleCount - 8 - 3] = mod;
  modules[(i/3)*moduleCount + i % 3 + moduleCount - 8 - 3] = mod ? 1:2;
 }

 for ( i = 0; i < 18; i++) {
  //Boolean mod = new Boolean(!test && ( (bits >> i) & 1) == 1);
  mod = FALSE;if (!test && ( (bits >> i) & 1) == 1) mod = TRUE;
  //modules[i % 3 + moduleCount - 8 - 3][i / 3] = mod;
  modules[(i % 3 + moduleCount - 8 - 3)*moduleCount + (i / 3)] = mod ? 1:2;
 }
}

 

BYTE* CQrcode::createData(int typeNumber, int errorCorrectLevel, CObArray &dataArray, int* bytesSize)
{
 //RSBlock[] rsBlocks = RSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
 CObArray rsBlocks;
 CQrcodeRSBlock::getRSBlocks(typeNumber, errorCorrectLevel, rsBlocks);
 int i;
 
 CQrcodeBitBuffer buffer;
 CQrcodeData *pqrdata = NULL;
 
 for ( i = 0; i < dataArray.GetSize(); i++) {
  pqrdata = (CQrcodeData *)dataArray.GetAt(i);
  buffer.put(pqrdata->getMode(), 4);
  buffer.put(pqrdata->getLength(), pqrdata->getLengthInBits(typeNumber) );
  pqrdata->write(buffer);
 }
 
 // 最大データ数を計算
 int totalDataCount = 0;
 CQrcodeRSBlock *pblock = NULL;
 for ( i = 0; i < rsBlocks.GetSize(); i++) {
  pblock = (CQrcodeRSBlock *)rsBlocks.GetAt(i);
  totalDataCount += pblock->getDataCount();
 }

 if (buffer.getLengthInBits() > totalDataCount * 8) {
  /*throw new IllegalArgumentException("code length overflow. ("
   + buffer.getLengthInBits()
   + ">"
   +  totalDataCount * 8
   + ")");
   */
  return NULL;
 }

 // 終端コード
 if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
  buffer.put(0, 4);
 }

 // padding
 while (buffer.getLengthInBits() % 8 != 0) {
  buffer.put(FALSE);
 }

 // padding
 while (TRUE) {
 
  if (buffer.getLengthInBits() >= totalDataCount * 8) {
   break;
  }
  buffer.put(PAD0, 8);
 
  if (buffer.getLengthInBits() >= totalDataCount * 8) {
   break;
  }
  buffer.put(PAD1, 8);
 }

 return createBytes(buffer, rsBlocks, bytesSize);
}

BYTE* CQrcode::createBytes(CQrcodeBitBuffer &buffer, CObArray &rsBlocks, int* bytesSize)
{
  int offset = 0;
  int i,r;
  int maxDcCount = 0;
  int maxEcCount = 0;
  int dcCount;
  int ecCount;
  CUIntArray *pint = NULL;
 
  CQrcode2DIntArray dcdata;
  CQrcode2DIntArray ecdata;
  int rsBlocks_length = rsBlocks.GetSize();
  CQrcodeRSBlock *pblock = NULL;
  for ( r = 0; r < rsBlocks_length; r++) {
   pblock = (CQrcodeRSBlock *)rsBlocks.GetAt(r);
   dcCount = pblock->getDataCount();
   ecCount = pblock->getTotalCount() - dcCount;

   maxDcCount = maxDcCount > dcCount ? maxDcCount:dcCount;
   maxEcCount = maxEcCount > ecCount ? maxEcCount:ecCount;
  
   for (i = 0; i < dcCount; i++) {
    dcdata.SetAt(r,i, 0xff & buffer.getBuffer()[i + offset]);
   }
   offset += dcCount;
  
   CQrcodePolynomial rsPoly = CQrcodeUtil::getErrorCorrectPolynomial(ecCount);
   pint = dcdata.GetIntArray(r);
   CQrcodePolynomial rawPoly((*pint), rsPoly.getLength() - 1);
   CQrcodePolynomial modPoly = rawPoly.mod(rsPoly);
   //
   for ( i = 0; i < (rsPoly.getLength() - 1); i++) {
    int modIndex = i + modPoly.getLength() - (rsPoly.getLength() - 1);
    ecdata.SetAt(r,i, (modIndex >= 0)? modPoly.get(modIndex) : 0);
   }

  }
 
 
  int totalCodeCount = 0;
  for ( i = 0; i < rsBlocks_length; i++) {
   pblock = (CQrcodeRSBlock *)rsBlocks.GetAt(i);
   totalCodeCount += pblock->getTotalCount();
  }

  BYTE* data = (BYTE*)malloc(totalCodeCount);
  memset(data, 0 , totalCodeCount);
  (*bytesSize) = totalCodeCount;

  int index = 0;
 
  for ( i = 0; i < maxDcCount; i++) {
   for ( r = 0; r < rsBlocks_length; r++) {
    pint = dcdata.GetIntArray(r);
    if (i < pint->GetSize()) {
     data[index++] = (BYTE)dcdata.GetAt(r,i);
    }
   }
  }

  for ( i = 0; i < maxEcCount; i++) {
   for ( r = 0; r < rsBlocks_length; r++) {
    pint = ecdata.GetIntArray(r);
    if (i < pint->GetSize()) {
     data[index++] = (BYTE)ecdata.GetAt(r,i);
    }
   }
  }
  return data;

}

void CQrcode::mapData(BYTE* bytes, int bytes_size, int maskPattern)
{
  int inc = -1;
  int row = moduleCount - 1;
  int bitIndex = 7;
  int byteIndex = 0;
 
  for (int col = moduleCount - 1; col > 0; col -= 2) {

   if (col == 6) col--;

   while (true) {
   
    for (int c = 0; c < 2; c++) {
    
     if (modules[row*moduleCount + col - c] == 0) {
     
      BOOL dark = FALSE;

      if (byteIndex < bytes_size) {
       dark = ( ( (bytes[byteIndex] >> bitIndex) & 1) == 1);
      }

      BOOL mask = CQrcodeUtil::getMask(maskPattern, row, col - c);

      if (mask) {
       dark = !dark;
      }
     
      modules[row*moduleCount + col - c] = dark ? 1:2;
      bitIndex--;

      if (bitIndex == -1) {
       byteIndex++;
       bitIndex = 7;
      }
     }
    }
       
    row += inc;

    if (row < 0 || moduleCount <= row) {
     row -= inc;
     inc = -inc;
     break;
    }
   }
  }
}

CQrcode* CQrcode::getMinimumQRCode(CString data, int errorCorrectLevel)
{
 int mode = CQrcodeUtil::getMode(data);

    CQrcode *qr = new CQrcode();
    qr->setErrorCorrectLevel(errorCorrectLevel);
    qr->addData(data, mode);

 CQrcodeData *pdata = (CQrcodeData *)qr->getData(0);
    int length = pdata->getLength();

 for (int typeNumber = 1; typeNumber <= 10; typeNumber++) {
        if (length <= CQrcodeUtil::getMaxLength(typeNumber, mode, errorCorrectLevel) ) {
            qr->setTypeNumber(typeNumber);
            break;
        }
  if (typeNumber==10) AfxMessageBox("数据太大了");
 }

    qr->make();

    return qr;
}

void CQrcode::Draw(CDC *pdc, int cellSize, int margin)
{
 int imageSize = getModuleCount() * cellSize + margin * 2;
 int row,col;
    for (int y = 0; y < imageSize; y++) {
        for (int x = 0; x < imageSize; x++) {
            if (margin <= x && x < imageSize - margin
                    && margin <= y && y < imageSize - margin) {
                       
                col = (x - margin) / cellSize;
                row = (y - margin) / cellSize;

                if (isDark(row, col) ) {
                    pdc->SetPixel(x, y, RGB(0,0,0));
                } else {
                    pdc->SetPixel(x, y, RGB(255,255,255));
                }

            } else {
                pdc->SetPixel(x, y, RGB(255,255,255));
            }
        }
    }

}

typedef struct _T_PIXEL
 {
     BYTE b; //代表blue
     BYTE g; //代表green
     BYTE r; //代表red
 }T_PIXEL;

void CQrcode::SaveToBmp(CString filename, int cellSize, int margin)
{
 BITMAPFILEHEADER BMPHeader; //BMP文件头
 BITMAPINFO BMPInfo; //BMP信息块
 BITMAPINFOHEADER BMPInfoHeader; //BMP信息头(即包含在BMP信息块的 信息头)
 //RGBQUAD BMPRgbQuad; //BMP色彩表(即包含在BMP信息块的色彩表)
 CFile BMPFile;
 if (!BMPFile.Open(filename,CFile::modeCreate|CFile::modeWrite)) //创建BMP文件
 {
  AfxMessageBox("无法创建文件"+filename);
  return;
 }

 //SetBMPFileHeader
 int imageSize = getModuleCount() * cellSize + margin * 2;
 BMPHeader.bfType=0x4D42;
 BMPHeader.bfSize=3*imageSize*imageSize+0x36; //指示 整个BMP文件字节数,其中0x36是文件头本身的长度
 BMPHeader.bfReserved1=0x0;
 BMPHeader.bfReserved2=0x0;
 BMPHeader.bfOffBits=0x36; //x36是文件头本身的长度
 //以上共占据14个字节
 BMPInfoHeader.biSize=sizeof(BITMAPINFOHEADER); //指示 文件信息头大小
 BMPInfoHeader.biWidth=imageSize; //图片宽度
 BMPInfoHeader.biHeight=imageSize; //图片高度
 BMPInfoHeader.biPlanes=1;
 BMPInfoHeader.biBitCount=24; //图片位数,位24位图
 //以上共占据14+16个字节
 BMPInfoHeader.biCompression=0; //表示没有压缩
 BMPInfoHeader.biSizeImage=0x30; //因为没有压缩,所以可以设置为0
 BMPInfoHeader.biXPelsPerMeter=0x0;
 BMPInfoHeader.biYPelsPerMeter=0x0;
 BMPInfoHeader.biClrUsed=0; //表明使用所有索引色
 BMPInfoHeader.biClrImportant=0; //说明对图象显示有重要影响的颜色索引的数目,0表示都重要。
 //以上共占据14+16+24个字节

 BMPInfo.bmiHeader=BMPInfoHeader;

 BMPFile.Write(&(BMPHeader),sizeof(BMPHeader));
 BMPFile.Write(&BMPInfoHeader,sizeof(BMPInfo)-sizeof(RGBQUAD));
 //

 T_PIXEL p;
 int row,col;
 for (int y = imageSize; y >= 0 ; y--) {
  for (int x = 0; x < imageSize; x++) {
   if (margin <= x && x < imageSize - margin
     && margin <= y && y < imageSize - margin) {
                   
    col = (x - margin) / cellSize;
    row = (y - margin) / cellSize;

    if (isDark(row, col) ) {
     p.b = 0; p.g = 0; p.r = 0;
    } else {
     p.b = 255; p.g = 255; p.r = 255;
    }

   } else {
    p.b = 255; p.g = 255; p.r = 255;
   }
   BMPFile.Write(&p, sizeof(T_PIXEL));
  }
 }
 //
 BMPFile.Flush();
 BMPFile.Close();
}