Continued implementing C library by adding a main QR Code encoding function and auxiliary functions.

pull/11/head
Project Nayuki 8 years ago
parent 316bb588f2
commit d332c4a91c

@ -23,6 +23,7 @@
*/
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include "qrcodegen.h"
@ -30,6 +31,9 @@
/*---- Forward declarations for private functions ----*/
static void appendBitsToBuffer(uint16_t val, int numBits, uint8_t buffer[], int *bitLen);
static int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
static bool getModule(const uint8_t qrcode[], int size, int x, int y);
static void setModule(uint8_t qrcode[], int size, int x, int y, bool isBlack);
static void setModuleBounded(uint8_t qrcode[], int size, int x, int y, bool isBlack);
@ -111,6 +115,73 @@ bool qrcodegen_isNumeric(const char *text) {
}
// Public function - see documentation comment in header file.
int qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[],
enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask) {
assert(1 <= minVersion && minVersion <= maxVersion && maxVersion <= 40);
assert(0 <= (int)ecl && (int)ecl <= 3 && -1 <= (int)mask && (int)mask <= 7);
int version;
int dataUsedBits = -1;
int dataCapacityBits = -1;
for (version = minVersion; ; version++) {
if ((version <= 9 && dataLen < (1U << 8)) || dataLen < (1U << 16)) {
dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
dataUsedBits = 4 + (version <= 9 ? 8 : 16);
if (dataLen > (unsigned int)INT_MAX / 8 || (unsigned int)(INT_MAX - dataUsedBits) < dataLen * 8)
continue;
dataUsedBits += dataLen * 8;
if (dataUsedBits <= dataCapacityBits)
break; // This version number is found to be suitable
}
if (version >= maxVersion) // All versions in the range could not fit the given data
return 0;
}
assert(dataUsedBits >= 0 && dataCapacityBits >= 0);
memset(qrcode, 0, qrcodegen_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0]));
int bitLen = 0;
appendBitsToBuffer(4, 4, qrcode, &bitLen);
appendBitsToBuffer((uint16_t)dataLen, (version <= 9 ? 8 : 16), qrcode, &bitLen);
for (size_t i = 0; i < dataLen; i++)
appendBitsToBuffer(dataAndTemp[i], 8, qrcode, &bitLen);
int terminatorBits = dataCapacityBits - bitLen;
if (terminatorBits > 4)
terminatorBits = 4;
appendBitsToBuffer(0, terminatorBits, qrcode, &bitLen);
appendBitsToBuffer(0, (8 - bitLen % 8) % 8, qrcode, &bitLen);
for (uint8_t padByte = 0xEC; bitLen < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
appendBitsToBuffer(padByte, 8, qrcode, &bitLen);
assert(bitLen % 8 == 0);
appendErrorCorrection(qrcode, version, ecl, dataAndTemp);
initializeFunctionalModules(version, qrcode);
drawCodewords(dataAndTemp, getNumRawDataModules(version) / 8, qrcode, version);
drawWhiteFunctionModules(qrcode, version);
initializeFunctionalModules(version, dataAndTemp);
mask = qrcodegen_Mask_0;
applyMask(dataAndTemp, qrcode, qrcodegen_getSize(version), (int)mask);
drawFormatBits(ecl, (int)mask, qrcode, qrcodegen_getSize(version));
return version;
}
// Appends the given sequence of bits to the given byte-based bit buffer, increasing the bit length.
static void appendBitsToBuffer(uint16_t val, int numBits, uint8_t buffer[], int *bitLen) {
assert(0 <= numBits && numBits <= 16 && (long)val >> numBits == 0);
for (int i = numBits - 1; i >= 0; i--, (*bitLen)++)
buffer[*bitLen >> 3] |= ((val >> i) & 1) << (7 - (*bitLen & 7));
}
// Returns the number of 8-bit codewords that can be used for storing data (not ECC),
// for the given version number and error correction level. The result is in the range [9, 2956].
static int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl) {
assert(0 <= (int)ecl && (int)ecl < 4 && 1 <= version && version <= 40);
return getNumRawDataModules(version) / 8 - NUM_ERROR_CORRECTION_CODEWORDS[(int)ecl][version];
}
// Public function - see documentation comment in header file.
int qrcodegen_getSize(int version) {
assert(1 <= version && version <= 40);

@ -76,6 +76,17 @@ bool qrcodegen_isAlphanumeric(const char *text);
bool qrcodegen_isNumeric(const char *text);
/*
* Encodes the given binary data to a QR Code symbol, return the actual version number used.
* If the data is too long to fit in any version in the given range at the given ECC level,
* then 0 is returned. dataAndTemp[0 : dataLen] represents the input data, and the function
* may overwrite the array's contents as a temporary work area. Both dataAndTemp and qrcode
* must have length at least qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion).
*/
int qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[],
enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask);
/*
* Returns the side length of any QR Code of the given version.
* The version must be in the range [1, 40]. The result is in the range [21, 177].

Loading…
Cancel
Save