www.pudn.com > QRAPPuie.rar > QRapi.cpp


/********************************************************************************  
 *  QRAPI.cpp 
 *  
 *  Source file for QR code image processing API.  Provides  
 *  function realization for QR  image processing  
 * 
 *AUTHOR: Song Shaojing 
 * 
 *DATE:   2005.12.06 
 * 
 ********************************************************************************/  
#include "stdafx.h" 
#include "QRapi.h"  
 
#include   
#include   
#include   
//#include   
//#include   
#include   
#include   
#include   
#include   
#include   
 
HGLOBAL hIndexData=NULL; 
HGLOBAL hMaskImg=NULL; 
HGLOBAL hMarkImage=NULL; 
HGLOBAL hOriginalCode=NULL; 
HGLOBAL hDecodeData=NULL; 
// local use macro 
 
ORIENTATIONCENTER TopLeft={0,0}; 
ORIENTATIONCENTER TopRight={0,0}; 
ORIENTATIONCENTER BottomLeft={0,0}; 
 
unsigned char ReviseImgPos[8];//[5] is the number of coordinate.  
 
 
// The following kernel definitions are for convolution filtering. 
// Kernel entries are specified with a divisor to get around the 
// requirement for floating point numbers in the low pass filters. 
 
 
QRKERNEL QRHP1 = {                    // HP filter #1 
  {-1, -1, -1, 
   -1,  9, -1, 
   -1, -1, -1}, 
    1                             // Divisor = 1 
}; 
 
QRKERNEL QRHP2 = {                    // HP filter #2 
  { 0, -1,  0, 
   -1,  5, -1, 
    0, -1,  0}, 
    1                             // Divisor = 1 
}; 
 
QRKERNEL QRHP3 = {                    // HP filter #3 
  { 1, -2,  1, 
   -2,  5, -2, 
    1, -2,  1}, 
    1                             // Divisor = 1 
}; 
 
QRKERNEL QRLP1 = {                    // LP filter #1 
  { 1,  1,  1, 
    1,  1,  1, 
    1,  1,  1}, 
    9                             // Divisor = 9 
}; 
 
QRKERNEL QRLP2 = {                    // LP filter #2 
  { 1,  1,  1, 
    1,  2,  1, 
    1,  1,  1}, 
    10                            // Divisor = 10 
}; 
 
QRKERNEL QRLP3 = {                    // LP filter #3 
  { 1,  2,  1, 
    2,  4,  2, 
    1,  2,  1}, 
    16                            // Divisor = 16 
}; 
 
QRKERNEL QRVertEdge = {              // Vertical edge 
  { 0,  0,  0, 
    -1, 1,  0, 
    0,  0,  0}, 
    1                             // Divisor = 1 
}; 
 
QRKERNEL QRHorzEdge = {              // Horizontal edge 
  { 0,  -1,  0, 
    0,  1,  0, 
    0,  0,  0}, 
    1                             // Divisor = 1 
}; 
 
QRKERNEL QRVertHorzEdge = {           // Vertical Horizontal edge 
  { -1, 0,  0, 
    0,  1,  0, 
    0,  0,  0}, 
    1                             // Divisor = 1 
}; 
 
QRKERNEL QREdgeNorth = {              // North gradient 
  { 1,  1,  1, 
    1, -2,  1, 
   -1, -1, -1}, 
    1                             // Divisor = 1 
}; 
 
QRKERNEL QREdgeNorthEast = {          // North East gradient 
  { 1,  1,  1, 
   -1, -2,  1, 
   -1, -1,  1}, 
    1                             // Divisor = 1 
}; 
 
QRKERNEL QREdgeEast = {               // East gradient 
  {-1,  1,  1, 
   -1, -2,  1, 
   -1,  1,  1}, 
    1                             // Divisor = 1 
}; 
 
QRKERNEL QREdgeSouthEast = {          // South East gradient 
  {-1, -1,  1, 
   -1, -2,  1, 
    1,  1,  1}, 
    1                             // Divisor = 1 
}; 
 
QRKERNEL QREdgeSouth = {              // South gadient 
  {-1, -1, -1, 
    1, -2,  1, 
    1,  1,  1}, 
    1                             // Divisor = 1 
}; 
 
QRKERNEL QREdgeSouthWest = {          // South West gradient 
  { 1, -1, -1, 
    1, -2, -1, 
    1,  1,  1}, 
    1                             // Divisor = 1 
}; 
 
QRKERNEL QREdgeWest = {               // West gradient 
  { 1,  1, -1, 
    1, -2, -1, 
    1,  1, -1}, 
    1                             // Divisor = 1 
}; 
 
QRKERNEL QREdgeNorthWest = {          // North West gradient 
  { 1,  1,  1, 
    1, -2, -1, 
    1, -1, -1}, 
    1                             // Divisor = 1 
}; 
 
QRKERNEL QRLap1 = {					  // Laplace filter 1 
  { 0,  1,  0, 
    1, -4,  1, 
    0,  1,  0}, 
    1                             // Divisor = 1 
}; 
 
QRKERNEL QRLap2 = {					  // Laplace filter 2 
  { -1, -1, -1, 
    -1,  8, -1, 
    -1, -1, -1}, 
    1                             // Divisor = 1 
}; 
 
QRKERNEL QRLap3 = {					  // Laplace filter 3 
  { -1, -1, -1, 
    -1,  9, -1, 
    -1, -1, -1}, 
    1                             // Divisor = 1 
}; 
 
QRKERNEL QRLap4 = {					  // Laplace filter 4 
  { 1, -2, 1, 
    -2, 4, -2, 
    1, -2, 1}, 
    1                             // Divisor = 1 
}; 
 
QRKERNEL QRSobel[4] = { 
	{                    // Sobel1 
		{-1, 0, 1, 
		 -2, 0, 2, 
		 -1, 0, 1}, 
		1                             // Divisor = 1 
	}, 
	{                    // Sobel2 
		{-1, -2, -1, 
		  0,  0,  0, 
		  1,  2,  1}, 
		1                             // Divisor = 1 
	}, 
	{                    // Sobel3 
		{-2, -1, 0, 
		 -1,  0, 1, 
		  0,  1, 2}, 
		1                             // Divisor = 1 
	}, 
	{                    // Sobel4 
		{0, -1, -2, 
		 1,  0, -1, 
		 2,  1, 0}, 
		1                             // Divisor = 1 
	} 
}; 
 
QRKERNEL QRHough[4] = { 
	{                    // Hough1 
		{-1, 0, 1, 
		 -1, 0, 1, 
		 -1, 0, 1}, 
		1                             // Divisor = 1 
	}, 
	{                    // Hough2 
		{-1, -1, 0, 
		 -1,  0, 1, 
		  0,  1, 1}, 
		1                             // Divisor = 1 
	}, 
	{                    // Hough3 
		{-1, -1, -1, 
		  0,  0, 0, 
		  1,  1, 1}, 
		1                             // Divisor = 1 
	}, 
	{                    // Hough4 
		{0, -1, -1, 
		 1,  0, -1, 
		 1,  1, 0}, 
		1                             // Divisor = 1 
	} 
}; 
 
// function body 
 
/*************************************************************************  
 *  
 * HighPassDIB()  
 *  
 * Parameters:  
 *  
 * HQRIMG hDib        - objective DIB handle 
 * int nAlgorithm   - specify the filter to use 
 * int Strength     - operation strength set to the convolute 
 *  
 * Return Value:  
 *  
 * BOOL             - True is success, else False 
 *  
 * Description:  
 *  
 * High pass filtering to sharp DIB 
 *  
 ************************************************************************/  
BOOL HighPassQR(HQRIMG hDib, int Strength, int nAlgorithm)  
{ 
	switch (nAlgorithm) 
	{ 
	case QRFILTER1: 
		return ConvoluteQR(hDib, &QRHP1, Strength); 
	case QRFILTER2: 
		return ConvoluteQR(hDib, &QRHP2, Strength); 
	case QRFILTER3: 
		return ConvoluteQR(hDib, &QRHP3, Strength); 
	} 
 
	return FALSE; 
} 
 
/*************************************************************************  
 *  
 * LowPassDIB()  
 *  
 * Parameters:  
 *  
 * HQRIMG hDib        - objective DIB handle 
 * int nAlgorithm   - specify the filter to use 
 * int Strength     - operation strength set to the convolute 
 *  
 * Return Value:  
 *  
 * BOOL             - True is success, else False 
 *  
 * Description:  
 *  
 * Low pass filtering to blur DIB 
 *  
 ************************************************************************/  
BOOL LowPassQR(HQRIMG hDib, int Strength, int nAlgorithm)  
{ 
	switch (nAlgorithm) 
	{ 
	case QRFILTER1: 
		return ConvoluteQR(hDib, &QRLP1, Strength); 
	case QRFILTER2: 
		return ConvoluteQR(hDib, &QRLP2, Strength); 
	case QRFILTER3: 
		return ConvoluteQR(hDib, &QRLP3, Strength); 
	} 
 
	return FALSE; 
} 
 
/*************************************************************************  
 *  
 * EdgeEnhanceDIB()  
 *  
 * Parameters:  
 *  
 * HQRIMG hDib        - objective DIB handle 
 * int nAlgorithm   - specify the filter to use 
 * int Strength     - operation strength set to the convolute 
 *  
 * Return Value:  
 *  
 * BOOL             - True is success, else False 
 *  
 * Description:  
 *  
 * Edge enhance DIB 
 *  
 ************************************************************************/  
BOOL EdgeEnhanceQR(HQRIMG hDib, int Strength, int nAlgorithm) 
{ 
	switch (nAlgorithm) 
	{ 
	case QRVERT: 
		return ConvoluteQR(hDib, &QRVertEdge, Strength); 
	case QRHORZ: 
		return ConvoluteQR(hDib, &QRHorzEdge, Strength); 
	case QRVERTHORZ: 
		return ConvoluteQR(hDib, &QRVertHorzEdge, Strength); 
	case QRNORTH: 
		return ConvoluteQR(hDib, &QREdgeNorth, Strength); 
	case QRNORTHEAST: 
		return ConvoluteQR(hDib, &QREdgeNorthEast, Strength); 
	case QREAST: 
		return ConvoluteQR(hDib, &QREdgeEast, Strength); 
	case QRSOUTH: 
		return ConvoluteQR(hDib, &QREdgeSouth, Strength); 
	case QRSOUTHEAST: 
		return ConvoluteQR(hDib, &QREdgeSouthEast, Strength); 
	case QRSOUTHWEST: 
		return ConvoluteQR(hDib, &QREdgeSouthWest, Strength); 
	case QRWEST: 
		return ConvoluteQR(hDib, &QREdgeWest, Strength); 
	case QRNORTHWEST: 
		return ConvoluteQR(hDib, &QREdgeNorthWest, Strength); 
	case QRLAP1: 
		return ConvoluteQR(hDib, &QRLap1, Strength); 
	case QRLAP2: 
		return ConvoluteQR(hDib, &QRLap2, Strength); 
	case QRLAP3: 
		return ConvoluteQR(hDib, &QRLap3, Strength); 
	case QRLAP4: 
		return ConvoluteQR(hDib, &QRLap4, Strength); 
	case QRSOBEL: 
		return ConvoluteQR(hDib, QRSobel, Strength, 4); 
	case QRHOUGH: 
		return ConvoluteQR(hDib, QRHough, Strength, 4); 
	} 
 
	return FALSE; 
} 
 
/*************************************************************************  
 *  
 * MedianFilterDIB()  
 *  
 * Parameters:  
 *  
 * HQRIMG hDib        - objective DIB handle 
 *  
 * Return Value:  
 *  
 * BOOL             - True is success, else False 
 *  
 * Description:  
 *  
 * This is the media filtering function to DIB 
 *  
 ************************************************************************/  
BOOL MedianFilterQR(HQRIMG hDib)  
{ 
	QRWaitCursorBegin(); 
 
	HQRIMG hNewDib = NULL; 
	// we only convolute 24bpp DIB, so first convert DIB to 24bpp 
	WORD wBitCount = QRBitCount(hDib); 
	if (wBitCount != 24) 
		return FALSE; 
		//hNewDib = ConvertDIBFormat(hDib, 24, NULL); 
	else 
		hNewDib = CopyQRHandle(hDib); 
 
	if (! hNewDib) 
	{ 
		QRWaitCursorEnd(); 
		return FALSE; 
	} 
 
	// new DIB attributes 
	WORD wDIBWidth = (WORD)QRWidth(hNewDib); 
	WORD wDIBHeight = (WORD)QRHeight(hNewDib); 
	WORD wBytesPerLine = (WORD)QRBytesPerLine(hNewDib); 
	DWORD dwImageSize = wBytesPerLine * wDIBHeight; 
 
	// Allocate and lock memory for filtered image data 
	HGLOBAL hFilteredBits = GlobalAlloc(GHND, dwImageSize); 
	if (!hFilteredBits)  
	{ 
		QRWaitCursorEnd(); 
		return FALSE; 
	} 
	LPBYTE lpDestImage = (LPBYTE)GlobalLock(hFilteredBits); 
 
	// get bits address in DIB 
	LPBYTE lpDIB = (LPBYTE)GlobalLock(hNewDib); 
	LPBYTE lpDIBits = FindQRBits(lpDIB); 
 
	// convolute... 
	for (int i=1; i red) 
					red = r; 
				if (g > green) 
					green = g; 
				if (b > blue) 
					blue = b; 
				//red += r; green += g; blue += b; 
			} 
 
			// original RGB value in center pixel  (j, i) 
			LONG lOffset= PIXEL_OFFSET(i,j, wBytesPerLine); 
			BYTE OldB = *(lpDIBits + lOffset++); 
			BYTE OldG = *(lpDIBits + lOffset++); 
			BYTE OldR = *(lpDIBits + lOffset); 
			// When we get here, red, green and blue have the new RGB value. 
			if (Strength != 10)  
			{ 
				// Interpolate pixel data 
				red   = OldR + (((red - OldR) * Strength) / 10); 
				green = OldG + (((green - OldG) * Strength) / 10); 
				blue  = OldB + (((blue - OldB) * Strength) / 10); 
			} 
 
			lOffset= PIXEL_OFFSET(i,j, wBytesPerLine); 
			*(lpDestImage + lOffset++) = QRBOUND(blue, 0, 255); 
			*(lpDestImage + lOffset++) = QRBOUND(green, 0, 255); 
			*(lpDestImage + lOffset)   = QRBOUND(red, 0, 255); 
		} 
 
	// a filtered image is available in lpDestImage 
	// copy it to DIB bits 
	memcpy(lpDIBits, lpDestImage, dwImageSize); 
 
	// cleanup temp buffers 
	GlobalUnlock(hFilteredBits); 
	GlobalFree(hFilteredBits); 
	GlobalUnlock(hNewDib); 
 
	// rebuild hDib 
	HQRIMG hTmp = NULL; 
	if (wBitCount != 24) 
		//if image is not 24bpp ,return 
		return FALSE; 
		//hTmp = ConvertDIBFormat(hNewDib, wBitCount, NULL); 
	else 
		hTmp = CopyQRHandle(hNewDib); 
	GlobalFree(hNewDib); 
	DWORD dwSize = GlobalSize(hTmp); 
	memcpy((LPBYTE)GlobalLock(hDib), (LPBYTE)GlobalLock(hTmp), dwSize); 
	GlobalUnlock(hTmp); 
	GlobalFree(hTmp); 
	GlobalUnlock(hDib); 
	QRWaitCursorEnd(); 
 
	return TRUE; 
} 
 
// local function: perform convolution to DIB with a kernel 
void DoConvoluteQR(int *red, int *green, int *blue, int i, int j,  
			WORD wBytesPerLine, LPBYTE lpDIBits, QRKERNEL *lpKernel) 
{ 
	BYTE b[9], g[9], r[9]; 
	LONG lOffset; 
	 
	lOffset= PIXEL_OFFSET(i-1,j-1, wBytesPerLine); 
	b[0] = *(lpDIBits + lOffset++); 
	g[0] = *(lpDIBits + lOffset++); 
	r[0] = *(lpDIBits + lOffset); 
 
	lOffset= PIXEL_OFFSET(i-1,j, wBytesPerLine); 
	b[1] = *(lpDIBits + lOffset++); 
	g[1] = *(lpDIBits + lOffset++); 
	r[1] = *(lpDIBits + lOffset); 
 
	lOffset= PIXEL_OFFSET(i-1,j+1, wBytesPerLine); 
	b[2] = *(lpDIBits + lOffset++); 
	g[2] = *(lpDIBits + lOffset++); 
	r[2] = *(lpDIBits + lOffset); 
 
	lOffset= PIXEL_OFFSET(i,j-1, wBytesPerLine); 
	b[3] = *(lpDIBits + lOffset++); 
	g[3] = *(lpDIBits + lOffset++); 
	r[3] = *(lpDIBits + lOffset); 
 
	lOffset= PIXEL_OFFSET(i,j, wBytesPerLine); 
	b[4] = *(lpDIBits + lOffset++); 
	g[4] = *(lpDIBits + lOffset++); 
	r[4] = *(lpDIBits + lOffset); 
 
	lOffset= PIXEL_OFFSET(i,j+1, wBytesPerLine); 
	b[5] = *(lpDIBits + lOffset++); 
	g[5] = *(lpDIBits + lOffset++); 
	r[5] = *(lpDIBits + lOffset); 
 
	lOffset= PIXEL_OFFSET(i+1,j-1, wBytesPerLine); 
	b[6] = *(lpDIBits + lOffset++); 
	g[6] = *(lpDIBits + lOffset++); 
	r[6] = *(lpDIBits + lOffset); 
 
	lOffset= PIXEL_OFFSET(i+1,j, wBytesPerLine); 
	b[7] = *(lpDIBits + lOffset++); 
	g[7] = *(lpDIBits + lOffset++); 
	r[7] = *(lpDIBits + lOffset); 
 
	lOffset= PIXEL_OFFSET(i+1,j+1, wBytesPerLine); 
	b[8] = *(lpDIBits + lOffset++); 
	g[8] = *(lpDIBits + lOffset++); 
	r[8] = *(lpDIBits + lOffset); 
 
	*red = *green = *blue = 0; 
	for (int k=0; k<8; ++k) 
	{ 
		*red   += lpKernel->Element[k]*r[k]; 
		*green += lpKernel->Element[k]*g[k]; 
		*blue  += lpKernel->Element[k]*b[k]; 
	} 
 
	if (lpKernel->Divisor != 1)  
	{ 
		*red   /= lpKernel->Divisor; 
		*green /= lpKernel->Divisor; 
		*blue  /= lpKernel->Divisor; 
	} 
} 
 
 
// function used to sort in the call of qsort 
int QRcompare(const void *e1, const void *e2) 
{ 
	if (*(BYTE *)e1 < *(BYTE *)e2) 
		return -1; 
	if (*(BYTE *)e1 > *(BYTE *)e2) 
		return 1; 
 
	return 0; 
} 
 
 
WORD QRBitCount(LPBYTE lpDIB)  
{  
    if (IS_WIN30_QR(lpDIB))  
        return ((LPBITMAPINFOHEADER)lpDIB)->biBitCount;  
    else  
        return ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;  
}  
 
WORD QRBitCount(HQRIMG hDIB)  
{  
	LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB); 
	WORD wSize = QRBitCount(lpDIB); 
	GlobalUnlock(hDIB); 
	return wSize; 
}  
/*************************************************************************  
 *  
 * CopyHandle()  
 *  
 * Parameters:  
 *  
 * HANDLE h         - source handle 
 *  
 * Return Value:  
 *  
 * HANDLE           - duplicated handle 
 *  
 * Description:  
 *  
 * Copy memory handle to another 
 ************************************************************************/  
 
HANDLE CopyQRHandle(HANDLE h) 
{ 
	if (h == NULL) 
		return NULL; 
 
	DWORD  dwLen = GlobalSize((HGLOBAL)h); 
	HANDLE hCopy = GlobalAlloc(GHND, dwLen); 
	if (hCopy == NULL) 
		return NULL; 
 
	void* lpCopy = GlobalLock((HGLOBAL) hCopy); 
	void* lp     = GlobalLock((HGLOBAL) h); 
	CopyMemory(lpCopy, lp, dwLen); 
	GlobalUnlock(hCopy); 
	GlobalUnlock(h); 
 
	return hCopy; 
} 
 
/*************************************************************************  
 *  
 * DIBWidth()  
 *  
 * Parameter:  
 *  
 * LPBYTE lpDIB      - pointer to packed-DIB memory block  
 *  
 * Return Value:  
 *  
 * DWORD            - width of the DIB  
 *  
 * Description:  
 *  
 * This function gets the width of the DIB from the BITMAPINFOHEADER  
 * width field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER  
 * width field if it is an OS/2-style DIB.  
 *  
 ************************************************************************/  
DWORD QRWidth(LPBYTE lpDIB)  
{  
    LPBITMAPINFOHEADER   lpbmi;  // pointer to a Win 3.0-style DIB  
    LPBITMAPCOREHEADER   lpbmc;  // pointer to an OS/2-style DIB  
  
    // point to the header (whether Win 3.0 and OS/2)  
  
    lpbmi = (LPBITMAPINFOHEADER)lpDIB;  
    lpbmc = (LPBITMAPCOREHEADER)lpDIB;  
  
    // return the DIB width if it is a Win 3.0 DIB  
  
    if (lpbmi->biSize == sizeof(BITMAPINFOHEADER))  
        return lpbmi->biWidth;  
    else  // it is an OS/2 DIB, so return its width  
        return (DWORD)lpbmc->bcWidth;  
}  
  
DWORD QRWidth(HQRIMG hDIB)  
{  
	LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB); 
	DWORD dw = QRWidth(lpDIB); 
	GlobalUnlock(hDIB); 
	return dw; 
}  
  
/*************************************************************************  
 *  
 * DIBHeight()  
 *  
 * Parameter:  
 *  
 * LPBYTE lpDIB      - pointer to packed-DIB memory block  
 *  
 * Return Value:  
 *  
 * DWORD            - height of the DIB  
 *  
 * Description:  
 *  
 * This function gets the height of the DIB from the BITMAPINFOHEADER  
 * height field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER  
 * height field if it is an OS/2-style DIB.  
 *  
 ************************************************************************/  
DWORD QRHeight(LPBYTE lpDIB)  
{  
   LPBITMAPINFOHEADER   lpbmi;  // pointer to a Win 3.0-style DIB  
   LPBITMAPCOREHEADER   lpbmc;  // pointer to an OS/2-style DIB  
  
   // point to the header (whether OS/2 or Win 3.0  
  
   lpbmi = (LPBITMAPINFOHEADER)lpDIB;  
   lpbmc = (LPBITMAPCOREHEADER)lpDIB;  
  
    // return the DIB height if it is a Win 3.0 DIB  
    if (lpbmi->biSize == sizeof(BITMAPINFOHEADER))  
        return lpbmi->biHeight;  
    else  // it is an OS/2 DIB, so return its height  
        return (DWORD)lpbmc->bcHeight;  
}  
  
DWORD QRHeight(HQRIMG hDIB)  
{  
	LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB); 
	DWORD dw = QRHeight(lpDIB); 
	GlobalUnlock(hDIB); 
	return dw; 
}  
  
/****************************************************************************  
*  
*     FUNCTION: BytesPerLine  
*  
*     PURPOSE:  Calculates the number of bytes in one scan line.  
*  
*     PARAMS:   LPBYTE lpDIB - pointer to the BITMAPINFOHEADER  
                              that begins the CF_DIB block  
*  
*     RETURNS:  DWORD - number of bytes in one scan line (DWORD aligned)  
*  
\****************************************************************************/  
DWORD QRBytesPerLine(LPBYTE lpDIB)  
{  
    return QRWIDTHBYTES(((LPBITMAPINFOHEADER)lpDIB)->biWidth * ((LPBITMAPINFOHEADER)lpDIB)->biPlanes * ((LPBITMAPINFOHEADER)lpDIB)->biBitCount);  
}  
 
DWORD QRBytesPerLine(HQRIMG hDIB)  
{  
	LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB); 
	DWORD dw = QRBytesPerLine(lpDIB); 
	GlobalUnlock(hDIB); 
	return dw; 
}  
 
/*************************************************************************  
 *  
 * FindDIBBits()  
 *  
 * Parameter:  
 *  
 * LPBYTE lpDIB      - pointer to packed-DIB memory block  
 *  
 * Return Value:  
 *  
 * LPBYTE            - pointer to the DIB bits  
 *  
 * Description:  
 *  
 * This function calculates the address of the DIB's bits and returns a  
 * pointer to the DIB bits.  
 *  
 ************************************************************************/  
LPBYTE FindQRBits(LPBYTE lpDIB)  
{  
   return (lpDIB + *(LPDWORD)lpDIB + QRPaletteSize(lpDIB));  
}  
 
/*************************************************************************  
 *  
 * PaletteSize()  
 *  
 * Parameter:  
 *  
 * LPBYTE lpDIB      - pointer to packed-DIB memory block  
 *  
 * Return Value:  
 *  
 * WORD             - size of the color palette of the DIB  
 *  
 * Description:  
 *  
 * This function gets the size required to store the DIB's palette by  
 * multiplying the number of colors by the size of an RGBQUAD (for a  
 * Windows 3.0-style DIB) or by the size of an RGBTRIPLE (for an OS/2-  
 * style DIB).  
 *  
 ************************************************************************/  
WORD QRPaletteSize(LPBYTE lpDIB)  
{  
    // calculate the size required by the palette  
    if (IS_WIN30_QR (lpDIB))  
        return (QRNumColors(lpDIB) * sizeof(RGBQUAD));  
    else  
        return (QRNumColors(lpDIB) * sizeof(RGBTRIPLE));  
}  
  
WORD QRPaletteSize(HQRIMG hDIB)  
{  
	LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB); 
	WORD wSize = QRPaletteSize(lpDIB); 
	GlobalUnlock(hDIB); 
	return wSize; 
}  
  
/*************************************************************************  
 *  
 * DIBNumColors()  
 *  
 * Parameter:  
 *  
 * LPBYTE lpDIB      - pointer to packed-DIB memory block  
 *  
 * Return Value:  
 *  
 * WORD             - number of colors in the color table  
 *  
 * Description:  
 *  
 * This function calculates the number of colors in the DIB's color table  
 * by finding the bits per pixel for the DIB (whether Win3.0 or OS/2-style  
 * DIB). If bits per pixel is 1: colors=2, if 4: colors=16, if 8: colors=256,  
 * if 24, no colors in color table.  
 *  
 ************************************************************************/  
WORD QRNumColors(LPBYTE lpDIB)  
{  
    WORD wBitCount;  // DIB bit count  
  
    // If this is a Windows-style DIB, the number of colors in the  
    // color table can be less than the number of bits per pixel  
    // allows for (i.e. lpbi->biClrUsed can be set to some value).  
    // If this is the case, return the appropriate value.  
      
  
    if (IS_WIN30_QR(lpDIB))  
    {  
        DWORD dwClrUsed;  
  
        dwClrUsed = ((LPBITMAPINFOHEADER)lpDIB)->biClrUsed;  
        if (dwClrUsed)  
  
        return (WORD)dwClrUsed;  
    }  
  
    // Calculate the number of colors in the color table based on  
    // the number of bits per pixel for the DIB.  
      
    if (IS_WIN30_QR(lpDIB))  
        wBitCount = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount;  
    else  
        wBitCount = ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;  
  
    // return number of colors based on bits per pixel  
  
    switch (wBitCount)  
    {  
        case 1:  
            return 2;  
  
        case 4:  
            return 16;  
  
        case 8:  
            return 256;  
  
        default:  
            return 0;  
    }  
}  
 
WORD QRNumColors(HQRIMG hDIB)  
{  
	LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB); 
	WORD wSize = QRNumColors(lpDIB); 
	GlobalUnlock(hDIB); 
	return wSize; 
}  
  
  
/****************************************************************************  
*  
*     FUNCTION: QRBlockSize  
*  
*     PURPOSE:  Calculates the number of bytes in one scan line.  
*  
*     PARAMS:   LPBYTE lpDIB - pointer to the BITMAPINFOHEADER  
                              that begins the CF_DIB block  
*  
*     RETURNS:  DWORD - DIB block size 
*  
\****************************************************************************/  
DWORD QRBlockSize(LPBYTE lpDIB) 
{ 
	if (((LPBITMAPINFOHEADER)lpDIB)->biSizeImage == 0) 
		((LPBITMAPINFOHEADER)lpDIB)->biSizeImage = QRBytesPerLine(lpDIB) * ((LPBITMAPINFOHEADER)lpDIB)->biHeight; 
	return ((LPBITMAPINFOHEADER)lpDIB)->biSize + QRPaletteSize(lpDIB) + ((LPBITMAPINFOHEADER)lpDIB)->biSizeImage; 
} 
 
DWORD QRBlockSize(HQRIMG hDIB)  
{  
	LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB); 
	DWORD dw = QRBlockSize(lpDIB); 
	GlobalUnlock(hDIB); 
	return dw; 
}  
/******************************************************************** 
 * 
 * void Histogram(long *Graytable) 
 * 
 *Parameters: 
 * 
 * long *Graytable		-	pointer to an array for the statistic data of every gray level  
 * 
 *Discription: 
 * This function calculate the histogram  of the gray QR image 
 * 
 ********************************************************************/ 
 void Histogram(HQRIMG hDib,long * GrayTable,long *DifGrayTable) 
 { 
	DWORD				 BufSize,LineBytes,BitCounts; 
	LPBITMAPINFOHEADER  	 lpImgData,SrcBi; 
	LPSTR				 lpPtr; 
	int				   	 x,y,m,n; 
	int          				 grayindex; 
//	HQRIMG				 hDifImg=NULL; 
	int					 TempValue,TempGray,Center; 
	int					 MaxValue=0; 
	 
	for(grayindex=0;grayindex<256;grayindex++) 
	{ 
		GrayTable[grayindex]=0; 
		DifGrayTable[grayindex]=0; 
	} 
		 
	BufSize=QRBlockSize(hDib);	 
	BitCounts=QRBitCount(hDib); 
	SrcBi=(LPBITMAPINFOHEADER)GlobalLock(hDib); 
	LineBytes=(DWORD)QRWIDTHBYTES(SrcBi->biWidth*BitCounts); 
	 
//	hDifImg=CopyQRHandle(hDib); 
	lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hDib); 
	//lpDifImgData=(LPBITMAPINFOHEADER)GlobalLock(hDifImg); 
	for(y=0;ybiHeight;y++) 
	{ 
		lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes); 
		for(x=0;xbiWidth;x++) 
		{ 
			//to get histogram data of the differential image 
			if(0biWidth-1 && 0biHeight-1) 
			{ 
				Center=(unsigned char)*lpPtr; 
				for(m=0;m<3;m++) 
					for(n=0;n<3;n++) 
					{ 
						TempValue=(unsigned char)*(lpPtr+(m-1)*LineBytes+n); 
						TempGray=QRABS(Center,TempValue); 
						if(TempGray>MaxValue) 
							MaxValue=TempGray; 
					} 
				DifGrayTable[MaxValue]++; 
			} 
			grayindex=(unsigned char)*(lpPtr++); 
			GrayTable[grayindex]++; 
		} 
	} 
	GlobalUnlock(hDib); 
//	GlobalUnlock(hDifImg); 
 } 
	// to get the differential image data and get the Histogram data of differential image 
	/* 
	for(y=1;ybiHeight-1;y++) 
	{ 
		lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes); 
		lpDifPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes); 
		for(x=1;xbiWidth-1;x++) 
		{ 
			for(m=0;m<3;m++) 
				for(n=0;n<3;n++) 
				{ 
 
				} 
			TempValue=DoDifferential(lpPtr++,LineBytes); 
			DifGrayTable[TempValue]++; 
		} 
	} 
	*/ 
  
/*  
 unsigned char DoDifferential(LPSTR lpPtr,DWORD LineBytes) 
 { 
 		unsigned char TemValue; 
 		unsigned char MaxValue=0; 
 		int x,y; 
 		for(x=0;x<3;x++) 
 			for(y=0;y<3;y++) 
 			{ 
 				TemValue=QRABS((lpPtr+(x-1)*LineBytes+y),lpPtr); 
 				if(TemValue>MaxValue) 
 							MaxValue=TemValue; 
 			} 
  return MaxValue;	 
   
 } 
 */ 
 int QRABS(int str1,int str2) 
 { 
	int Value; 
	if(str1>=str2) 
		Value=str1-str2; 
	else 
		Value=str2-str1; 
 
	return Value; 
} 
/******************************************************************** 
 * 
 * int Erzhihua() 
 * 
 *Parameters: 
 * 
 * HQRIMG hDib - handle of the QR image  
 * 
 *Discription: 
 * This function calculate the histogram  of the gray QR image and get the adaptive  
 * threshold value by OTSU algorithm 
 * 
 ********************************************************************/ 
BOOL Erzhihua(HQRIMG hDib) 
{ 
	DWORD				 BufSize,LineBytes,BitCounts; 
  LPBITMAPINFOHEADER  	 lpImgData,SrcBi; 
  LPSTR				 lpPtr; 
  int thresholdValue=1; // 阈值 
  int GrayTable[256];             // 图像直方图,256个点 
  int n, n1, n2; 
  double m1, m2, sum, csum, fmax, sb; 
  int				   	 x,y,k,grayindex; 
	 
  BufSize=QRBlockSize(hDib);	 
  BitCounts=QRBitCount(hDib); 
  if(BitCounts!=8) 
	  return FALSE; 
	SrcBi=(LPBITMAPINFOHEADER)GlobalLock(hDib); 
	LineBytes=(DWORD)QRWIDTHBYTES(SrcBi->biWidth*BitCounts); 
//	hDifImg=CopyQRHandle(hDib); 
	lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hDib); 
   
  // 对直方图置零... 
  memset(GrayTable, 0, sizeof(GrayTable)); 
  //to costruct the histogram of QR gray scale image; 
  for(y=0;ybiHeight;y++) 
	{ 
		lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes); 
		for(x=0;xbiWidth;x++) 
		{ 
			grayindex=(unsigned char)*(lpPtr++); 
			GrayTable[grayindex]++; 
		} 
	} 
  // set up everything 
  sum = csum = 0.0; 
  n = 0; 
 
  for (k = 0; k < 256; k++) 
  { 
    sum += (double) k * (double) GrayTable[k];    /* x*f(x) 质量矩*/ 
    n   += GrayTable[k];                                         /*  f(x)    质量    */ 
  } 
  if (!n) { return (128); } 
  // do the otsu global thresholding method 
  fmax = -1.0; 
  n1 = 0; 
  for (k = 0; k < 256; k++)  
  { 
    n1 += GrayTable[k]; 
    if (!n1) { continue; } 
    n2 = n - n1; 
    if (n2 == 0) { break; } 
    csum += (double) k *GrayTable[k]; 
    m1 = csum / n1; 
    m2 = (sum - csum) / n2; 
    sb = (double) n1 *(double) n2 *(m1 - m2) * (m1 - m2); 
    /* bbg: note: can be optimized. */ 
    if (sb > fmax) 
    { 
      fmax = sb; 
      thresholdValue = k; 
    } 
  } 
   
  for(y=0;ybiHeight;y++) 
	{ 
		lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes); 
		for(x=0;xbiWidth;x++) 
		{ 
			grayindex=(unsigned char)*(lpPtr); 
			if(grayindex>thresholdValue) 
				*(lpPtr)=255; 
			else 
				*(lpPtr)=0; 
			lpPtr++;	 
		} 
	} 
  GlobalUnlock(hDib); 
  return TRUE;; 
} 
 
 
 /*************************************************************************  
 *  
 * ConvertQRToGrayscale()  
 *  
 * Parameters:  
 *  
 * HQRIMG hDIB        - handle to global memory with a DIB spec  
 *                    in it followed by the DIB bits  
 *  
 * int nMethod      - method used to convert color to grayscale 
 * 
 * double fRedWeight    - weight of Red 
 * 
 * double fGreenWeight	- weight of Green 
 * 
 * double fBlueWeight	- weight of Blue 
 *  
 * Return Value:  
 *  
 * HPALETTE         - handle of result grayscale palette 
 *  
 * Description:  
 *   Change QR image color table from color to grayscale 
 *  
 ************************************************************************/  
HPALETTE ConvertQRToGrayscale(HQRIMG hDib, int nMethod,  
				double fRedWeight, double fGreenWeight, double fBlueWeight) 
{ 
	DWORD             		SrcBufSize,DstBufSize,LineBytes,DstLineBytes; 
	HGLOBAL			   	hTempImgData; 
 	LPBITMAPINFOHEADER 	lpImgData; 
	LPBITMAPINFOHEADER 	lpTempImgData; 
	LPSTR              			lpPtr,lpTempPtr; 
	long              			x,y; 
//	BITMAPFILEHEADER   	DstBf; 
//	LPBITMAPFILEHEADER 	SrcBf; 
	BITMAPINFOHEADER  	DstBi; 
	LPBITMAPINFOHEADER 	SrcBi; 
    	DWORD			   	NumColors,NewNumColors; 
	WORD			   	BitCounts,NewBitCounts; 
	LOGPALETTE        		*pPal; 
//  HPALETTE           		hPrevPalette;  
	HGLOBAL            		hPal; 
	float					Y; 
	DWORD              		i; 
	HPALETTE           		hQRPalette=NULL; 
	unsigned char      		Red,Green,Blue,Gray; 
	 
	 
	if (hDib == NULL) 
		return NULL; 
	QRWaitCursorBegin(); 
	NumColors=QRNumColors(hDib); 
	NewNumColors=NumColors; 
	BitCounts=QRBitCount(hDib); 
	NewBitCounts=BitCounts; 
	if(NumColors==0) 
	{ 
		NewNumColors=256; 
		NewBitCounts=8; 
	} 
	SrcBi=(LPBITMAPINFOHEADER)GlobalLock(hDib); 
	LineBytes=(DWORD)QRWIDTHBYTES(SrcBi->biWidth*BitCounts); 
	DstLineBytes=(DWORD)QRWIDTHBYTES(SrcBi->biWidth*NewBitCounts); 
	DstBufSize=(DWORD)(sizeof(BITMAPINFOHEADER)+NewNumColors*sizeof(RGBQUAD)+(DWORD)DstLineBytes*SrcBi->biHeight); 
	memcpy((char *)&DstBi,(char *)SrcBi,sizeof(BITMAPINFOHEADER)); 
	/*	 
	memcpy((char *)&DstBf,(char *)SrcBf,sizeof(BITMAPFILEHEADER)); 
	DstBf.bfSize=DstBufSize+sizeof(BITMAPFILEHEADER); 
	DstBf.bfOffBits=(DWORD)(NewNumColors*sizeof(RGBQUAD)+sizeof(BITMAPFILEHEADER) 
							+sizeof(BITMAPINFOHEADER)); 
	*/ 
	memcpy((char *)&DstBi,(char *)SrcBi,sizeof(BITMAPINFOHEADER)); 
	DstBi.biClrUsed=0; 
	DstBi.biBitCount=NewBitCounts; 
	DstBi.biSizeImage=(DWORD)DstLineBytes*SrcBi->biHeight; 
	SrcBufSize=QRBlockSize(hDib); 
		 
	if((hTempImgData=GlobalAlloc(GHND,DstBufSize))==NULL) 
    		 return FALSE; 
  	//Realize the Palette  
  	lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hDib);     
	lpTempImgData=(LPBITMAPINFOHEADER)GlobalLock(hTempImgData); 
	//copy image data 
	memcpy(lpTempImgData,lpImgData,DstBufSize); 
	//overwrite bitmapinfoheader with the new one 
	memcpy(lpTempImgData,(char *)&DstBi,sizeof(BITMAPINFOHEADER)); 
	 
	lpPtr=(char *)lpImgData+sizeof(BITMAPINFOHEADER); 
	lpTempPtr=(char *)lpTempImgData+sizeof(BITMAPINFOHEADER); 
  	hPal=GlobalAlloc(GHND,sizeof(LOGPALETTE) + NewNumColors* sizeof(PALETTEENTRY)); 
  	pPal =(LOGPALETTE *)GlobalLock(hPal); 
  	pPal->palNumEntries =(WORD) NewNumColors; 
	pPal->palVersion = QRPALVERSION; 
	if(NumColors==0) //true color 
		for (i = 0; i < 256; i++)  
		{ 
     			pPal->palPalEntry[i].peRed=(BYTE)i; 
			pPal->palPalEntry[i].peGreen=(BYTE)i; 
			pPal->palPalEntry[i].peBlue=(BYTE)i; 
			pPal->palPalEntry[i].peFlags=(BYTE)0; 
			*(lpTempPtr++)=(unsigned char)i; 
			*(lpTempPtr++)=(unsigned char)i; 
			*(lpTempPtr++)=(unsigned char)i; 
			*(lpTempPtr++)=0; 
		} 
	else  
		for (i = 0; i < NewNumColors; i++)  
		{ 
			Blue=(unsigned char )(*lpPtr++); 
			Green=(unsigned char )(*lpPtr++); 
			Red=(unsigned char )(*lpPtr++); 
			Y=(float)(Red*0.299+Green*0.587+Blue*0.114); 
			Gray=(BYTE)Y; 
			lpPtr++; 
     			pPal->palPalEntry[i].peRed=Gray; 
			pPal->palPalEntry[i].peGreen=Gray; 
			pPal->palPalEntry[i].peBlue=Gray; 
			pPal->palPalEntry[i].peFlags=0; 
			*(lpTempPtr++)=(unsigned char)Gray; 
			*(lpTempPtr++)=(unsigned char)Gray; 
			*(lpTempPtr++)=(unsigned char)Gray; 
			*(lpTempPtr++)=0; 
		} 
	if(hQRPalette!=NULL)                      
        DeleteObject(hQRPalette); 
	hQRPalette=CreatePalette(pPal); 
	GlobalUnlock(hPal); 
	GlobalFree(hPal); 
	 
	//lpPtr=(char *)lpImgData+sizeof(BITMAPINFOHEADER); 
	//lpTempPtr=(unsigned char *)lpTempImgData+sizeof(BITMAPINFOHEADER); 
	BYTE GrayValue = 0; 
	switch(nMethod) 
	{ 
		case QRMAXIMUM_GRAY: 
			if(NumColors==0) 
			for(y=0;ybiHeight;y++) 
			{ 
				lpPtr=(char *)lpImgData+(SrcBufSize-LineBytes-y*LineBytes); 
				lpTempPtr=(char *)lpTempImgData+(DstBufSize-DstLineBytes-y*DstLineBytes); 
				for(x=0;xbiWidth;x++) 
				{ 
					Blue=(unsigned char )(*lpPtr++); 
					Green=(unsigned char )(*lpPtr++); 
					Red=(unsigned char )(*lpPtr++); 
					GrayValue=max(Blue,Green,Red); 
					*(lpTempPtr++)=(unsigned char)GrayValue; 
				} 
			} 
			break; 
		case QRMEAN_GRAY: 
			if(NumColors==0) 
			for(y=0;ybiHeight;y++) 
			{ 
				lpPtr=(char *)lpImgData+(SrcBufSize-LineBytes-y*LineBytes); 
				lpTempPtr=(char *)lpTempImgData+(DstBufSize-DstLineBytes-y*DstLineBytes); 
				for(x=0;xbiWidth;x++) 
				{ 
					Blue=(unsigned char )(*lpPtr++); 
					Green=(unsigned char )(*lpPtr++); 
					Red=(unsigned char )(*lpPtr++); 
					GrayValue=min(255,(unsigned char)(Blue/3+Green/3+Red/3)); 
					*(lpTempPtr++)=(unsigned char)GrayValue; 
				} 
			} 
			break; 
		case QRWEIGHT_GRAY: 
			if(NumColors==0) 
			for(y=0;ybiHeight;y++) 
			{ 
				lpPtr=(char *)lpImgData+(SrcBufSize-LineBytes-y*LineBytes); 
				lpTempPtr=(char *)lpTempImgData+(DstBufSize-DstLineBytes-y*DstLineBytes); 
				for(x=0;xbiWidth;x++) 
				{ 
					Blue=(unsigned char )(*lpPtr++); 
					Green=(unsigned char )(*lpPtr++); 
					Red=(unsigned char )(*lpPtr++); 
					GrayValue=min(255,(BYTE)(Blue*fBlueWeight+Green*fGreenWeight+Red*fRedWeight)); 
					*(lpTempPtr++)=(unsigned char)GrayValue; 
				} 
			} 
			break; 
	} 
	//copy the grayscale data (BITMAPINFOHEADER+PALETTE+PIXEL DATA)to the original image area 
	if(NumColors==0) 
	{ 
		GlobalUnlock(hDib); 
		hDib=GlobalReAlloc(hDib,DstBufSize,0); 
		lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hDib);  
		memcpy(lpImgData,lpTempImgData,DstBufSize); 
	} 
	if(hTempImgData!=NULL) 
	{ 
		GlobalUnlock(hTempImgData); 
		GlobalFree(hTempImgData); 
	} 
	 
	GlobalUnlock(hDib); 
	QRWaitCursorEnd(); 
	return hQRPalette; 
} 
 
 /*************************************************************************  
 *  
 * FindOrientationImage()  
 *  
 * Parameters:  
 *  
 * HQRIMG hDIB        - handle to global memory with a DIB spec  
 *                    in it followed by the DIB bits  
 *  
 * ORIENTATIONCENTER topleft - the coordinates of the top left orientation image 
 * 
 * ORIENTATIONCENTER topright - the coordinates of the top right orientation image 
 *  
 * ORIENTATIONCENTER bottomleft - the coordinates of the bottom left orientation image 
 *  
 * Return Value:  
 *  
 * if Find the three orientation image coordinates return TRue,otherwise FALSE 
 *  
 * Description:  
 *    
 * This function to get the coordinates of the three orientation image.  
 * the width and the height of the QR image must be the multiple of 4 
 ************************************************************************/   
BOOL PositionDetectImage(HQRIMG hDib,int * dim) 
{ 
	LPBITMAPINFOHEADER 	SrcBi; 
//	LPBITMAPINFOHEADER 	lpImage; 
 
//	BITMAPINFOHEADER  bHeader; 
//	BITMAPFILEHEADER  bBitFile; 
//	HFILE hf; 
	 
	long				Width,Height; 
	int					x,y; 
	int					dims[2]; 
//	int					start,end; 
	LPBYTE				lpImageData; 
//	ORIENTATIONCENTER   	Tmptopleft,Tmptopright,Tmpbottomleft,Tmpbottomright; 
	bool					bTopleft=false; 
	bool					bBottomright=false; 
	bool					bTopright=false; 
	bool					bBottomleft=false; 
//	int					Blockx,Blocky; 
//	WORD				BitCounts; 
	//DWORD				LineBytes,SrcBufSize; 
	int 					index=0; 
	HGLOBAL				hStatistic,hLine; 
	HGLOBAL				hTmpIndex,hTmpStatistic; 
	int					*lpStatistic; 
	int					tmp;//datatmp; 
	int					*lpTmpStatistic; 
//	int					lpTmpSta[LINE_MAX]; 
	int					*lpLine; 
	bool					bWB=false; 
	//HGLOBAL				hIndex; 
	 
	 
	if(hDib==NULL) 
		return FALSE; 
	SrcBi=(LPBITMAPINFOHEADER)GlobalLock(hDib); 
	Width=SrcBi->biWidth; 
	Height=SrcBi->biHeight; 
	//LineBytes=(DWORD)QRWIDTHBYTES(SrcBi->biWidth*SrcBi->biBitCount); 
	 
	if( (Width%4!=0) && (Height%4!=0)) 
		return FALSE; 
 
	//lpImage=(LPBITMAPINFOHEADER)GlobalLock(hDib); 
	//hIndex=CopyQRHandle(hDib); 
	GlobalUnlock(hDib); 
	LPBYTE lpImage=(LPBYTE)GlobalLock(hDib); 
	lpImageData=FindQRBits(lpImage); 
	//SrcBufSize=QRBlockSize(hDib); 
 
	//to find four corner coordinates of the QR image	 
	/* 
	for(y=0;y-1;x--) 
		{	//top left pixel 
			if((unsigned char)*(lpImageData+x)==0 &&!bTopleft) 
			{ 
				Tmptopleft.x=x; 
				Tmptopleft.y=y; 
				bTopleft=true; 
			} 
			 
	 	} 
		if(bTopleft ) 
		break; 
	} 
	for(y=0;y-1;x--) 
		{	//top left pixel 
			if((unsigned char)*(lpImageData++)==0 &&!bBottomright) 
			{ 
				Tmpbottomright.x=x; 
				Tmpbottomright.y=y; 
				bBottomright=true; 
			} 
			 
	 	} 
		if(bBottomright) 
		break; 
	} 
 
	for(x=0;x-1;x--) 
	{ 
		for(y=Height-1;y>-1;y--) 
		{	//top left pixel 
			lpImageData=(LPBYTE)lpImage+(SrcBufSize-LineBytes-y*LineBytes); 
			if((unsigned char)*(lpImageData+x)==0 &&!bBottomleft) 
			{ 
				Tmpbottomleft.x=x; 
				Tmpbottomleft.y=y; 
				bBottomleft=true; 
			} 
			 
	 	} 
		if(bBottomleft) 
		break; 
	} 
	 
	for(y=0;y=0) 
				(*(lpTmpStatistic+tmp))++; 
		} 
		*(lpLine+y)=index; 
	} 
	//to get the statistic of the most high frequency data; 
	int max=0; 
	int unitminbak=Width; 
	for(int i=0;imax) 
		{ 
			max=*(lpTmpStatistic+i); 
			unitminbak=i; 
		} 
	} 
	// if the unitmin is unequal to the unitminbak 
	if(unitminbak>unitmin) 
	{ 
//		if(unitminbak%unitmin!=0) 
			if(((*(lpTmpStatistic+unitminbak))/(*(lpTmpStatistic+unitmin)))>10) 
				unitmin=unitminbak; 
	} 
 
	// to find the start pixel and the end pixel 
	ORIENTATIONCENTER START,END; 
	y=0; 
	while((*(lpLine+y))<3) 
		y++; 
	START.y=y; 
	while((*(lpLine+y))>2) 
		y++; 
	END.y=y; 
 
	x=0; 
	while((unsigned char)*(lpImageData+START.y*Width+x)!=0) 
		x++; 
	int temx1=x; 
	x=0; 
	while((unsigned char)*(lpImageData+(END.y-1)*Width+x)!=0) 
		x++; 
	int temx2=x; 
	START.x=min(temx1,temx2); 
	 
	x=Width-1; 
	while((unsigned char)*(lpImageData+START.y*Width+x)!=0) 
		x--; 
	temx1=x; 
	x=Width-1; 
	while((unsigned char)*(lpImageData+(END.y-1)*Width+x)!=0) 
		x--; 
	temx2=x; 
	END.x=max(temx1,temx2)+1; 
 
	//to construct the index image 
	int Indexnum=max((END.x-START.x),(END.y-START.y))/unitmin; 
	int Indexsum=0; 
	int row=0; 
	int column=0; 
	if((hIndexData=GlobalAlloc(GHND,Indexnum*Indexnum*sizeof(char)))==NULL) 
		return FALSE; 
	LPBYTE lpIndexData=(LPBYTE)GlobalLock(hIndexData); 
	for(y=START.y; y128) 
				*(lpIndexData+column*Indexnum+row)=255; 
			else 
				*(lpIndexData+column*Indexnum+row)=0; 
			row++; 
		} 
		column++; 
	} 
	dims[0]=row; 
	dims[1]=column; 
	*(dim)=row; 
	*(dim+1)=column; 
 
// to get the three orientation image coordinates and make the image to the standard position 
	Rotate RotateAngle=NOACTION; 
	bool bRotate=false; 
	BYTE POSITIONPATTERN[7][7]={ 
					{  0 ,   0 ,  0  , 0  ,  0  ,  0 ,  0 }, 
					{  0  ,255,255,255,255,255,  0 }, 
					{  0  ,255,  0,   0  ,  0  ,255,  0}, 
					{  0  ,255,  0 ,  0  ,  0  ,255,  0}, 
					{  0  ,255,  0 ,  0  ,  0  ,255,  0}, 
					{  0  ,255,255,255,255,255,  0}, 
					{  0  ,  0 ,  0  ,  0 ,  0  ,  0  ,  0} 
					}; 
	for(y=0;y<7;y++) 
	{ 
		for(x=0;x<7;x++) 
			if((*(lpIndexData+y*Indexnum+x))^POSITIONPATTERN[y][x]) 
			{ 
				RotateAngle=ANTICLOCKWISE; 
				bRotate=true; 
				break; 
			} 
		if(bRotate) 
			break; 
	} 
 
	if(!bRotate) 
	{ 
		for(y=0;y<7;y++) 
		{ 
			for(x=0;x<7;x++) 
				if((*(lpIndexData+(column-1-y)*Indexnum+x))^POSITIONPATTERN[y][x]) 
				{ 
					RotateAngle=HALFCIRCLE; 
					bRotate=true; 
					break; 
				} 
			if(bRotate) 
				break; 
		} 
	} 
 
	if(!bRotate) 
	{ 
		for(y=0;y<7;y++) 
		{ 
			for(x=0;x<7;x++) 
				if((*(lpIndexData+(column-1-y)*Indexnum+(row-1-x)))^POSITIONPATTERN[y][x]) 
				{ 
					RotateAngle=CLOCKWISE; 
					bRotate=true; 
					break; 
				} 
			if(bRotate) 
				break; 
		} 
	} 
 
	GlobalUnlock(hIndexData); 
	if(bRotate) 
	{ 
		if(!RotateIndexImage(hIndexData,RotateAngle,row,column)) 
		return FALSE; 
	} 
	lpIndexData=(LPBYTE)GlobalLock(hIndexData); 
	if((hTmpIndex=GlobalAlloc(GHND,row*column*sizeof(BYTE)))==NULL) 
		return FALSE; 
	LPBYTE lpTmpIndex=(LPBYTE)GlobalLock(hTmpIndex); 
	for(y=0;ybmiHeader.biHeight=row; 
	lpIndexHdr->bmiHeader.biWidth=column; 
	//lpIndexHdr->biPlanes=0; 
	lpIndexHdr->bmiHeader.biSizeImage=0;//row*column*sizeof(char); 
	LPBYTE lpdata=(LPBYTE)GlobalLock(hIndextmp); 
	//memcpy(lpdata+sizeof(BITMAPINFOHEADER),lpImage+sizeof(BITMAPINFOHEADER),256*sizeof(RGBQUAD)); 
	memcpy(lpdata+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD),lpIndexData,row*column*sizeof(BYTE));//; 
	 
	//LPBYTE lpbit=(LPBYTE)GlobalLock(hIndex); 
	bBitFile.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD); 
	bBitFile.bfType=0x4d42; 
	bBitFile.bfReserved1=0; 
	bBitFile.bfReserved2=0; 
	bBitFile.bfSize=sizeof(BITMAPFILEHEADER)+destbuf; 
	 
	HANDLE hFile; 
	DWORD               dwWritten;  
	 
	if ((hFile = CreateFile("c:\\gray.bmp", GENERIC_WRITE, 0, NULL,  
            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,  
            NULL)) != INVALID_HANDLE_VALUE)  
	{ 
		WriteFile(hFile,(LPBYTE)&bBitFile,sizeof(BITMAPFILEHEADER),&dwWritten,NULL); 
		//WriteFile(hFile,(LPBYTE)lpIndexHdr,sizeof(BITMAPINFOHEADER),&dwWritten,NULL); 
		//WriteFile(hFile,(LPBYTE)(lpImage+sizeof(BITMAPINFOHEADER)),256*sizeof(RGBQUAD),&dwWritten,NULL); 
		//WriteFile(hFile,(LPBYTE)lpIndexData,row*column,&dwWritten,NULL); 
		WriteFile(hFile,(LPBYTE)lpdata,destbuf,&dwWritten,NULL); 
	} 
	CloseHandle(hFile);  
 
*/ 
	if(hTmpIndex!=NULL) 
	{ 
		GlobalUnlock(hTmpIndex); 
		GlobalFree(hTmpIndex); 
	} 
	if(hStatistic!=NULL) 
	{ 
		GlobalUnlock(hStatistic); 
		GlobalFree(hStatistic); 
	} 
	if(hLine!=NULL) 
	{ 
		GlobalUnlock(hLine); 
		GlobalFree(hLine); 
	} 
	if(hTmpStatistic!=NULL) 
	{ 
		GlobalUnlock(hTmpStatistic); 
		GlobalFree(hTmpStatistic); 
	} 
//	lpTmpSat=(int *)GlobalLock(hTmpSat); 
//	if(hTmpStatistic!=NULL) 
//	{ 
//		GlobalUnlock(hTmpStatistic); 
//		GlobalFree(hTmpStatistic); 
	//	DWORD fff=GetLastError(); 
//	} 
////////////////////////////////////////////////////////////////////////////////// 
/*	unsigned char VersionNum=VersionNumberInfo( hIndexData,row, column); 
	unsigned char Format=FormatInfo(hIndexData,row,column); 
	if(!MaskImg(Format,VersionNum)) 
		return FALSE; 
	unsigned char CorrectPos=ReviseimagePos(VersionNum); 
	if(!UnmaskIndexImage(hIndexData,hMaskImg,VersionNum)) 
		return FALSE; 
	HGLOBAL OriginalCode=GetOriginalCode(hIndexData,VersionNum,Format); 
*/ 
//	HGLOBAL DecoderCode=QRDecoder(OriginalCode,VersionNum,Format); 
 
/////////////////////////////////////////////////////////////////////////////////// 
 
 
return TRUE; 
} 
 
/******************************************************************* 
* 
*RotateIndexImage() 
* 
*Parameters: 
* 
*HGLOBAL hIndexData - the handle of the index image data; 
* 
*Rotate  RotateAngle - the angle that the index image need to roate 
*  
*int  row - the width of the index image; 
* 
*int column - the height of the index image; 
* 
*RETURN value: 
* 
*			TRUE or FALSE 
* 
*REMARKS: 
* 
*This function is to rotate the index image to standard position, There is not  position detection 
*image at the bottom right corner of the index image.If the rotate success return TRUE, 
*otherwise return FALSE; 
* 
  ******************************************************************/ 
 BOOL RotateIndexImage(HGLOBAL hIndexData,Rotate RotateAngle,int row,int column) 
 { 
 	HGLOBAL hTmpIndex; 
	LPBYTE 	lpIndexData,lpTmpData; 
	int x,y; 
	 
 	if(hIndexData==NULL) 
		return FALSE; 
	lpIndexData=(LPBYTE)GlobalLock(hIndexData); 
	if((hTmpIndex=GlobalAlloc(GHND,row*column*sizeof(BYTE)))==NULL) 
		return FALSE; 
	lpTmpData=(LPBYTE)GlobalLock(hTmpIndex); 
	switch(RotateAngle) 
		{ 
		case CLOCKWISE: 
			for(y=0;y>10); 
	else 
		return FALSE; 
 
 } 
/************************************************************************** 
* 
*VersionNumberInfo() 
* 
*Parameters: 
* 
*HGLOBAL hIndexData - the handle of the index image data; 
* 
*int  row - the width of the index image; 
* 
*int column - the height of the index image; 
* 
*RETURN value: 
* 
*			unsigned char -low six bits is the version number 
* 
*REMARKS: 
* 
*This function is to get the Version number as the return value show; 
* 
*************************************************************************/ 
 unsigned char VersionNumberInfo(HGLOBAL hIndexData,int row,int column) 
 { 
	LPBYTE 	      lpIndexData; 
 	unsigned int  VersionNum=0U; 
	unsigned int  VersionBak=0U; 
	unsigned int  VersionFlag=1U; 
	int m,n; 
	if(hIndexData==NULL) 
		return FALSE; 
	lpIndexData=(LPBYTE)GlobalLock(hIndexData); 
	if(row<45) 
		return (row-21)/4+1; 
	//to read the top right version number 
	for(m=0;m<6;m++) 
		for(n=0;n<3;n++) 
		{ 
			if(*(lpIndexData+(5-m)*row+(column-9-n))==0) 
				VersionNum=VersionNum|(VersionFlag<<(17-m*3-n)); 
		} 
	//to read the bottom left version number 
	for(m=0;m<6;m++) 
		for(n=0;n<3;n++) 
		{ 
			if(*(lpIndexData+(row-9-n)*row+(5-m))==0) 
				VersionBak=VersionBak|(VersionFlag<<(17-m*3-n)); 
		} 
 
	if(VersionNum==VersionBak) 
		return (unsigned char)(VersionNum>>12); 
	else 
		return FALSE; 
	 
 } 
 
/************************************************************************** 
* 
*MaskImg() 
* 
*Parameters: 
* 
*unsigned char FormatNum - the format information of the QR index image,including the mask 
* 						reference and the correction level; 
* 
*unsigned char VersionNum - the version number  information of the QR index image 
* 
* 
*RETURN value: 
* 
*		if the function runs properply,it returns TRUE. otherwise returns FALSE; 
* 
*REMARKS: 
* 
*		This function is to make the mask image according to  format information and version 
*		number infromation; 
* 
*************************************************************************/ 
BOOL MaskImg(unsigned char FormatNum,unsigned char VersionNum) 
{ 
	unsigned char dimension=0; 
	unsigned char maskref=0; 
	unsigned char * lpMaskData; 
	dimension=21+(VersionNum-1)*4; 
	maskref=FormatNum&7; 
	int i,j; 
	if((hMaskImg=GlobalAlloc(GHND,dimension*dimension*sizeof(BYTE)))==NULL) 
		return FALSE; 
	lpMaskData=(unsigned char *)GlobalLock(hMaskImg); 
	switch(maskref) 
	{ 
		case 0: 
			for(i=0;i6) 
	{ 
		for(y=0;y<6;y++) 
		for(x=0;x<3;x++) 
			*(lpMarkImgData+y*dimension+(dimension-11+x))=128;	 
	//to mark the bottom left version number area 
		for(y=0;y<3;y++) 
		for(x=0;x<6;x++) 
			*(lpMarkImgData+(dimension-11+y)*dimension+x)=128;	 
	} 
	//to mark the orientation image 
	for(x=0;x>3; 
	switch(VersionNum) 
	{ 
		case 1: 
			switch(CorrectLevel) 
			{ 
				case LEVEL_L: //Level L 
						CorrectCode[0]=26; 
						CorrectCode[1]=19; 
						CorrectCode[2]=2; 
						CorrectCode[3]=1; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_M: //Level M 
						CorrectCode[0]=26;//sum of all code 
						CorrectCode[1]=16;//sum of data 
						CorrectCode[2]=4;// capacity of correction 
						CorrectCode[3]=1; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_Q: //Level Q 
						CorrectCode[0]=26; 
						CorrectCode[1]=13; 
						CorrectCode[2]=6; 
						CorrectCode[3]=1; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_H: //Level H 
						CorrectCode[0]=26; 
						CorrectCode[1]=9; 
						CorrectCode[2]=8; 
						CorrectCode[3]=1; 
						CorrectCode[4]=0; 
						return TRUE; 
			} 
		case 2: 
			switch(CorrectLevel) 
			{ 
				case LEVEL_L: //Level L 
						CorrectCode[0]=44; 
						CorrectCode[1]=34; 
						CorrectCode[2]=4; 
						CorrectCode[3]=1; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_M: //Level M 
						CorrectCode[0]=44;//sum of all code 
						CorrectCode[1]=28;//sum of data 
						CorrectCode[2]=8;// capacity of correction 
						CorrectCode[3]=1; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_Q: //Level Q 
						CorrectCode[0]=44; 
						CorrectCode[1]=22; 
						CorrectCode[2]=11; 
						CorrectCode[3]=1; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_H: //Level H 
						CorrectCode[0]=44; 
						CorrectCode[1]=16; 
						CorrectCode[2]=14; 
						CorrectCode[3]=1; 
						CorrectCode[4]=0; 
						return TRUE; 
			} 
		case 3: 
			switch(CorrectLevel) 
			{ 
				case LEVEL_L: //Level L 
						CorrectCode[0]=70; 
						CorrectCode[1]=55; 
						CorrectCode[2]=7; 
						CorrectCode[3]=1; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_M: //Level M 
						CorrectCode[0]=70;//sum of all code 
						CorrectCode[1]=44;//sum of data 
						CorrectCode[2]=13;// capacity of correction 
						CorrectCode[3]=1; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_Q: //Level Q 
						CorrectCode[0]=35; 
						CorrectCode[1]=17; 
						CorrectCode[2]=9; 
						CorrectCode[3]=2; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_H: //Level H 
						CorrectCode[0]=35; 
						CorrectCode[1]=13; 
						CorrectCode[2]=11; 
						CorrectCode[3]=2; 
						CorrectCode[4]=0; 
						return TRUE; 
			} 
		case 4: 
			switch(CorrectLevel) 
			{ 
				case LEVEL_L: //Level L 
						CorrectCode[0]=100; 
						CorrectCode[1]=80; 
						CorrectCode[2]=10; 
						CorrectCode[3]=1; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_M: //Level M 
						CorrectCode[0]=50;//sum of all code 
						CorrectCode[1]=32;//sum of data 
						CorrectCode[2]=9;// capacity of correction 
						CorrectCode[3]=2; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_Q: //Level Q 
						CorrectCode[0]=50; 
						CorrectCode[1]=24; 
						CorrectCode[2]=13; 
						CorrectCode[3]=2; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_H: //Level H 
						CorrectCode[0]=25; 
						CorrectCode[1]=9; 
						CorrectCode[2]=8; 
						CorrectCode[3]=4; 
						CorrectCode[4]=0; 
						return TRUE; 
			} 
		case 5: 
			switch(CorrectLevel) 
			{ 
				case LEVEL_L: //Level L 
						CorrectCode[0]=134; 
						CorrectCode[1]=108; 
						CorrectCode[2]=13; 
						CorrectCode[3]=1; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_M: //Level M 
						CorrectCode[0]=67;//sum of all code 
						CorrectCode[1]=43;//sum of data 
						CorrectCode[2]=12;// capacity of correction 
						CorrectCode[3]=2; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_Q: //Level Q 
						CorrectCode[0]=33; 
						CorrectCode[1]=15; 
						CorrectCode[2]=9; 
						CorrectCode[3]=2; 
						CorrectCode[4]=2; 
						return TRUE; 
				case LEVEL_H: //Level H 
						CorrectCode[0]=33; 
						CorrectCode[1]=11; 
						CorrectCode[2]=11; 
						CorrectCode[3]=2; 
						CorrectCode[4]=2; 
						return TRUE; 
			} 
		case 6: 
			switch(CorrectLevel) 
			{ 
				case LEVEL_L: //Level L 
						CorrectCode[0]=86; 
						CorrectCode[1]=68; 
						CorrectCode[2]=9; 
						CorrectCode[3]=2; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_M: //Level M 
						CorrectCode[0]=43;//sum of all code 
						CorrectCode[1]=27;//sum of data 
						CorrectCode[2]=8;// capacity of correction 
						CorrectCode[3]=4; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_Q: //Level Q 
						CorrectCode[0]=43; 
						CorrectCode[1]=19; 
						CorrectCode[2]=12; 
						CorrectCode[3]=4; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_H: //Level H 
						CorrectCode[0]=43; 
						CorrectCode[1]=15; 
						CorrectCode[2]=14; 
						CorrectCode[3]=4; 
						CorrectCode[4]=0; 
						return TRUE; 
			} 
		case 7: 
			switch(CorrectLevel) 
			{ 
				case LEVEL_L: //Level L 
						CorrectCode[0]=98; 
						CorrectCode[1]=78; 
						CorrectCode[2]=10; 
						CorrectCode[3]=2; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_M: //Level M 
						CorrectCode[0]=49;//sum of all code 
						CorrectCode[1]=31;//sum of data 
						CorrectCode[2]=9;// capacity of correction 
						CorrectCode[3]=4; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_Q: //Level Q 
						CorrectCode[0]=32; 
						CorrectCode[1]=14; 
						CorrectCode[2]=9; 
						CorrectCode[3]=2; 
						CorrectCode[4]=4; 
						return TRUE; 
				case LEVEL_H: //Level H 
						CorrectCode[0]=39; 
						CorrectCode[1]=13; 
						CorrectCode[2]=13; 
						CorrectCode[3]=4; 
						CorrectCode[4]=1; 
						return TRUE; 
			} 
		case 8: 
			switch(CorrectLevel) 
			{ 
				case LEVEL_L: //Level L 
						CorrectCode[0]=121; 
						CorrectCode[1]=97; 
						CorrectCode[2]=12; 
						CorrectCode[3]=2; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_M: //Level M 
						CorrectCode[0]=60;//sum of all code 
						CorrectCode[1]=38;//sum of data 
						CorrectCode[2]=11;// capacity of correction 
						CorrectCode[3]=2; 
						CorrectCode[4]=2; 
						return TRUE; 
				case LEVEL_Q: //Level Q 
						CorrectCode[0]=40; 
						CorrectCode[1]=18; 
						CorrectCode[2]=11; 
						CorrectCode[3]=4; 
						CorrectCode[4]=2; 
						return TRUE; 
				case LEVEL_H: //Level H 
						CorrectCode[0]=40; 
						CorrectCode[1]=14; 
						CorrectCode[2]=13; 
						CorrectCode[3]=4; 
						CorrectCode[4]=2; 
						return TRUE; 
			} 
		case 9: 
			switch(CorrectLevel) 
			{ 
				case LEVEL_L: //Level L 
						CorrectCode[0]=146; 
						CorrectCode[1]=116; 
						CorrectCode[2]=15; 
						CorrectCode[3]=2; 
						CorrectCode[4]=0; 
						return TRUE; 
				case LEVEL_M: //Level M 
						CorrectCode[0]=58;//sum of all code 
						CorrectCode[1]=36;//sum of data 
						CorrectCode[2]=11;// capacity of correction 
						CorrectCode[3]=3; 
						CorrectCode[4]=2; 
						return TRUE; 
				case LEVEL_Q: //Level Q 
						CorrectCode[0]=36; 
						CorrectCode[1]=16; 
						CorrectCode[2]=10; 
						CorrectCode[3]=4; 
						CorrectCode[4]=4; 
						return TRUE; 
				case LEVEL_H: //Level H 
						CorrectCode[0]=36; 
						CorrectCode[1]=12; 
						CorrectCode[2]=12; 
						CorrectCode[3]=4; 
						CorrectCode[4]=4; 
						return TRUE; 
			} 
		case 10: 
			switch(CorrectLevel) 
			{ 
				case LEVEL_L: //Level L 
						CorrectCode[0]=86; 
						CorrectCode[1]=68; 
						CorrectCode[2]=9; 
						CorrectCode[3]=2; 
						CorrectCode[4]=2; 
						return TRUE; 
				case LEVEL_M: //Level M 
						CorrectCode[0]=69;//sum of all code 
						CorrectCode[1]=43;//sum of data 
						CorrectCode[2]=13;// capacity of correction 
						CorrectCode[3]=4; 
						CorrectCode[4]=1; 
						return TRUE; 
				case LEVEL_Q: //Level Q 
						CorrectCode[0]=43; 
						CorrectCode[1]=19; 
						CorrectCode[2]=12; 
						CorrectCode[3]=6; 
						CorrectCode[4]=2; 
						return TRUE; 
				case LEVEL_H: //Level H 
						CorrectCode[0]=43; 
						CorrectCode[1]=15; 
						CorrectCode[2]=14; 
						CorrectCode[3]=6; 
						CorrectCode[4]=2; 
						return TRUE; 
			} 
		default: 
			return FALSE; 
	} 
} 
 
/************************************************************************** 
* 
*GetOriginalCode() 
* 
*Parameters: 
* 
*unsigned char VersionNum - the version number  information of the QR index image 
* 
*unsigned char Format - the Format information of the QR index image 
* 
*HGLOBAL hIndexData - the handle of unmasked index image data  
* 
*RETURN value: 
* 
*		if this function gets original code properply,it returns the handle of original code 
*		otherwise it will return NULL; 
* 
*REMARKS: 
* 
*		This function is to get the original code including data code and correction code 
* 
*************************************************************************/ 
 
HGLOBAL GetOriginalCode(HGLOBAL hIndexData,unsigned char VersionNum,unsigned char Format) 
{ 
	HGLOBAL					hTmpCode=NULL; 
	unsigned char 	READFLAG=1U; 
	unsigned char 	count=0U; 
	unsigned char 	row,column,dimension; 
	unsigned char   tmpcode=0; 
	unsigned short	codesum; 
	unsigned short	alreadyread=0; 
	unsigned char * lpIndexData; 
	unsigned char *	lpOriginalCode; 
	unsigned char * lpTmpCode; 
	unsigned char   CorrectCode[5]; 
	BOOL						ORDERFLAG=TRUE; 
	BOOL						bFinished=TRUE; 
	BOOL						bUpDown=TRUE; 
	int							i,j; 
//	BOOL						bOneByte=TRUE; 
	if(hIndexData==NULL) 
		return NULL; 
	dimension=21+(VersionNum-1)*4; 
	lpIndexData=(unsigned char *)GlobalLock(hIndexData); 
	 
	//to get the amount of correct module and correction code 
	//for(i=0;i<5;i++) 
		//CorrectCode[i]=0; 
	memset(CorrectCode,0,sizeof(CorrectCode)); 
	if(!GetCorrectionCode(VersionNum,Format,CorrectCode)) 
		return NULL; 
	//to allocate memory for reading original code	 
	codesum=(unsigned short)(CorrectCode[0]*CorrectCode[3]+(CorrectCode[0]+1)*CorrectCode[4]); 
	if((hOriginalCode=GlobalAlloc(GHND,codesum*sizeof(unsigned char)))==NULL) 
		return NULL; 
	lpOriginalCode=(unsigned char *)GlobalLock(hOriginalCode); 
	//start to read original code 
	row=column=0;	 
	while(bFinished) 
	{ 
		if(bUpDown) 
		{ 
			row=row+1; 
			if(column==0) 
				column=column+1; 
			else 
				column=column+2; 
			if(column==dimension-6) 
				column=column+1; 
			while(bUpDown) 
			{ 
				if(ORDERFLAG) 
				{ 
					if(*(lpIndexData+(dimension-row)*dimension+(dimension-column))==255)//0 
					{ 
						tmpcode=tmpcode|READFLAG<<(7-count); 
						count++; 
					} 
					else if(*(lpIndexData+(dimension-row)*dimension+(dimension-column))==0)//255 
					{ 
						count++; 
					} 
					column++; 
					ORDERFLAG=FALSE; 
				} 
				else 
				{ 
					if(*(lpIndexData+(dimension-row)*dimension+(dimension-column))==255)//0 
					{ 
						tmpcode=tmpcode|READFLAG<<(7-count); 
						count++; 
					} 
					else if(*(lpIndexData+(dimension-row)*dimension+(dimension-column))==0)//255 
					{ 
						count++; 
					} 
					row++; 
					column--; 
					ORDERFLAG=TRUE; 
				} 
				if(count==8) 
				{ 
					count=0; 
					if(alreadyread=dimension && column>=dimension) 
					bFinished=FALSE; 
 
				if(row>dimension||column>dimension-1) 
				bUpDown=FALSE; 
			} 
		}//bUp 
		else 
		{ 
			row=row-1; 
			column=column+2; 
			if(column==dimension-6) 
				column=column+1; 
			while(!bUpDown) 
			{ 
				if(ORDERFLAG) 
				{ 
					if(*(lpIndexData+(dimension-row)*dimension+(dimension-column))==255)//0 
					{ 
						tmpcode=tmpcode|READFLAG<<(7-count); 
						count++; 
					} 
					else if(*(lpIndexData+(dimension-row)*dimension+(dimension-column))==0)//255 
					{ 
						count++; 
					} 
					column++; 
					ORDERFLAG=FALSE; 
				} 
				else 
				{ 
					if(*(lpIndexData+(dimension-row)*dimension+(dimension-column))==255)//0 
					{ 
						tmpcode=tmpcode|READFLAG<<(7-count); 
						count++; 
					} 
					else if(*(lpIndexData+(dimension-row)*dimension+(dimension-column))==0)//255 
					{ 
						count++; 
					} 
					row--; 
					column--; 
					ORDERFLAG=TRUE; 
				} 
				if(count==8) 
				{ 
					count=0; 
					if(alreadyread=dimension && column>=dimension) 
					bFinished=FALSE; 
 
				if(row>dimension || row<1||column>dimension) 
					bUpDown=TRUE; 
			} 
		}//bDown 
	}//bFinished 
	 
 
	if((hTmpCode=GlobalAlloc(GHND,codesum*sizeof(unsigned char)))==NULL) 
		return NULL; 
	lpTmpCode=(unsigned char *)GlobalLock(hTmpCode); 
	int SumCorrect=CorrectCode[3]+CorrectCode[4]; 
	if(SumCorrect>1) 
	{ 
// to construct the sequence data code 
		for(i=0;i>4; 
		else 
		{ 
			mode=(((*(lpOriginalCode+shang))<>4; 
			mode=mode|(*(lpOriginalCode+shang+1)>>(12-yushu)); 
		} 
		//mode=((*lpOriginalCode+shang)&0xF0)>>4; 
		//to get the code amount of segment 1 
		CountBit=GetModeCountBit(VersionNum,mode); 
		switch(mode) 
		{ 
			case 0x01: 
				if(yushu<5) 
				{ 
					TmpData=*(lpOriginalCode+shang); 
					CharacterAmount=((TmpData<<(yushu+4))&0x00FF)<<(CountBit-8); 
					if(CountBit+yushu-4<=8) 
					{ 
						TmpData=*(lpOriginalCode+shang+1); 
						CharacterAmount=CharacterAmount|(TmpData>>(12-CountBit-yushu)); 
					} 
					else 
					{ 
						TmpData=*(lpOriginalCode+shang+1); 
						CharacterAmount=CharacterAmount|(TmpData<<(yushu+CountBit-12)); 
						TmpData=*(lpOriginalCode+shang+2); 
						CharacterAmount=CharacterAmount|(TmpData>>(20-CountBit-yushu)); 
					} 
				} 
				else 
				{ 
					TmpData=*(lpOriginalCode+shang+1); 
					CharacterAmount=(TmpData<<((yushu-4))&0x00FF)<<(CountBit-8); 
					if(CountBit+yushu-12<=8) 
					{ 
						TmpData=*(lpOriginalCode+shang+2); 
						CharacterAmount=CharacterAmount|(TmpData>>(20-CountBit-yushu)); 
					} 
					else 
					{ 
						TmpData=*(lpOriginalCode+shang+2); 
						CharacterAmount=CharacterAmount|(TmpData<<(yushu+CountBit-20)); 
						TmpData=*(lpOriginalCode+shang+3); 
						CharacterAmount=CharacterAmount|(TmpData>>(28-CountBit-yushu)); 
					} 
				} 
				break; 
			case 0x02: 
				if(yushu<5) 
				{ 
					TmpData=*(lpOriginalCode+shang); 
					CharacterAmount=((TmpData<<(yushu+4))&0x00FF)<<(CountBit-8); 
					if(CountBit+yushu-4<=8) 
					{ 
						TmpData=*(lpOriginalCode+shang+1); 
						CharacterAmount=CharacterAmount|(TmpData>>(12-CountBit-yushu)); 
					} 
					else 
					{ 
						TmpData=*(lpOriginalCode+shang+1); 
						CharacterAmount=CharacterAmount|(TmpData<<(yushu+CountBit-12)); 
						TmpData=*(lpOriginalCode+shang+2); 
						CharacterAmount=CharacterAmount|(TmpData>>(20-CountBit-yushu)); 
					} 
				} 
				else 
				{ 
					TmpData=*(lpOriginalCode+shang+1); 
					CharacterAmount=(TmpData<<((yushu-4))&0x00FF)<<(CountBit-8); 
					if(CountBit+yushu-12<=8) 
					{ 
						TmpData=*(lpOriginalCode+shang+2); 
						CharacterAmount=CharacterAmount|(TmpData>>(20-CountBit-yushu)); 
					} 
					else 
					{ 
						TmpData=*(lpOriginalCode+shang+2); 
						CharacterAmount=CharacterAmount|(TmpData<<(yushu+CountBit-20)); 
						TmpData=*(lpOriginalCode+shang+3); 
						CharacterAmount=CharacterAmount|(TmpData>>(28-CountBit-yushu)); 
					} 
				} 
				break; 
			case 0x04: 
				if(yushu<5) 
				{ 
					TmpData=*(lpOriginalCode+shang); 
					CharacterAmount=((TmpData<<(yushu+4))&0x00FF)<<(CountBit-8); 
					if(CountBit+yushu-4<=8) 
					{ 
						TmpData=*(lpOriginalCode+shang+1); 
						CharacterAmount=CharacterAmount|(TmpData>>(12-CountBit-yushu)); 
					} 
					else 
					{ 
						TmpData=*(lpOriginalCode+shang+1); 
						CharacterAmount=CharacterAmount|(TmpData<<(yushu+CountBit-12)); 
						TmpData=*(lpOriginalCode+shang+2); 
						CharacterAmount=CharacterAmount|(TmpData>>(20-CountBit-yushu)); 
					} 
				} 
				else 
				{ 
					TmpData=*(lpOriginalCode+shang+1); 
					CharacterAmount=(TmpData<<((yushu-4))&0x00FF)<<(CountBit-8); 
					if(CountBit+yushu-12<=8) 
					{ 
						TmpData=*(lpOriginalCode+shang+2); 
						CharacterAmount=CharacterAmount|(TmpData>>(20-CountBit-yushu)); 
					} 
					else 
					{ 
						TmpData=*(lpOriginalCode+shang+2); 
						CharacterAmount=CharacterAmount|(TmpData<<(yushu+CountBit-20)); 
						TmpData=*(lpOriginalCode+shang+3); 
						CharacterAmount=CharacterAmount|(TmpData>>(28-CountBit-yushu)); 
					} 
				} 
				break; 
			case 0x0D: 
				if(yushu<5) 
				{ 
					TmpData=*(lpOriginalCode+shang+1); 
					CharacterAmount=((TmpData<>(16-CountBit-yushu)); 
					} 
					else 
					{ 
					//	TmpData=*(lpOriginalCode+shang+2); 
					//	CharacterAmount=CharacterAmount|(TmpData<<(yushu+CountBit-16)); 
					//	TmpData=*(lpOriginalCode+shang+3); 
					//	CharacterAmount=CharacterAmount|(TmpData>>(24-CountBit-yushu)); 
					} 
				} 
				else 
				{ 
					TmpData=*(lpOriginalCode+shang+1); 
					CharacterAmount=((TmpData<>(16-CountBit-yushu)); 
					} 
					else 
					{ 
						TmpData=*(lpOriginalCode+shang+2); 
						CharacterAmount=CharacterAmount|(TmpData<<(yushu+CountBit-16)); 
						TmpData=*(lpOriginalCode+shang+3); 
						CharacterAmount=CharacterAmount|(TmpData>>(24-CountBit-yushu)); 
					} 
				} 
				break; 
			default: 
				break;		 
		} 
	//to calculate the bit amount of segment 1; 
		switch(mode) 
		{ 
			case 0x01: 
				if(CharacterAmount%3==0) 
					BitSum=4+CountBit+10*(CharacterAmount/3); 
				else if(CharacterAmount%3==1) 
					BitSum=4+CountBit+10*(CharacterAmount/3)+4; 
				else if(CharacterAmount%3==2) 
					BitSum=4+CountBit+10*(CharacterAmount/3)+7; 
				break; 
			case 0x02: 
				BitSum=4+CountBit+11*(CharacterAmount/2)+6*(CharacterAmount%2); 
				break; 
			case 0x04: 
				BitSum=4+CountBit+8*CharacterAmount; 
				break; 
			case 0x0D: 
				BitSum=4+4+CountBit+13*CharacterAmount; 
				break; 
			default: 
				break; 
		} 
	 
		BitAmount=BitAmount+BitSum; 
		if(BitAmount>=DataSum*8||mode==0) 
			bRead=FALSE; 
		else 
		{ 
			ModeIndex[SegmentNum]=mode; 
			Character[SegmentNum]=CharacterAmount; 
			Segment[SegmentNum++]=BitSum; 
		} 
	} 
	CharacterAmount=0; 
	for(i=0;iCharacter[i]) 
					{ 
						bRead=FALSE; 
						break; 
					} 
					if(yushu==0) 
						shang++; 
					if(yushu<=6) 
					{	 
						TmpData=*(lpOriginalCode+shang); 
						ReadData=((TmpData<>(6-yushu)); 
						if(yushu==6) 
						{ 
					 	 	yushu=0; 
					 	// 	shang++; 
					 	} 
					 	else 
					 		yushu=(yushu+10)%8; 
					} 
					else 
					{ 
						TmpData=*(lpOriginalCode+shang); 
						ReadData=((TmpData<>yushu); 
						yushu=(yushu+10)%8;	 
					} 
					*(lpDecodeData+ReadNum++)=((0xA3B0+ReadData/100))>>8; 
					*(lpDecodeData+ReadNum++)=(0xA3B0+ReadData/100); 
					*(lpDecodeData+ReadNum++)=((0xA3B0+(ReadData%100)/10))>>8; 
					*(lpDecodeData+ReadNum++)=(0xA3B0+(ReadData%100)/10); 
					*(lpDecodeData+ReadNum++)=((0xA3B0+(ReadData%100)%10))>>8; 
					*(lpDecodeData+ReadNum++)=(0xA3B0+(ReadData%100)%10); 
					 
	 
				} 
				if(Character[i]%3==1) 
				{ 
					if(yushu==0) 
						shang++; 
					TmpData=*(lpOriginalCode+shang); 
					if(yushu<5) 
					{ 
						ReadData=((TmpData<>4; 
						if(yushu==4) 
						{ 
							yushu=(yushu+4)%8; 
					//		shang++; 
						} 
						else 
							yushu=(yushu+4)%8; 
					} 
					else 
					{ 
						ReadData=((TmpData<>4; 
						shang++; 
						TmpData=*(lpOriginalCode+shang); 
						ReadData=ReadData|TmpData>>(12-yushu); 
						yushu=yushu-4; 
					} 
					*(lpDecodeData+ReadNum++)=(0xA3B0+ReadData)>>8; 
					*(lpDecodeData+ReadNum++)=0xA3B0+ReadData; 
					 
				} 
				else if(Character[i]%3==2) 
				{ 
					if(yushu==0) 
						shang++; 
					TmpData=*(lpOriginalCode+shang); 
					if(yushu<2) 
					{ 
						ReadData=((TmpData<>1; 
						if(yushu==1) 
						{ 
							yushu=(yushu+7)%8; 
					//		shang++; 
						} 
						else 
							yushu=1; 
					} 
					else 
					{ 
						ReadData=((TmpData<>1; 
						shang++; 
						TmpData=*(lpOriginalCode+shang); 
						ReadData=ReadData|TmpData>>(9-yushu); 
						yushu=yushu-1; 
					} 
					*(lpDecodeData+ReadNum++)=(0xA3B0+ReadData/10)>>8; 
					*(lpDecodeData+ReadNum++)=0xA3B0+ReadData/10; 
					*(lpDecodeData+ReadNum++)=(0xA3B0+ReadData%10)>>8; 
					*(lpDecodeData+ReadNum++)=0xA3B0+ReadData%10; 
					 
					 
				} 
				break; 
			case 0x02: 
				bRead=TRUE; 
				CharacterAmount=0; 
				CountBit=GetModeCountBit(VersionNum,ModeIndex[i]); 
				yushu=(BitAmount+4+CountBit)%8; 
				shang=(BitAmount+4+CountBit)/8; 
				BitAmount=BitAmount+Segment[i]; 
				while(bRead) 
				{ 
					TmpData=0; 
					CharacterAmount=CharacterAmount+2; 
					if(CharacterAmount>Character[i]) 
					{ 
						bRead=FALSE; 
						break; 
					} 
					if(yushu==0) 
						shang++; 
					if(yushu<6) 
					{ 
						TmpData=*(lpOriginalCode+shang); 
						ReadData=((TmpData<>(5-yushu)); 
						if(yushu==5) 
						{ 
					 	 	yushu=0; 
					// 	 	shang++; 
					 	} 
					 	else 
					 		yushu=(yushu+11)%8; 
					} 
					else 
					{ 
						TmpData=*(lpOriginalCode+shang); 
						ReadData=((TmpData<>(13-yushu)); 
						yushu=(yushu+11)%8;	 
					} 
					first=ReadData/45; 
					second=ReadData%45; 
					ReadData=TranslateChaNum(first); 
					*(lpDecodeData+ReadNum++)=ReadData>>8; 
					*(lpDecodeData+ReadNum++)=ReadData; 
					ReadData=TranslateChaNum(second); 
					*(lpDecodeData+ReadNum++)=ReadData>>8; 
					*(lpDecodeData+ReadNum++)=ReadData; 
					 
				} 
				if(Character[i]%2==1) 
				{ 
					if(yushu==0) 
						shang++; 
					TmpData=*(lpOriginalCode+shang); 
					if(yushu<3) 
					{ 
						ReadData=((TmpData<>2; 
						if(yushu==2) 
						{ 
							yushu=0; 
					//		shang++; 
						} 
						else 
							yushu=(yushu+6)%8; 
					} 
					else 
					{ 
						ReadData=((TmpData<>2; 
						shang++; 
						TmpData=*(lpOriginalCode+shang); 
						ReadData=ReadData|TmpData>>(10-yushu); 
						yushu=yushu-2; 
					} 
					second=ReadData%45; 
					ReadData=TranslateChaNum(second); 
					*(lpDecodeData+ReadNum++)=ReadData>>8; 
					*(lpDecodeData+ReadNum++)=ReadData; 
					 
				} 
				break; 
			case 0x04: 
				bRead=TRUE; 
				CharacterAmount=0; 
				CountBit=GetModeCountBit(VersionNum,ModeIndex[i]); 
				yushu=(BitAmount+4+CountBit)%8; 
				shang=(BitAmount+4+CountBit)/8; 
				BitAmount=BitAmount+Segment[i]; 
				while(bRead) 
				{ 
					TmpData=0; 
					CharacterAmount++; 
					if(CharacterAmount>Character[i]) 
					{ 
						bRead=FALSE; 
						break; 
					} 
					if(yushu==0) 
					{ 
						shang++; 
						ReadData=*(lpOriginalCode+shang); 
					} 
					else 
					{ 
						TmpData=*(lpOriginalCode+shang); 
						ReadData=((TmpData<>(8-yushu)); 
					} 
					if(ReadNum<2) 
						*(lpDecodeData+ReadNum++)=ReadData; 
					else 
					{ 
						*(lpDecodeData+ReadNum++)=(ReadData+0xA380)>>8; 
						*(lpDecodeData+ReadNum++)=ReadData+0xA380; 
						 
					} 
				} 
				break; 
			case 0x0D: 
				bRead=TRUE; 
				CharacterAmount=0; 
				CountBit=GetModeCountBit(VersionNum,ModeIndex[i]); 
				yushu=(BitAmount+8+CountBit)%8; 
				shang=(BitAmount+8+CountBit)/8; 
				if(yushu==0) 
					shang--; 
				BitAmount=BitAmount+Segment[i]; 
				while(bRead) 
				{ 
					TmpData=0; 
					CharacterAmount++; 
					if(CharacterAmount>Character[i]) 
					{ 
						bRead=FALSE; 
						break; 
					} 
					if(yushu==0) 
						shang++; 
					if(yushu<=3) 
					{ 
						TmpData=*(lpOriginalCode+shang); 
						ReadData=((TmpData<>(3-yushu)); 
						if(yushu==3) 
						{ 
					 	 	yushu=0; 
				//	 	 	shang++; 
					 	} 
					 	else 
					 		yushu=(yushu+13)%8; 
					} 
					else 
					{ 
						TmpData=*(lpOriginalCode+shang); 
						ReadData=((TmpData<>(11-yushu)); 
						yushu=(yushu+13)%8;	 
					} 
					first=ReadData/0x60; 
					if(first<0x0A) 
						first=first+0xA1; 
					else 
						first=first+0xA6; 
					*(lpDecodeData+ReadNum++)=first; 
					*(lpDecodeData+ReadNum++)=(ReadData%0x60)+0xA1; 
					 
				 
				} 
				break; 
			default: 
				break; 
		} 
		 
	} 
	*(lpDecodeData+ReadNum)='\0'; 
	if(hOriginalCode!=NULL) 
	{ 
		GlobalUnlock(hOriginalCode); 
		GlobalFree(hOriginalCode); 
	} 
	GlobalUnlock(hDecodeData); 
 
	return CharacterSum-1; 
 
} 
/************************************************************************** 
* 
*GetModeCountBit() 
* 
*Parameters: 
* 
*unsigned char VersionNum - the version number  information of the QR index image 
* 
*unsigned char mode - the code mode. 0x01 - digital mode;0x02 - character-number mode 
																		 0x04 - 8 bit byte mode;0x0D - Chinese mode  
* 
*RETURN value: 
* 
*		if this function runs properply,it returns bit digit of character counter of every mode 
* 
*************************************************************************/ 
unsigned char GetModeCountBit(unsigned char VersionNum,unsigned char mode) 
{ 
	switch(mode) 
	{ 
		case 0x01: 
			if(VersionNum>0&&VersionNum<10) 
				return 10; 
			if(VersionNum>9&&VersionNum<27) 
				return 12; 
			if(VersionNum>26&&VersionNum<41) 
				return 14; 
		case 0x02: 
			if(VersionNum>0&&VersionNum<10) 
				return 9; 
			if(VersionNum>9&&VersionNum<27) 
				return 11; 
			if(VersionNum>26&&VersionNum<41) 
				return 13; 
		case 0x04: 
			if(VersionNum>0&&VersionNum<10) 
				return 8; 
			if(VersionNum>9&&VersionNum<27) 
				return 16; 
			if(VersionNum>26&&VersionNum<41) 
				return 16; 
		case 0x0D: 
			if(VersionNum>0&&VersionNum<10) 
				return 8; 
			if(VersionNum>9&&VersionNum<27) 
				return 10; 
			if(VersionNum>26&&VersionNum<41) 
				return 12; 
		default: 
			return 0; 
	} 
	 
} 
 
unsigned short TranslateChaNum(unsigned char chanum) 
{ 
	unsigned short GBCha; 
	if(chanum<10) 
		GBCha=0xA3B0+chanum; 
	else if(chanum<36) 
		GBCha=0xA3B7+chanum; 
	else if(chanum==36) 
		GBCha=0xA3A0; 
	else if(chanum==37) 
		GBCha=0xA3A4; 
	else if(chanum==38) 
		GBCha=0xA3A5; 
	else if(chanum==39) 
		GBCha=0xA3AA; 
	else if(chanum==40) 
		GBCha=0xA3AB; 
	else if(chanum>40 && chanum<44) 
		GBCha=0xA384+chanum; 
	else if(chanum==44) 
		GBCha=0xA3BA; 
		 
	return GBCha; 
} 
 
HGLOBAL GetDecodeData(unsigned short * codenum,unsigned char VersionNum,unsigned char Format) 
{ 
	HGLOBAL OriginalCode=GetOriginalCode(hIndexData,VersionNum,Format); 
	*(codenum)=QRDecoder(OriginalCode,VersionNum,Format); 
	return hDecodeData; 
} 
 
HGLOBAL GetIndexImage() 
{ 
	return hIndexData; 
} 
HGLOBAL GetMaskImg() 
{ 
	return hMaskImg; 
}