/* * Copyright (c) 2010 Psytec Inc. * Copyright (c) 2012 Alexey Mednyy * Copyright (c) 2012-2014 Pavol Rusnak * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include "qr_encode.h" #include "qr_consts.h" static int m_nLevel; static int m_nVersion; static int m_nMaskingNo; static int m_ncDataCodeWordBit, m_ncAllCodeWord, nEncodeVersion; static int m_ncDataBlock; static int m_nSymbleSize; static int m_nBlockLength[QR_MAX_DATACODEWORD]; static uint8_t m_byModuleData[QR_MAX_MODULESIZE][QR_MAX_MODULESIZE]; // [x][y] static uint8_t m_byAllCodeWord[QR_MAX_ALLCODEWORD]; static uint8_t m_byBlockMode[QR_MAX_DATACODEWORD]; static uint8_t m_byDataCodeWord[QR_MAX_DATACODEWORD]; static uint8_t m_byRSWork[QR_MAX_CODEBLOCK]; static int IsNumeralData(uint8_t c) { if (c >= '0' && c <= '9') return 1; return 0; } static int IsAlphabetData(uint8_t c) { if (c >= '0' && c <= '9') return 1; if (c >= 'A' && c <= 'Z') return 1; if (c == ' ' || c == '$' || c == '%' || c == '*' || c == '+' || c == '-' || c == '.' || c == '/' || c == ':') return 1; return 0; } static uint8_t AlphabetToBinary(uint8_t c) { if (c >= '0' && c <= '9') return (uint8_t)(c - '0'); if (c >= 'A' && c <= 'Z') return (uint8_t)(c - 'A' + 10); if (c == ' ') return 36; if (c == '$') return 37; if (c == '%') return 38; if (c == '*') return 39; if (c == '+') return 40; if (c == '-') return 41; if (c == '.') return 42; if (c == '/') return 43; return 44; // c == ':' } static int SetBitStream(int nIndex, uint16_t wData, int ncData) { int i; if (nIndex == -1 || nIndex + ncData > QR_MAX_DATACODEWORD * 8) return -1; for (i = 0; i < ncData; i++) { if (wData & (1 << (ncData - i - 1))) { m_byDataCodeWord[(nIndex + i) / 8] |= 1 << (7 - ((nIndex + i) % 8)); } } return nIndex + ncData; } static int GetBitLength(uint8_t nMode, int ncData, int nVerGroup) { int ncBits = 0; switch (nMode) { case QR_MODE_NUMERAL: ncBits = 4 + nIndicatorLenNumeral[nVerGroup] + (10 * (ncData / 3)); switch (ncData % 3) { case 1: ncBits += 4; break; case 2: ncBits += 7; break; default: // case 0: break; } break; case QR_MODE_ALPHABET: ncBits = 4 + nIndicatorLenAlphabet[nVerGroup] + (11 * (ncData / 2)) + (6 * (ncData % 2)); break; default: // case QR_MODE_8BIT: ncBits = 4 + nIndicatorLen8Bit[nVerGroup] + (8 * ncData); break; } return ncBits; } static int EncodeSourceData(const char* lpsSource, int ncLength, int nVerGroup) { memset(m_nBlockLength, 0, sizeof(m_nBlockLength)); int i, j; // Investigate whether continuing characters (bytes) which mode is what for (m_ncDataBlock = i = 0; i < ncLength; i++) { uint8_t byMode; if (IsNumeralData(lpsSource[i])) { byMode = QR_MODE_NUMERAL; } else if (IsAlphabetData(lpsSource[i])) { byMode = QR_MODE_ALPHABET; } else { byMode = QR_MODE_8BIT; } if (i == 0) { m_byBlockMode[0] = byMode; } if (m_byBlockMode[m_ncDataBlock] != byMode) { m_byBlockMode[++m_ncDataBlock] = byMode; } m_nBlockLength[m_ncDataBlock]++; } m_ncDataBlock++; // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // / // Linked by a sequence of conditional block alphanumeric mode and numeric mode block adjacent int ncSrcBits, ncDstBits; // The bit length of the block mode if you have over the original bit length and a single alphanumeric int nBlock = 0; while (nBlock < m_ncDataBlock - 1) { int ncJoinFront, ncJoinBehind; // Bit length when combined with 8-bit byte block mode before and after int nJoinPosition = 0; // Block the binding of 8-bit byte mode: combined with the previous -1 = 0 = do not bind, bind behind a = // Sort of - "digit alphanumeric" - "or alphanumeric numbers" if ((m_byBlockMode[nBlock] == QR_MODE_NUMERAL && m_byBlockMode[nBlock + 1] == QR_MODE_ALPHABET) || (m_byBlockMode[nBlock] == QR_MODE_ALPHABET && m_byBlockMode[nBlock + 1] == QR_MODE_NUMERAL)) { // If you compare the bit length of alphanumeric characters and a single block mode over the original bit length ncSrcBits = GetBitLength(m_byBlockMode[nBlock], m_nBlockLength[nBlock], nVerGroup) + GetBitLength(m_byBlockMode[nBlock + 1], m_nBlockLength[nBlock + 1], nVerGroup); ncDstBits = GetBitLength(QR_MODE_ALPHABET, m_nBlockLength[nBlock] + m_nBlockLength[nBlock + 1], nVerGroup); if (ncSrcBits > ncDstBits) { // If there is an 8-bit byte block mode back and forth, check whether they favor the binding of if (nBlock >= 1 && m_byBlockMode[nBlock - 1] == QR_MODE_8BIT) { // There are 8-bit byte block mode before ncJoinFront = GetBitLength(QR_MODE_8BIT, m_nBlockLength[nBlock - 1] + m_nBlockLength[nBlock], nVerGroup) + GetBitLength(m_byBlockMode[nBlock + 1], m_nBlockLength[nBlock + 1], nVerGroup); if (ncJoinFront > ncDstBits + GetBitLength(QR_MODE_8BIT, m_nBlockLength[nBlock - 1], nVerGroup)) { ncJoinFront = 0; // 8-bit byte and block mode does not bind } } else { ncJoinFront = 0; } if (nBlock < m_ncDataBlock - 2 && m_byBlockMode[nBlock + 2] == QR_MODE_8BIT) { // There are 8-bit byte mode block behind ncJoinBehind = GetBitLength(m_byBlockMode[nBlock], m_nBlockLength[nBlock], nVerGroup) + GetBitLength(QR_MODE_8BIT, m_nBlockLength[nBlock + 1] + m_nBlockLength[nBlock + 2], nVerGroup); if (ncJoinBehind > ncDstBits + GetBitLength(QR_MODE_8BIT, m_nBlockLength[nBlock + 2], nVerGroup)) { ncJoinBehind = 0; // 8-bit byte and block mode does not bind } } else { ncJoinBehind = 0; } if (ncJoinFront != 0 && ncJoinBehind != 0) { // If there is a 8-bit byte block mode has priority both before and after the way the data length is shorter nJoinPosition = (ncJoinFront < ncJoinBehind) ? -1 : 1; } else { nJoinPosition = (ncJoinFront != 0) ? -1 : ((ncJoinBehind != 0) ? 1 : 0); } if (nJoinPosition != 0) { // Block the binding of 8-bit byte mode if (nJoinPosition == -1) { m_nBlockLength[nBlock - 1] += m_nBlockLength[nBlock]; // The subsequent shift for (i = nBlock; i < m_ncDataBlock - 1; i++) { m_byBlockMode[i] = m_byBlockMode[i + 1]; m_nBlockLength[i] = m_nBlockLength[i + 1]; } } else { m_byBlockMode[nBlock + 1] = QR_MODE_8BIT; m_nBlockLength[nBlock + 1] += m_nBlockLength[nBlock + 2]; // The subsequent shift for (i = nBlock + 2; i < m_ncDataBlock - 1; i++) { m_byBlockMode[i] = m_byBlockMode[i + 1]; m_nBlockLength[i] = m_nBlockLength[i + 1]; } } m_ncDataBlock--; } else { // Block mode integrated into a single alphanumeric string of numbers and alphanumeric if (nBlock < m_ncDataBlock - 2 && m_byBlockMode[nBlock + 2] == QR_MODE_ALPHABET) { // Binding mode of the block followed by alphanumeric block attempts to join m_nBlockLength[nBlock + 1] += m_nBlockLength[nBlock + 2]; // The subsequent shift for (i = nBlock + 2; i < m_ncDataBlock - 1; i++) { m_byBlockMode[i] = m_byBlockMode[i + 1]; m_nBlockLength[i] = m_nBlockLength[i + 1]; } m_ncDataBlock--; } m_byBlockMode[nBlock] = QR_MODE_ALPHABET; m_nBlockLength[nBlock] += m_nBlockLength[nBlock + 1]; // The subsequent shift for (i = nBlock + 1; i < m_ncDataBlock - 1; i++) { m_byBlockMode[i] = m_byBlockMode[i + 1]; m_nBlockLength[i] = m_nBlockLength[i + 1]; } m_ncDataBlock--; if (nBlock >= 1 && m_byBlockMode[nBlock - 1] == QR_MODE_ALPHABET) { // Combined mode of alphanumeric block before the block bound m_nBlockLength[nBlock - 1] += m_nBlockLength[nBlock]; // The subsequent shift for (i = nBlock; i < m_ncDataBlock - 1; i++) { m_byBlockMode[i] = m_byBlockMode[i + 1]; m_nBlockLength[i] = m_nBlockLength[i + 1]; } m_ncDataBlock--; } } continue; // Re-examine the block of the current position } } nBlock++; // Investigate the next block } // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // / // 8-bit byte block mode over the short block mode to continuous nBlock = 0; while (nBlock < m_ncDataBlock - 1) { ncSrcBits = GetBitLength(m_byBlockMode[nBlock], m_nBlockLength[nBlock], nVerGroup) + GetBitLength(m_byBlockMode[nBlock + 1], m_nBlockLength[nBlock + 1], nVerGroup); ncDstBits = GetBitLength(QR_MODE_8BIT, m_nBlockLength[nBlock] + m_nBlockLength[nBlock + 1], nVerGroup); // If there is a 8-bit byte block mode before, subtract the duplicate indicator minute if (nBlock >= 1 && m_byBlockMode[nBlock - 1] == QR_MODE_8BIT) { ncDstBits -= (4 + nIndicatorLen8Bit[nVerGroup]); } // If there is a block behind the 8-bit byte mode, subtract the duplicate indicator minute if (nBlock < m_ncDataBlock - 2 && m_byBlockMode[nBlock + 2] == QR_MODE_8BIT) { ncDstBits -= (4 + nIndicatorLen8Bit[nVerGroup]); } if (ncSrcBits > ncDstBits) { if (nBlock >= 1 && m_byBlockMode[nBlock - 1] == QR_MODE_8BIT) { // 8-bit byte mode coupling block in front of the block to join m_nBlockLength[nBlock - 1] += m_nBlockLength[nBlock]; // The subsequent shift for (i = nBlock; i < m_ncDataBlock - 1; i++) { m_byBlockMode[i] = m_byBlockMode[i + 1]; m_nBlockLength[i] = m_nBlockLength[i + 1]; } m_ncDataBlock--; nBlock--; } if (nBlock < m_ncDataBlock - 2 && m_byBlockMode[nBlock + 2] == QR_MODE_8BIT) { // 8-bit byte mode coupling block at the back of the block to join m_nBlockLength[nBlock + 1] += m_nBlockLength[nBlock + 2]; // The subsequent shift for (i = nBlock + 2; i < m_ncDataBlock - 1; i++) { m_byBlockMode[i] = m_byBlockMode[i + 1]; m_nBlockLength[i] = m_nBlockLength[i + 1]; } m_ncDataBlock--; } m_byBlockMode[nBlock] = QR_MODE_8BIT; m_nBlockLength[nBlock] += m_nBlockLength[nBlock + 1]; // The subsequent shift for (i = nBlock + 1; i < m_ncDataBlock - 1; i++) { m_byBlockMode[i] = m_byBlockMode[i + 1]; m_nBlockLength[i] = m_nBlockLength[i + 1]; } m_ncDataBlock--; // Re-examination in front of the block bound if (nBlock >= 1) { nBlock--; } continue; } nBlock++;// Investigate the next block } // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // / // Mosquito bit array int ncComplete = 0; // Data pre-processing counter uint16_t wBinCode; m_ncDataCodeWordBit = 0;// Bit counter processing unit memset(m_byDataCodeWord, 0, sizeof(m_byDataCodeWord)); for (i = 0; i < m_ncDataBlock && m_ncDataCodeWordBit != -1; i++) { if (m_byBlockMode[i] == QR_MODE_NUMERAL) { // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // / // Numeric mode // Indicator (0001b) m_ncDataCodeWordBit = SetBitStream(m_ncDataCodeWordBit, 1, 4); // Set number of characters m_ncDataCodeWordBit = SetBitStream(m_ncDataCodeWordBit, (uint16_t)m_nBlockLength[i], nIndicatorLenNumeral[nVerGroup]); // Save the bit string for (j = 0; j < m_nBlockLength[i]; j += 3) { if (j < m_nBlockLength[i] - 2) { wBinCode = (uint16_t)(((lpsSource[ncComplete + j] - '0') * 100) + ((lpsSource[ncComplete + j + 1] - '0') * 10) + (lpsSource[ncComplete + j + 2] - '0')); m_ncDataCodeWordBit = SetBitStream(m_ncDataCodeWordBit, wBinCode, 10); } else if (j == m_nBlockLength[i] - 2) { // 2 bytes fraction wBinCode = (uint16_t)(((lpsSource[ncComplete + j] - '0') * 10) + (lpsSource[ncComplete + j + 1] - '0')); m_ncDataCodeWordBit = SetBitStream(m_ncDataCodeWordBit, wBinCode, 7); } else if (j == m_nBlockLength[i] - 1) { // A fraction of bytes wBinCode = (uint16_t)(lpsSource[ncComplete + j] - '0'); m_ncDataCodeWordBit = SetBitStream(m_ncDataCodeWordBit, wBinCode, 4); } } ncComplete += m_nBlockLength[i]; } else if (m_byBlockMode[i] == QR_MODE_ALPHABET) { // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // / // Alphanumeric mode // Mode indicator (0010b) m_ncDataCodeWordBit = SetBitStream(m_ncDataCodeWordBit, 2, 4); // Set number of characters m_ncDataCodeWordBit = SetBitStream(m_ncDataCodeWordBit, (uint16_t)m_nBlockLength[i], nIndicatorLenAlphabet[nVerGroup]); // Save the bit string for (j = 0; j < m_nBlockLength[i]; j += 2) { if (j < m_nBlockLength[i] - 1) { wBinCode = (uint16_t)((AlphabetToBinary(lpsSource[ncComplete + j]) * 45) + AlphabetToBinary(lpsSource[ncComplete + j + 1])); m_ncDataCodeWordBit = SetBitStream(m_ncDataCodeWordBit, wBinCode, 11); } else { // A fraction of bytes wBinCode = (uint16_t)AlphabetToBinary(lpsSource[ncComplete + j]); m_ncDataCodeWordBit = SetBitStream(m_ncDataCodeWordBit, wBinCode, 6); } } ncComplete += m_nBlockLength[i]; } else { // (m_byBlockMode[i] == QR_MODE_8BIT) // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // / // 8-bit byte mode // Mode indicator (0100b) m_ncDataCodeWordBit = SetBitStream(m_ncDataCodeWordBit, 4, 4); // Set number of characters m_ncDataCodeWordBit = SetBitStream(m_ncDataCodeWordBit, (uint16_t)m_nBlockLength[i], nIndicatorLen8Bit[nVerGroup]); // Save the bit string for (j = 0; j < m_nBlockLength[i]; j++) { m_ncDataCodeWordBit = SetBitStream(m_ncDataCodeWordBit, (uint16_t)lpsSource[ncComplete + j], 8); } ncComplete += m_nBlockLength[i]; } } return (m_ncDataCodeWordBit != -1); } // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // / // APPLICATIONS: To get the bit length // Args: data mode type, data length, group version (model number) // Returns: data bit length static int GetEncodeVersion(int nVersion, const char* lpsSource, int ncLength) { int nVerGroup = nVersion >= 27 ? QR_VERSION_L : (nVersion >= 10 ? QR_VERSION_M : QR_VERSION_S); int i, j; for (i = nVerGroup; i <= QR_VERSION_L; i++) { if (EncodeSourceData(lpsSource, ncLength, i)) { if (i == QR_VERSION_S) { for (j = 1; j <= 9; j++) { if ((m_ncDataCodeWordBit + 7) / 8 <= QR_VersonInfo[j].ncDataCodeWord[m_nLevel]) { return j; } } } #if QR_MAX_VERSION >= QR_VERSION_M else if (i == QR_VERSION_M) { for (j = 10; j <= 26; j++) { if ((m_ncDataCodeWordBit + 7) / 8 <= QR_VersonInfo[j].ncDataCodeWord[m_nLevel]) { return j; } } } #endif #if QR_MAX_VERSION >= QR_VERSION_L else if (i == QR_VERSION_L) { for (j = 27; j <= 40; j++) { if ((m_ncDataCodeWordBit + 7) / 8 <= QR_VersonInfo[j].ncDataCodeWord[m_nLevel]) { return j; } } } #endif } } return 0; } static void GetRSCodeWord(uint8_t* lpbyRSWork, int ncDataCodeWord, int ncRSCodeWord) { int i, j; for (i = 0; i < ncDataCodeWord ; i++) { if (lpbyRSWork[0] != 0) { uint8_t nExpFirst = byIntToExp[lpbyRSWork[0]]; // Multiplier coefficient is calculated from the first term for (j = 0; j < ncRSCodeWord; j++) { // Add (% 255 ^ 255 = 1) the first term multiplier to multiplier sections uint8_t nExpElement = (uint8_t)(((int)(byRSExp[ncRSCodeWord][j] + nExpFirst)) % 255); // Surplus calculated by the exclusive lpbyRSWork[j] = (uint8_t)(lpbyRSWork[j + 1] ^ byExpToInt[nExpElement]); } // Shift the remaining digits for (j = ncRSCodeWord; j < ncDataCodeWord + ncRSCodeWord - 1; j++) { lpbyRSWork[j] = lpbyRSWork[j + 1]; } } else { // Shift the remaining digits for (j = 0; j < ncDataCodeWord + ncRSCodeWord - 1; j++) { lpbyRSWork[j] = lpbyRSWork[j + 1]; } } } } static void SetFinderPattern(int x, int y) { static const uint8_t byPattern[] = { 0x7f, // 1111111b 0x41, // 1000001b 0x5d, // 1011101b 0x5d, // 1011101b 0x5d, // 1011101b 0x41, // 1000001b 0x7f}; // 1111111b int i, j; for (i = 0; i < 7; i++) { for (j = 0; j < 7; j++) { m_byModuleData[x + j][y + i] = (byPattern[i] & (1 << (6 - j))) ? '\x30' : '\x20'; } } } static void SetVersionPattern(void) { int i, j; if (m_nVersion <= 6) { return; } int nVerData = m_nVersion << 12; // Calculated bit remainder for (i = 0; i < 6; i++) { if (nVerData & (1 << (17 - i))) { nVerData ^= (0x1f25 << (5 - i)); } } nVerData += m_nVersion << 12; for (i = 0; i < 6; i++) { for (j = 0; j < 3; j++) { m_byModuleData[m_nSymbleSize - 11 + j][i] = m_byModuleData[i][m_nSymbleSize - 11 + j] = (nVerData & (1 << (i * 3 + j))) ? '\x30' : '\x20'; } } } static void SetAlignmentPattern(int x, int y) { static const uint8_t byPattern[] = { 0x1f, // 11111b 0x11, // 10001b 0x15, // 10101b 0x11, // 10001b 0x1f}; // 11111b int i, j; if (m_byModuleData[x][y] & 0x20) { return; // Excluded due to overlap with the functional module } x -= 2; y -= 2; // Convert the coordinates to the upper left corner for (i = 0; i < 5; i++) { for (j = 0; j < 5; j++) { m_byModuleData[x + j][y + i] = (byPattern[i] & (1 << (4 - j))) ? '\x30' : '\x20'; } } } static void SetFunctionModule(void) { int i, j; // Position detection pattern SetFinderPattern(0, 0); SetFinderPattern(m_nSymbleSize - 7, 0); SetFinderPattern(0, m_nSymbleSize - 7); // Separator pattern position detection for (i = 0; i < 8; i++) { m_byModuleData[i][7] = m_byModuleData[7][i] = '\x20'; m_byModuleData[m_nSymbleSize - 8][i] = m_byModuleData[m_nSymbleSize - 8 + i][7] = '\x20'; m_byModuleData[i][m_nSymbleSize - 8] = m_byModuleData[7][m_nSymbleSize - 8 + i] = '\x20'; } // Registration as part of a functional module position description format information for (i = 0; i < 9; i++) { m_byModuleData[i][8] = m_byModuleData[8][i] = '\x20'; } for (i = 0; i < 8; i++) { m_byModuleData[m_nSymbleSize - 8 + i][8] = m_byModuleData[8][m_nSymbleSize - 8 + i] = '\x20'; } // Version information pattern SetVersionPattern(); // Pattern alignment for (i = 0; i < QR_VersonInfo[m_nVersion].ncAlignPoint; i++) { SetAlignmentPattern(QR_VersonInfo[m_nVersion].nAlignPoint[i], 6); SetAlignmentPattern(6, QR_VersonInfo[m_nVersion].nAlignPoint[i]); for (j = 0; j < QR_VersonInfo[m_nVersion].ncAlignPoint; j++) { SetAlignmentPattern(QR_VersonInfo[m_nVersion].nAlignPoint[i], QR_VersonInfo[m_nVersion].nAlignPoint[j]); } } // Timing pattern for (i = 8; i <= m_nSymbleSize - 9; i++) { m_byModuleData[i][6] = (i % 2) == 0 ? '\x30' : '\x20'; m_byModuleData[6][i] = (i % 2) == 0 ? '\x30' : '\x20'; } } static void SetCodeWordPattern(void) { int x = m_nSymbleSize; int y = m_nSymbleSize - 1; int nCoef_x = 1; // placement orientation axis x int nCoef_y = 1; // placement orientation axis y int i, j; for (i = 0; i < m_ncAllCodeWord; i++) { for (j = 0; j < 8; j++) { do { x += nCoef_x; nCoef_x *= -1; if (nCoef_x < 0) { y += nCoef_y; if (y < 0 || y == m_nSymbleSize) { y = (y < 0) ? 0 : m_nSymbleSize - 1; nCoef_y *= -1; x -= 2; if (x == 6) { // Timing pattern x--; } } } } while (m_byModuleData[x][y] & 0x20); // Exclude a functional module m_byModuleData[x][y] = (m_byAllCodeWord[i] & (1 << (7 - j))) ? '\x02' : '\x00'; } } } static void SetMaskingPattern(int nPatternNo) { int i, j; for (i = 0; i < m_nSymbleSize; i++) { for (j = 0; j < m_nSymbleSize; j++) { if (! (m_byModuleData[j][i] & 0x20)) { // Exclude a functional module int bMask; switch (nPatternNo) { case 0: bMask = ((i + j) % 2 == 0); break; case 1: bMask = (i % 2 == 0); break; case 2: bMask = (j % 3 == 0); break; case 3: bMask = ((i + j) % 3 == 0); break; case 4: bMask = (((i / 2) + (j / 3)) % 2 == 0); break; case 5: bMask = (((i * j) % 2) + ((i * j) % 3) == 0); break; case 6: bMask = ((((i * j) % 2) + ((i * j) % 3)) % 2 == 0); break; default: // case 7: bMask = ((((i * j) % 3) + ((i + j) % 2)) % 2 == 0); break; } m_byModuleData[j][i] = (uint8_t)((m_byModuleData[j][i] & 0xfe) | (((m_byModuleData[j][i] & 0x02) > 1) ^ bMask)); } } } } static void SetFormatInfoPattern(int nPatternNo) { int nFormatInfo; int i; switch (m_nLevel) { case QR_LEVEL_L: nFormatInfo = 0x08; // 01nnnb break; case QR_LEVEL_M: nFormatInfo = 0x00; // 00nnnb break; case QR_LEVEL_Q: nFormatInfo = 0x18; // 11nnnb break; default: // case QR_LEVEL_H: nFormatInfo = 0x10; // 10nnnb break; } nFormatInfo += nPatternNo; int nFormatData = nFormatInfo << 10; // Calculated bit remainder for (i = 0; i < 5; i++) { if (nFormatData & (1 << (14 - i))) { nFormatData ^= (0x0537 << (4 - i)); // 10100110111b } } nFormatData += nFormatInfo << 10; // Masking nFormatData ^= 0x5412; // 101010000010010b // Position detection patterns located around the upper left for (i = 0; i <= 5; i++) { m_byModuleData[8][i] = (nFormatData & (1 << i)) ? '\x30' : '\x20'; } m_byModuleData[8][7] = (nFormatData & (1 << 6)) ? '\x30' : '\x20'; m_byModuleData[8][8] = (nFormatData & (1 << 7)) ? '\x30' : '\x20'; m_byModuleData[7][8] = (nFormatData & (1 << 8)) ? '\x30' : '\x20'; for (i = 9; i <= 14; i++) { m_byModuleData[14 - i][8] = (nFormatData & (1 << i)) ? '\x30' : '\x20'; } // Position detection patterns located under the upper right corner for (i = 0; i <= 7; i++) { m_byModuleData[m_nSymbleSize - 1 - i][8] = (nFormatData & (1 << i)) ? '\x30' : '\x20'; } // Right lower left position detection patterns located m_byModuleData[8][m_nSymbleSize - 8] = '\x30'; // Module fixed dark for (i = 8; i <= 14; i++) { m_byModuleData[8][m_nSymbleSize - 15 + i] = (nFormatData & (1 << i)) ? '\x30' : '\x20'; } } static int CountPenalty(void) { int nPenalty = 0; int i, j, k; // Column of the same color adjacent module for (i = 0; i < m_nSymbleSize; i++) { for (j = 0; j < m_nSymbleSize - 4; j++) { int nCount = 1; for (k = j + 1; k < m_nSymbleSize; k++) { if (((m_byModuleData[i][j] & 0x11) == 0) == ((m_byModuleData[i][k] & 0x11) == 0)) { nCount++; } else { break; } } if (nCount >= 5) { nPenalty += 3 + (nCount - 5); } j = k - 1; } } // Adjacent module line of the same color for (i = 0; i < m_nSymbleSize; i++) { for (j = 0; j < m_nSymbleSize - 4; j++) { int nCount = 1; for (k = j + 1; k < m_nSymbleSize; k++) { if (((m_byModuleData[j][i] & 0x11) == 0) == ((m_byModuleData[k][i] & 0x11) == 0)) { nCount++; } else { break; } } if (nCount >= 5) { nPenalty += 3 + (nCount - 5); } j = k - 1; } } // Modules of the same color block (2 ~ 2) for (i = 0; i < m_nSymbleSize - 1; i++) { for (j = 0; j < m_nSymbleSize - 1; j++) { if ((((m_byModuleData[i][j] & 0x11) == 0) == ((m_byModuleData[i + 1][j] & 0x11) == 0)) && (((m_byModuleData[i][j] & 0x11) == 0) == ((m_byModuleData[i] [j + 1] & 0x11) == 0)) && (((m_byModuleData[i][j] & 0x11) == 0) == ((m_byModuleData[i + 1][j + 1] & 0x11) == 0))) { nPenalty += 3; } } } // Pattern (dark dark: light: dark: light) ratio 1:1:3:1:1 in the same column for (i = 0; i < m_nSymbleSize; i++) { for (j = 0; j < m_nSymbleSize - 6; j++) { if (((j == 0) || (! (m_byModuleData[i][j - 1] & 0x11))) && ( m_byModuleData[i][j ] & 0x11) && (! (m_byModuleData[i][j + 1] & 0x11)) && ( m_byModuleData[i][j + 2] & 0x11) && ( m_byModuleData[i][j + 3] & 0x11) && ( m_byModuleData[i][j + 4] & 0x11) && (! (m_byModuleData[i][j + 5] & 0x11)) && ( m_byModuleData[i][j + 6] & 0x11) && ((j == m_nSymbleSize - 7) || (! (m_byModuleData[i][j + 7] & 0x11)))) { // Clear pattern of four or more before or after if (((j < 2 || ! (m_byModuleData[i][j - 2] & 0x11)) && (j < 3 || ! (m_byModuleData[i][j - 3] & 0x11)) && (j < 4 || ! (m_byModuleData[i][j - 4] & 0x11))) || ((j >= m_nSymbleSize - 8 || ! (m_byModuleData[i][j + 8] & 0x11)) && (j >= m_nSymbleSize - 9 || ! (m_byModuleData[i][j + 9] & 0x11)) && (j >= m_nSymbleSize - 10 || ! (m_byModuleData[i][j + 10] & 0x11)))) { nPenalty += 40; } } } } // Pattern (dark dark: light: dark: light) in the same line ratio 1:1:3:1:1 for (i = 0; i < m_nSymbleSize; i++) { for (j = 0; j < m_nSymbleSize - 6; j++) { if (((j == 0) || (! (m_byModuleData[j - 1][i] & 0x11))) && ( m_byModuleData[j ] [i] & 0x11) && (! (m_byModuleData[j + 1][i] & 0x11)) && ( m_byModuleData[j + 2][i] & 0x11) && ( m_byModuleData[j + 3][i] & 0x11) && ( m_byModuleData[j + 4][i] & 0x11) && (! (m_byModuleData[j + 5][i] & 0x11)) && ( m_byModuleData[j + 6][i] & 0x11) && ((j == m_nSymbleSize - 7) || (! (m_byModuleData[j + 7][i] & 0x11)))) { // Clear pattern of four or more before or after if (((j < 2 || ! (m_byModuleData[j - 2][i] & 0x11)) && (j < 3 || ! (m_byModuleData[j - 3][i] & 0x11)) && (j < 4 || ! (m_byModuleData[j - 4][i] & 0x11))) || ((j >= m_nSymbleSize - 8 || ! (m_byModuleData[j + 8][i] & 0x11)) && (j >= m_nSymbleSize - 9 || ! (m_byModuleData[j + 9][i] & 0x11)) && (j >= m_nSymbleSize - 10 || ! (m_byModuleData[j + 10][i] & 0x11)))) { nPenalty += 40; } } } } // The proportion of modules for the entire dark int nCount = 0; for (i = 0; i < m_nSymbleSize; i++) { for (j = 0; j < m_nSymbleSize; j++) { if (! (m_byModuleData[i][j] & 0x11)) { nCount++; } } } nPenalty += (abs(50 - ((nCount * 100) / (m_nSymbleSize * m_nSymbleSize))) / 5) * 10; return nPenalty; } static void FormatModule(void) { int i, j; memset(m_byModuleData, 0, sizeof(m_byModuleData)); // Function module placement SetFunctionModule(); // Data placement SetCodeWordPattern(); if (m_nMaskingNo == -1) { // Select the best pattern masking m_nMaskingNo = 0; SetMaskingPattern(m_nMaskingNo); // Masking SetFormatInfoPattern(m_nMaskingNo); // Placement pattern format information int nMinPenalty = CountPenalty(); for (i = 1; i <= 7; i++) { SetMaskingPattern(i); // Masking SetFormatInfoPattern(i); // Placement pattern format information int nPenalty = CountPenalty(); if (nPenalty < nMinPenalty) { nMinPenalty = nPenalty; m_nMaskingNo = i; } } } SetMaskingPattern(m_nMaskingNo); // Masking SetFormatInfoPattern(m_nMaskingNo); // Placement pattern format information // The module pattern converted to a Boolean value for (i = 0; i < m_nSymbleSize; i++) { for (j = 0; j < m_nSymbleSize; j++) { m_byModuleData[i][j] = (uint8_t)((m_byModuleData[i][j] & 0x11) != 0); } } } static void putBitToPos(uint32_t pos, int bw, uint8_t *bits) { if (bw == 0) return; uint32_t tmp; uint32_t bitpos[8] = {128, 64, 32, 16, 8, 4, 2, 1}; if (pos % 8 == 0) { tmp = (pos / 8) - 1; bits[tmp] = bits[tmp] ^ bitpos[7]; } else { tmp = pos / 8; bits[tmp] = bits[tmp] ^ bitpos[pos % 8 - 1]; } } int qr_encode(int level, int version, const char *source, size_t source_len, uint8_t *result) { int i, j; const bool auto_extent = 0; m_nLevel = level; m_nMaskingNo = -1; memset(result, 0, QR_MAX_BITDATA); // If the data length is not specified, acquired by lstrlen size_t ncLength = source_len > 0 ? source_len : strlen(source); if (ncLength == 0) { return -1; // No data } // Check version (model number) nEncodeVersion = GetEncodeVersion(version, source, ncLength); if (nEncodeVersion == 0) { return -1; // Over-capacity } if (version == 0) { // Auto Part m_nVersion = nEncodeVersion; } else { if (nEncodeVersion <= version) { m_nVersion = version; } else { if (auto_extent) { m_nVersion = nEncodeVersion; // Automatic extended version (model number) } else { return -1; // Over-capacity } } } // Terminator addition code "0000" int ncDataCodeWord = QR_VersonInfo[m_nVersion].ncDataCodeWord[level]; int ncTerminater = (ncDataCodeWord * 8) - m_ncDataCodeWordBit; if (ncTerminater < 4) { ncTerminater = 4; } if (ncTerminater > 0) { m_ncDataCodeWordBit = SetBitStream(m_ncDataCodeWordBit, 0, ncTerminater); } // Additional padding code "11101100, 00010001" uint8_t byPaddingCode = 0xec; for (i = (m_ncDataCodeWordBit + 7) / 8; i < ncDataCodeWord; i++) { m_byDataCodeWord[i] = byPaddingCode; byPaddingCode = (uint8_t)(byPaddingCode == 0xec ? 0x11 : 0xec); } // Calculated the total clear area code word m_ncAllCodeWord = QR_VersonInfo[m_nVersion].ncAllCodeWord; memset(m_byAllCodeWord, 0, sizeof(m_byAllCodeWord)); int nDataCwIndex = 0; // Position data processing code word // Division number data block int ncBlock1 = QR_VersonInfo[m_nVersion].RS_BlockInfo1[level].ncRSBlock; int ncBlock2 = QR_VersonInfo[m_nVersion].RS_BlockInfo2[level].ncRSBlock; int ncBlockSum = ncBlock1 + ncBlock2; int nBlockNo = 0; // Block number in the process // The number of data code words by block int ncDataCw1 = QR_VersonInfo[m_nVersion].RS_BlockInfo1[level].ncDataCodeWord; int ncDataCw2 = QR_VersonInfo[m_nVersion].RS_BlockInfo2[level].ncDataCodeWord; // Code word interleaving data placement for (i = 0; i < ncBlock1; i++) { for (j = 0; j < ncDataCw1; j++) { m_byAllCodeWord[(ncBlockSum * j) + nBlockNo] = m_byDataCodeWord[nDataCwIndex++]; } nBlockNo++; } for (i = 0; i < ncBlock2; i++) { for (j = 0; j < ncDataCw2; j++) { if (j < ncDataCw1) { m_byAllCodeWord[(ncBlockSum * j) + nBlockNo] = m_byDataCodeWord[nDataCwIndex++]; } else { // 2 minute fraction block placement event m_byAllCodeWord[(ncBlockSum * ncDataCw1) + i] = m_byDataCodeWord[nDataCwIndex++]; } } nBlockNo++; } // RS code words by block number (currently the same number) int ncRSCw1 = QR_VersonInfo[m_nVersion].RS_BlockInfo1[level].ncAllCodeWord - ncDataCw1; int ncRSCw2 = QR_VersonInfo[m_nVersion].RS_BlockInfo2[level].ncAllCodeWord - ncDataCw2; // RS code word is calculated nDataCwIndex = 0; nBlockNo = 0; for (i = 0; i < ncBlock1; i++) { memset(m_byRSWork, 0, sizeof(m_byRSWork)); memmove(m_byRSWork, m_byDataCodeWord + nDataCwIndex, ncDataCw1); GetRSCodeWord(m_byRSWork, ncDataCw1, ncRSCw1); // RS code word placement for (j = 0; j < ncRSCw1; j++) { m_byAllCodeWord[ncDataCodeWord + (ncBlockSum * j) + nBlockNo] = m_byRSWork[j]; } nDataCwIndex += ncDataCw1; nBlockNo++; } for (i = 0; i < ncBlock2; i++) { memset(m_byRSWork, 0, sizeof(m_byRSWork)); memmove(m_byRSWork, m_byDataCodeWord + nDataCwIndex, ncDataCw2); GetRSCodeWord(m_byRSWork, ncDataCw2, ncRSCw2); // RS code word placement for (j = 0; j < ncRSCw2; j++) { m_byAllCodeWord[ncDataCodeWord + (ncBlockSum * j) + nBlockNo] = m_byRSWork[j]; } nDataCwIndex += ncDataCw2; nBlockNo++; } m_nSymbleSize = m_nVersion * 4 + 17; // Module placement FormatModule(); for (i = 0; i < m_nSymbleSize; i++) { for (j = 0; j < m_nSymbleSize; j++) { if (!m_byModuleData[i][j]) { putBitToPos((j * m_nSymbleSize) + i + 1, 0, result); } else { putBitToPos((j * m_nSymbleSize) + i + 1, 1, result); } } } return m_nSymbleSize; }