31 #define testable static
63 const uint8_t generator[],
int degree, uint8_t result[]);
67static void drawLightFunctionModules(uint8_t qrcode[],
int version);
70static void fillRectangle(
int left,
int top,
int width,
int height, uint8_t qrcode[]);
72static void drawCodewords(
const uint8_t data[],
int dataLen, uint8_t qrcode[]);
73static void applyMask(
const uint8_t functionModules[], uint8_t qrcode[],
enum qrcodegen_Mask mask);
74static long getPenaltyScore(
const uint8_t qrcode[]);
75static int finderPenaltyCountPatterns(
const int runHistory[7],
int qrsize);
76static int finderPenaltyTerminateAndCount(
bool currentRunColor,
int currentRunLength,
int runHistory[7],
int qrsize);
77static void finderPenaltyAddHistory(
int currentRunLength,
int runHistory[7],
int qrsize);
82static bool getBit(
int x,
int i);
94static const char *ALPHANUMERIC_CHARSET =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
100 {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
101 {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28},
102 {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
103 {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
106#define qrcodegen_REED_SOLOMON_DEGREE_MAX 30
112 {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25},
113 {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49},
114 {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68},
115 {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81},
119static const int PENALTY_N1 = 3;
120static const int PENALTY_N2 = 3;
121static const int PENALTY_N3 = 40;
122static const int PENALTY_N4 = 10;
132 size_t textLen = strlen(text);
147 if (textLen > bufLen)
149 for (
size_t i = 0; i < textLen; i++)
150 tempBuffer[i] = (uint8_t)text[i];
156 seg.
data = tempBuffer;
178 seg.
data = dataAndTemp;
186 assert(0 <= numBits && numBits <= 16 && (
unsigned long)val >> numBits == 0);
187 for (
int i = numBits - 1; i >= 0; i--, (*bitLen)++)
188 buffer[*bitLen >> 3] |= ((val >> i) & 1) << (7 - (*bitLen & 7));
197 enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]) {
205 int minVersion,
int maxVersion,
enum qrcodegen_Mask mask,
bool boostEcl, uint8_t tempBuffer[], uint8_t qrcode[]) {
206 assert(segs != NULL || len == 0);
208 assert(0 <= (
int)ecl && (
int)ecl <= 3 && -1 <= (
int)mask && (
int)mask <= 7);
211 int version, dataUsedBits;
212 for (version = minVersion; ; version++) {
215 if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
217 if (version >= maxVersion) {
222 assert(dataUsedBits != -1);
233 for (
size_t i = 0; i < len; i++) {
237 for (
int j = 0; j < seg->
bitLength; j++) {
238 int bit = (seg->
data[j >> 3] >> (7 - (j & 7))) & 1;
242 assert(bitLen == dataUsedBits);
246 assert(bitLen <= dataCapacityBits);
247 int terminatorBits = dataCapacityBits - bitLen;
248 if (terminatorBits > 4)
252 assert(bitLen % 8 == 0);
255 for (uint8_t padByte = 0xEC; bitLen < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
262 drawLightFunctionModules(qrcode, version);
267 long minPenalty = LONG_MAX;
268 for (
int i = 0; i < 8; i++) {
270 applyMask(tempBuffer, qrcode, msk);
271 drawFormatBits(ecl, msk, qrcode);
272 long penalty = getPenaltyScore(qrcode);
273 if (penalty < minPenalty) {
275 minPenalty = penalty;
277 applyMask(tempBuffer, qrcode, msk);
280 assert(0 <= (
int)mask && (
int)mask <= 7);
281 applyMask(tempBuffer, qrcode, mask);
282 drawFormatBits(ecl, mask, qrcode);
301 int numShortBlocks = numBlocks - rawCodewords % numBlocks;
302 int shortBlockDataLen = rawCodewords / numBlocks - blockEccLen;
308 const uint8_t *dat =
data;
309 for (
int i = 0; i < numBlocks; i++) {
310 int datLen = shortBlockDataLen + (i < numShortBlocks ? 0 : 1);
311 uint8_t *ecc = &
data[dataLen];
313 for (
int j = 0, k = i; j < datLen; j++, k += numBlocks) {
314 if (j == shortBlockDataLen)
318 for (
int j = 0, k = dataLen + i; j < blockEccLen; j++, k += numBlocks)
328 int v = version, e = (int)ecl;
329 assert(0 <= e && e < 4);
341 int result = (16 * ver + 128) * ver + 64;
343 int numAlign = ver / 7 + 2;
344 result -= (25 * numAlign - 10) * numAlign - 55;
348 assert(208 <= result && result <= 29648);
362 memset(result, 0, (
size_t)degree *
sizeof(result[0]));
363 result[degree - 1] = 1;
369 for (
int i = 0; i < degree; i++) {
371 for (
int j = 0; j < degree; j++) {
374 result[j] ^= result[j + 1];
385 const uint8_t generator[],
int degree, uint8_t result[]) {
387 memset(result, 0, (
size_t)degree *
sizeof(result[0]));
388 for (
int i = 0; i < dataLen; i++) {
389 uint8_t factor =
data[i] ^ result[0];
390 memmove(&result[0], &result[1], (
size_t)(degree - 1) *
sizeof(result[0]));
391 result[degree - 1] = 0;
392 for (
int j = 0; j < degree; j++)
397#undef qrcodegen_REED_SOLOMON_DEGREE_MAX
405 for (
int i = 7; i >= 0; i--) {
406 z = (uint8_t)((z << 1) ^ ((z >> 7) * 0x11D));
407 z ^= ((y >> i) & 1) * x;
420 int qrsize = version * 4 + 17;
421 memset(qrcode, 0, (
size_t)((qrsize * qrsize + 7) / 8 + 1) *
sizeof(qrcode[0]));
422 qrcode[0] = (uint8_t)qrsize;
425 fillRectangle(6, 0, 1, qrsize, qrcode);
426 fillRectangle(0, 6, qrsize, 1, qrcode);
429 fillRectangle(0, 0, 9, 9, qrcode);
430 fillRectangle(qrsize - 8, 0, 8, 9, qrcode);
431 fillRectangle(0, qrsize - 8, 9, 8, qrcode);
434 uint8_t alignPatPos[7];
436 for (
int i = 0; i < numAlign; i++) {
437 for (
int j = 0; j < numAlign; j++) {
439 if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0)))
440 fillRectangle(alignPatPos[i] - 2, alignPatPos[j] - 2, 5, 5, qrcode);
446 fillRectangle(qrsize - 11, 0, 3, 6, qrcode);
447 fillRectangle(0, qrsize - 11, 6, 3, qrcode);
455static void drawLightFunctionModules(uint8_t qrcode[],
int version) {
458 for (
int i = 7; i < qrsize - 7; i += 2) {
464 for (
int dy = -4; dy <= 4; dy++) {
465 for (
int dx = -4; dx <= 4; dx++) {
469 if (dist == 2 || dist == 4) {
478 uint8_t alignPatPos[7];
480 for (
int i = 0; i < numAlign; i++) {
481 for (
int j = 0; j < numAlign; j++) {
482 if ((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0))
484 for (
int dy = -1; dy <= 1; dy++) {
485 for (
int dx = -1; dx <= 1; dx++)
486 setModuleBounded(qrcode, alignPatPos[i] + dx, alignPatPos[j] + dy, dx == 0 && dy == 0);
495 for (
int i = 0; i < 12; i++)
496 rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
497 long bits = (long)version << 12 | rem;
498 assert(bits >> 18 == 0);
501 for (
int i = 0; i < 6; i++) {
502 for (
int j = 0; j < 3; j++) {
503 int k = qrsize - 11 + j;
518 assert(0 <= (
int)mask && (
int)mask <= 7);
519 static const int table[] = {1, 0, 3, 2};
520 int data = table[(int)ecl] << 3 | (
int)mask;
522 for (
int i = 0; i < 10; i++)
523 rem = (rem << 1) ^ ((rem >> 9) * 0x537);
524 int bits = (
data << 10 | rem) ^ 0x5412;
525 assert(bits >> 15 == 0);
528 for (
int i = 0; i <= 5; i++)
533 for (
int i = 9; i < 15; i++)
538 for (
int i = 0; i < 8; i++)
540 for (
int i = 8; i < 15; i++)
553 int numAlign = version / 7 + 2;
554 int step = (version == 32) ? 26 :
555 (version * 4 + numAlign * 2 + 1) / (numAlign * 2 - 2) * 2;
556 for (
int i = numAlign - 1, pos = version * 4 + 10; i >= 1; i--, pos -= step)
557 result[i] = (uint8_t)pos;
564static void fillRectangle(
int left,
int top,
int width,
int height, uint8_t qrcode[]) {
565 for (
int dy = 0; dy < height; dy++) {
566 for (
int dx = 0; dx < width; dx++)
577static void drawCodewords(
const uint8_t
data[],
int dataLen, uint8_t qrcode[]) {
581 for (
int right = qrsize - 1; right >= 1; right -= 2) {
584 for (
int vert = 0; vert < qrsize; vert++) {
585 for (
int j = 0; j < 2; j++) {
587 bool upward = ((right + 1) & 2) == 0;
588 int y = upward ? qrsize - 1 - vert : vert;
590 bool dark = getBit(
data[i >> 3], 7 - (i & 7));
599 assert(i == dataLen * 8);
608static void applyMask(
const uint8_t functionModules[], uint8_t qrcode[],
enum qrcodegen_Mask mask) {
609 assert(0 <= (
int)mask && (
int)mask <= 7);
611 for (
int y = 0; y < qrsize; y++) {
612 for (
int x = 0; x < qrsize; x++) {
617 case 0: invert = (x + y) % 2 == 0;
break;
618 case 1: invert = y % 2 == 0;
break;
619 case 2: invert = x % 3 == 0;
break;
620 case 3: invert = (x + y) % 3 == 0;
break;
621 case 4: invert = (x / 3 + y / 2) % 2 == 0;
break;
622 case 5: invert = x * y % 2 + x * y % 3 == 0;
break;
623 case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0;
break;
624 case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0;
break;
625 default: assert(
false);
return;
636static long getPenaltyScore(
const uint8_t qrcode[]) {
641 for (
int y = 0; y < qrsize; y++) {
642 bool runColor =
false;
644 int runHistory[7] = {0};
645 for (
int x = 0; x < qrsize; x++) {
649 result += PENALTY_N1;
653 finderPenaltyAddHistory(runX, runHistory, qrsize);
655 result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3;
660 result += finderPenaltyTerminateAndCount(runColor, runX, runHistory, qrsize) * PENALTY_N3;
663 for (
int x = 0; x < qrsize; x++) {
664 bool runColor =
false;
666 int runHistory[7] = {0};
667 for (
int y = 0; y < qrsize; y++) {
671 result += PENALTY_N1;
675 finderPenaltyAddHistory(runY, runHistory, qrsize);
677 result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3;
682 result += finderPenaltyTerminateAndCount(runColor, runY, runHistory, qrsize) * PENALTY_N3;
686 for (
int y = 0; y < qrsize - 1; y++) {
687 for (
int x = 0; x < qrsize - 1; x++) {
692 result += PENALTY_N2;
698 for (
int y = 0; y < qrsize; y++) {
699 for (
int x = 0; x < qrsize; x++) {
704 int total = qrsize * qrsize;
706 int k = (int)((labs(dark * 20L - total * 10L) + total - 1) / total) - 1;
707 assert(0 <= k && k <= 9);
708 result += k * PENALTY_N4;
709 assert(0 <= result && result <= 2568888L);
716static int finderPenaltyCountPatterns(
const int runHistory[7],
int qrsize) {
717 int n = runHistory[1];
718 assert(n <= qrsize * 3); (void)qrsize;
719 bool core = n > 0 && runHistory[2] == n && runHistory[3] == n * 3 && runHistory[4] == n && runHistory[5] == n;
722 return (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0)
723 + (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0);
728static int finderPenaltyTerminateAndCount(
bool currentRunColor,
int currentRunLength,
int runHistory[7],
int qrsize) {
729 if (currentRunColor) {
730 finderPenaltyAddHistory(currentRunLength, runHistory, qrsize);
731 currentRunLength = 0;
733 currentRunLength += qrsize;
734 finderPenaltyAddHistory(currentRunLength, runHistory, qrsize);
735 return finderPenaltyCountPatterns(runHistory, qrsize);
740static void finderPenaltyAddHistory(
int currentRunLength,
int runHistory[7],
int qrsize) {
741 if (runHistory[0] == 0)
742 currentRunLength += qrsize;
743 memmove(&runHistory[1], &runHistory[0], 6 *
sizeof(runHistory[0]));
744 runHistory[0] = currentRunLength;
753 assert(qrcode != NULL);
754 int result = qrcode[0];
763 assert(qrcode != NULL);
764 int qrsize = qrcode[0];
765 return (0 <= x && x < qrsize && 0 <= y && y < qrsize) &&
getModuleBounded(qrcode, x, y);
771 int qrsize = qrcode[0];
772 assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize);
773 int index = y * qrsize + x;
774 return getBit(qrcode[(index >> 3) + 1], index & 7);
780 int qrsize = qrcode[0];
781 assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize);
782 int index = y * qrsize + x;
783 int bitIndex = index & 7;
784 int byteIndex = (index >> 3) + 1;
786 qrcode[byteIndex] |= 1 << bitIndex;
788 qrcode[byteIndex] &= (1 << bitIndex) ^ 0xFF;
794 int qrsize = qrcode[0];
795 if (0 <= x && x < qrsize && 0 <= y && y < qrsize)
801static bool getBit(
int x,
int i) {
802 return ((x >> i) & 1) != 0;
811 assert(text != NULL);
812 for (; *text !=
'\0'; text++) {
813 if (*text < '0' || *text >
'9')
822 assert(text != NULL);
823 for (; *text !=
'\0'; text++) {
824 if (strchr(ALPHANUMERIC_CHARSET, *text) == NULL)
836 assert(0 <= temp && temp <= INT16_MAX);
837 return ((
size_t)temp + 7) / 8;
851 if (
numChars > (
unsigned int)INT16_MAX)
855 result = (result * 10 + 2) / 3;
857 result = (result * 11 + 1) / 2;
869 if (result > INT16_MAX)
877 assert(
data != NULL || len == 0);
884 memcpy(buf,
data, len *
sizeof(buf[0]));
892 assert(digits != NULL);
894 size_t len = strlen(digits);
897 assert(bitLen != -1);
900 memset(buf, 0, ((
size_t)bitLen + 7) / 8 *
sizeof(buf[0]));
903 unsigned int accumData = 0;
905 for (; *digits !=
'\0'; digits++) {
907 assert(
'0' <= c && c <=
'9');
908 accumData = accumData * 10 + (
unsigned int)(c -
'0');
910 if (accumCount == 3) {
926 assert(text != NULL);
928 size_t len = strlen(text);
931 assert(bitLen != -1);
934 memset(buf, 0, ((
size_t)bitLen + 7) / 8 *
sizeof(buf[0]));
937 unsigned int accumData = 0;
939 for (; *text !=
'\0'; text++) {
940 const char *temp = strchr(ALPHANUMERIC_CHARSET, *text);
941 assert(temp != NULL);
942 accumData = accumData * 45 + (
unsigned int)(temp - ALPHANUMERIC_CHARSET);
944 if (accumCount == 2) {
966 else if (assignVal < (1 << 7)) {
967 memset(buf, 0, 1 *
sizeof(buf[0]));
969 }
else if (assignVal < (1 << 14)) {
970 memset(buf, 0, 2 *
sizeof(buf[0]));
973 }
else if (assignVal < 1000000L) {
974 memset(buf, 0, 3 *
sizeof(buf[0]));
989 assert(segs != NULL || len == 0);
991 for (
size_t i = 0; i < len; i++) {
996 int ccbits = numCharCountBits(segs[i].
mode, version);
997 assert(0 <= ccbits && ccbits <= 16);
1001 if (result > INT16_MAX)
1004 assert(0 <= result && result <= INT16_MAX);
1013 int i = (version + 7) / 17;
1020 default: assert(
false);
return -1;
testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isDark)
size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars)
testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen)
bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[], enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl)
bool qrcodegen_isAlphanumeric(const char *text)
testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[])
struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[])
testable bool getModuleBounded(const uint8_t qrcode[], int x, int y)
testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version)
bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[], enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl)
bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl, uint8_t tempBuffer[], uint8_t qrcode[])
bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[])
bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y)
struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[])
testable void initializeFunctionModules(int version, uint8_t qrcode[])
testable int getAlignmentPatternPositions(int version, uint8_t result[7])
testable const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41]
testable void reedSolomonComputeRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[])
testable int getNumRawDataModules(int ver)
struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[])
testable const int8_t ECC_CODEWORDS_PER_BLOCK[4][41]
bool qrcodegen_isNumeric(const char *text)
struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[])
#define qrcodegen_REED_SOLOMON_DEGREE_MAX
testable void reedSolomonComputeDivisor(int degree, uint8_t result[])
testable void setModuleUnbounded(uint8_t qrcode[], int x, int y, bool isDark)
testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl)
testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars)
testable uint8_t reedSolomonMultiply(uint8_t x, uint8_t y)
int qrcodegen_getSize(const uint8_t qrcode[])
#define qrcodegen_VERSION_MAX
#define qrcodegen_BUFFER_LEN_FOR_VERSION(n)
#define qrcodegen_VERSION_MIN
@ qrcodegen_Mode_ALPHANUMERIC