Librerías C/C++ para generar códigos QR

Código QR
Con Clase

Generar códigos QR no es una tarea trivial. Existen varios formatos con muchas opciones diferentes.

El estándar está definido según las normas ISO/IEC 18004:2006.

Cada uno de los cuadrados que pueden ser blancos o negros se denomina módulo.

Existen varios tamaños, llamados versiones, desde 21x21 módulos a 177x177.

También existen varios modos, que definen el tipo de datos que contiene el código QR: numérico, alfanumérico, modo byte, Kanji y ECI. Dependiendo de la versión, se establece un número distinto de bits para cada modo.

Es importante tener en cuenta que el modo alfanumérico solo incluye los caracteres correspondientes a los dígitos numéricos, de 0 a 9, las letras mayúsculas, y algunos símbolos. Concretamente 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:. Como se puede apreciar, no incluye las minúsculas.

Por último, los códigos QR permiten añadir información adicional para detección y corrección de errores. También hay distintos niveles de corrección de errores, el nivel L puede recuperar hasta un 7% de los datos, el nivel M hasta un 15%, el nivel Q hasta un 25% y el nivel H hasta un 30%.

La información que puede contener un código QR depende de estos factores:

  • La versión (el tamaño), cuantos más módulos, mayor información puede contener.
  • El modo, ya que cada uno requiere un número diferente de bits para cada dato.
  • El nivel de corrección de errores, cuanto mayor, menos información se puede almacenar.

Ciertos módulos de cada versión del código QR no contienen información sobre los datos, sino que se destinan a que el software de reconocimiento pueda determinar la orientación y el tamaño de cada módulo. Estos son, por ejemplo, los cuadrados en las esquinas. Cada versión tiene un patrón parecido, fácilmente reconocible.

Existe otro parámetro que no afecta a la cantidad de información que pueda contener el código QR, sino a su aspecto. Se trata de la máscara. Con el fin de que los códigos QR sean más fáciles de leer por los dispositivos, los bits generados a partir de los datos y de los parámetros elegidos no se convierten directamente a módulos, sino que se procesan a través de una máscara. El objetivo es que no haya zonas demasiado grandes con módulos del mismo color, lo que podría provocar errores en el software de lectura, sobre todo en códigos incompletos o deformados por el ángulo, la forma del soporte o los reflejos, etc.

Existen ocho máscaras diferentes, y generalmente se determina cual de ellas usar mediante ciertas reglas. A los datos resultantes se le aplican las ocho máscaras sucesivamente, se evalúan según esas reglas, y se elige la que mejor puntuación obtiene.

Un vistazo a las especificaciones nos puede dar una idea de la complejidad de implementar una librería para generar códigos QR. El objetivo de este artículo no es reinventar la rueda, afortunadamente ya hay programadores que han creado librerías para que podamos usarlas en nuestros programas.

Librerías

Una búsqueda en Internet nos proporciona algunas opciones en cuanto a librerías. Nos centraremos en dos de ellas.

QRCode

Aunque está orientada al entorno Arduino, esta librería C se puede usar también en aplicaciones de ordenador, ya que es compatible con cualquier compilador de C o C++.

Se trata de una librería limitada, no dispone de todas las versiones ni de todos los modos posibles, pero es ligera y muy útil en entornos con pocos recursos, como son los microcontroladores.

Se puede descargar desde QRCode. Solo necesitamos los ficheros en la carpeta "src":

  • qrcode.c: implementación de la librería.
  • qrcode.h: declaraciones de tipos y funciones de la librería.

Incluiremos el fichero qrcode.c en nuestro proyecto y el fichero qrcode.h en cualquier módulo que necesite acceder a la librería. Por ejemplo:

#include <iostream>
#include "qrcode.h"

using namespace std;

int main() {
    // Estructura para manejar código QR
    QRCode qrcode;
    uint8_t *qrcodeBytes;
    const int version=2;
    char *dot="\333\333";
    char *esp="  ";

    // Obtener un trozo de memoria para almacenar el código QR
    qrcodeBytes = new uint8_t[qrcode_getBufferSize(version)];

    // Generar un código QR a partir de una cadena:
    qrcode_initText(&qrcode, qrcodeBytes, version, ECC_LOW, "https://conclase.net");

    // Mostrar código QR en modo texto:
    for (int y = 0; y < qrcode.size; y++) {
        for (int x = 0; x < qrcode.size; x++) {
            if(qrcode_getModule(&qrcode, x, y)) {
                cout << dot;
            } else {
                cout << esp;
            }
        }
        cout << endl;
    }
    delete[] qrcodeBytes;

    return 0;
}

La librería es muy simple, tan solo define algunas constantes, la estructura QRCode y cuatro funciones.

Constantes

Para definir el modo:

#define MODE_NUMERIC        0
#define MODE_ALPHANUMERIC   1
#define MODE_BYTE           2

Para definir el nivel de corrección de errores:

#define ECC_LOW            0
#define ECC_MEDIUM         1
#define ECC_QUARTILE       2
#define ECC_HIGH           3

Bloqueo de versión:

Definiendo la macro LOCK_VERSION con un valor distinto de cero podemos impedir que se generen códigos QR de otras versiones. Esto está pensado para ahorrar memoria al impedir la generación de tablas codeword. Por defecto está definida con valor 0.

#define LOCK_VERSION       0

Tipos

Solo hay declarado un tipo, el QRCode:

typedef struct QRCode {
    uint8_t version;
    uint8_t size;
    uint8_t ecc;
    uint8_t mode;
    uint8_t mask;
    uint8_t *modules;
} QRCode;

Una variable de este tipo es necesaria para manejar un código QR, y contiene la información sobre los parámetros que definen un código: versión, tamaño en módulos, nivel de corrección de errores, modo, máscara y un puntero a los datos que definen los módulos.

Funciones

La librería contiene cuatro funciones públicas:

qrcode_getBufferSize calcula el tamaño de la memoria necesaria para crear un código QR de la versión pasada como parámetro.

uint16_t qrcode_getBufferSize(uint8_t version);

qrcode_initText crea un código QR a partir de una cadena de texto. Esta función requiere cinco parámetros:

  1. qrcode: puntero a una estructura QRCode.
  2. modules: puntero a la memoria previamente obtenida, ya sea de forma dinámica o estática (un array).
  3. version: versión del código a generar, que define el tamaño del código.
  4. ecc: nivel de corrección de datos.
  5. data: puntero a cadena de texto a codificar.
int8_t qrcode_initText(QRCode *qrcode, uint8_t *modules, uint8_t version, uint8_t ecc, const char *data);

qrcode_initBytes crea un código QR a partir de datos binarios. Este formato permite valores no ASCII. Esta función requiere seis parámetros:

  1. qrcode: puntero a una estructura QRCode.
  2. modules: puntero a la memoria previamente obtenida, ya sea de forma dinámica o estática (un array).
  3. version: versión del código a generar, que define el tamaño del código.
  4. ecc: nivel de corrección de datos.
  5. data: puntero a buffer con los datos a codificar.
  6. length: tamaño de los datos contenidos en el buffer.
int8_t qrcode_initBytes(QRCode *qrcode, uint8_t *modules, uint8_t version, uint8_t ecc, uint8_t *data, uint16_t length);

qrcode_getModule obtiene el valor de un módulo del código generado. Esta función requiere tres parámetros:

  1. qrcode: puntero a una estructura QRCode.
  2. x: coordenada x del módulo.
  3. y: coordenada y del módulo.
bool qrcode_getModule(QRCode *qrcode, uint8_t x, uint8_t y);

Ejemplo con QRCode

Nombre Fichero Fecha Tamaño Contador Descarga
Ejemplo QRCode qrcode.zip 2023-08-12 12021 bytes 301

QR-Code generator

Esta librería es mucho más completa que la anterior, y además ofrece versiones para varios lenguajes diferentes: C, C++, Java, Python, Rust y TypeScript. Nos centraremos aquí en las versiones para C y C++.

Aunque es más compleja, y dispone de muchas más funciones que QRCode, también permite un uso simplificado, dejando que la propia librería establezca los valores de varios parámetros de forma automática.

Librería C de QR-Code generator

Se puede descargar desde QR Code generator. Solo necesitamos un par de ficheros en la carpeta correspondiente a la versión de C:

  • qrcodegen.c implementación de la librería.
  • qrcodegen.h: declaraciones de tipos y funciones de la librería.

Con en el caso anterior, incluiremos el fichero qrcodegen.c en nuestro proyecto y el fichero qrcodegen.h en cualquier módulo que necesite acceder a la librería. Por ejemplo:

#include <iostream>
#include "qrcodegen.h"

using namespace std;

int main() {
    char *dot="\333\333";
    char *esp="  ";

    // Text data
    uint8_t qr0[qrcodegen_BUFFER_LEN_MAX];
    uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
    bool ok = qrcodegen_encodeText("https://conclase.net",
        tempBuffer, qr0, qrcodegen_Ecc_MEDIUM,
        qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX,
        qrcodegen_Mask_AUTO, true);

    if (!ok) return 1;

    int size = qrcodegen_getSize(qr0);
    for (int y = 0; y < size; y++) {
        for (int x = 0; x < size; x++) {
            if(qrcodegen_getModule(qr0, x, y)) {
                cout << dot;
            } else {
                cout << esp;
            }
        }
        cout << endl;
    }

    return 0;
}

Los ficheros fuente están muy bien documentados, con abundantes comentarios sobre cada constante, estructura y función.

Constantes

En esta librería muchas de las constantes están definidas como tipos enumerados.

Los niveles de corrección de errores:

enum qrcodegen_Ecc {
	qrcodegen_Ecc_LOW = 0 ,  // The QR Code can tolerate about  7% erroneous codewords
	qrcodegen_Ecc_MEDIUM  ,  // The QR Code can tolerate about 15% erroneous codewords
	qrcodegen_Ecc_QUARTILE,  // The QR Code can tolerate about 25% erroneous codewords
	qrcodegen_Ecc_HIGH    ,  // The QR Code can tolerate about 30% erroneous codewords
};

También se define un tipo enumerado para las ocho máscaras disponibles:

enum qrcodegen_Mask {
	// A special value to tell the QR Code encoder to
	// automatically select an appropriate mask pattern
	qrcodegen_Mask_AUTO = -1,
	// The eight actual mask patterns
	qrcodegen_Mask_0 = 0,
	qrcodegen_Mask_1,
	qrcodegen_Mask_2,
	qrcodegen_Mask_3,
	qrcodegen_Mask_4,
	qrcodegen_Mask_5,
	qrcodegen_Mask_6,
	qrcodegen_Mask_7,
};

También hay un tipo enumerado para los diferentes modos de códigos QR:

enum qrcodegen_Mode {
	qrcodegen_Mode_NUMERIC      = 0x1,
	qrcodegen_Mode_ALPHANUMERIC = 0x2,
	qrcodegen_Mode_BYTE         = 0x4,
	qrcodegen_Mode_KANJI        = 0x8,
	qrcodegen_Mode_ECI          = 0x7,
};

También se definen algunas macros. Por ejemplo, las versiones mínima y máxima existentes:

#define qrcodegen_VERSION_MIN   1  // The minimum version number supported in the QR Code Model 2 standard
#define qrcodegen_VERSION_MAX  40  // The maximum version number supported in the QR Code Model 2 standard

Se definen dos macros para el tamaño de los buffers para contener los datos necesarios. La primera en función de la versión, y la segunda para la versión máxima:

#define qrcodegen_BUFFER_LEN_FOR_VERSION(n)  ((((n) * 4 + 17) * ((n) * 4 + 17) + 7) / 8 + 1)
#define qrcodegen_BUFFER_LEN_MAX  qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX)

Tipos

Un código QR no tiene por qué contener todos sus datos usando el mismo tipo. Puede haber varios segmentos separados con tipos de codificación diferentes. La estructura qrcodegen_Segment contiene la información a contener en un segmento en un código QR:

struct qrcodegen_Segment {
	// The mode indicator of this segment.
	enum qrcodegen_Mode mode;
	
	// The length of this segment's unencoded data. Measured in characters for
	// numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode.
	// Always zero or positive. Not the same as the data's bit length.
	int numChars;
	
	// The data bits of this segment, packed in bitwise big endian.
	// Can be null if the bit length is zero.
	uint8_t *data;
	
	// The number of valid data bits used in the buffer. Requires
	// 0 <= bitLength <= 32767, and bitLength <= (capacity of data array) * 8.
	// The character count (numChars) must agree with the mode and the bit buffer length.
	int bitLength;
};

Funciones

Disponemos de algunas funciones para generar códigos QR a partir de diferentes tipos de datos.

qrcodegen_encodeText genera un QR a partir de texto. Esta función requiere ocho parámetros:

  1. text: el texto a convertir, codificado en UTF-8.
  2. tempBuffer: puntero a un buffer temporal.
  3. qrcode: puntero a un buffer con los datos del código QR generado, si la función tiene éxito.
  4. ecl: nivel de correción de errores requerido.
  5. minVersion: versión mínima a utilizar, 1 o mayor.
  6. maxVersion: versión máxima a utilizar, menor o igual a 40.
  7. mask: máscara a utilizar entre qrcodegen_Mask_0 y qrcodegen_Mask_7. O qrcodegen_Mask_AUTO para que se seleccione una de forma automática.
  8. boostEcl: si es true, el valor ECC utilizado puede ser mayor que el indicado en ecl.

Se usará la versión más pequeña dentro del rango indicado, aumentando el ECC indicado si es posible y si boostEcl es true.

Ambos buffers deben permitir lectura y escritura, y no pueden superponerse. No es necesario inicializarlos.

El tamaño de los buffers debería ser qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion).

Si la codificación es posible para los parámetros indicados, el valor de retorno es true.

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);

La función qrcodegen_encodeBinary se usa para generar el código QR a partir de datos binarios. También requiere ocho parámetros, aunque los seis últimos son similares:

  1. dataAndTemp: los datos binarios a convertir. Pero también se usa como buffer temporal.
  2. dataLen: dado que el buffer de entrada será más grande que el buffer temporal necesario, y que los datos de entrada pueden contener nulos, este parámetro indica el tamaño de los datos de entrada.
  3. qrcode: puntero a un buffer con los datos del código QR generado, si la función tiene éxito.
  4. ecl: nivel de correción de errores requerido.
  5. minVersion: versión mínima a utilizar, 1 o mayor.
  6. maxVersion: versión máxima a utilizar, menor o igual a 40.
  7. mask: máscara a utilizar entre qrcodegen_Mask_0 y qrcodegen_Mask_7. O qrcodegen_Mask_AUTO para que se seleccione una de forma automática.
  8. boostEcl: si es true, el valor ECC utilizado puede ser mayor que el indicado en ecl.

El funcionamiento es similar a la función anterior, y las notas sobre los parámetros son equivalentes.

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);

La función qrcodegen_encodeSegments se usa para generar códigos QR a partir de varios segmentos. Requiere cinco parámetros:

  1. segs: array de estructuras qrcodegen_Segment con los segmentos a incluir.

  2. len: tamaño de los buffers tempBuffer y qrcode, es recomendable usar el tamaño necesario para la versión más grande, qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX).
  3. ecl: nivel de corrección de errores a utilizar.
  4. tempBuffer: buffer temporal de trabajo.
  5. qrcode: buffer de salida del código QR.
bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len,
	enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]);

Si la función tiene éxito, el valor de retorno será true.

La función qrcodegen_encodeSegmentsAdvanced realiza la misma tarea, pero admite mayor control sobre los parámetros, ya que requiere nueve:

  1. segs: array de estructuras qrcodegen_Segment con los segmentos a incluir.

  2. len: tamaño de los buffers tempBuffer y qrcode, es recomendable usar el tamaño necesario para la versión más grande, qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX).
  3. ecl: nivel de corrección de errores a utilizar.
  4. minVersion: versión mínima a utilizar, 1 o mayor.
  5. maxVersion: versión máxima a utilizar, menor o igual a 40.
  6. mask: máscara a utilizar entre qrcodegen_Mask_0 y qrcodegen_Mask_7. O qrcodegen_Mask_AUTO para que se seleccione una de forma automática.
  7. boostEcl: si es true, el valor ECC utilizado puede ser mayor que el indicado en ecl.
  8. tempBuffer: buffer temporal de trabajo.
  9. qrcode: buffer de salida del código QR.
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[]);

Si la función tiene éxito, el valor de retorno será true.

Disponemos además de varias funciones auxiliares.

Un texto puede contener solo caracteres numéricos, en cuyo caso podremos usar un modo diferente, que es más adecuado. Para averiguar si una cadena contiene solo números podemos usar la función qrcodegen_isNumeric:

bool qrcodegen_isNumeric(const char *text);

O la función qrcodegen_isAlphanumeric que verifica si se puede aplicar el modo alfanumérico:

bool qrcodegen_isAlphanumeric(const char *text);

Cuando trabajemos con segmentos, la función qrcodegen_calcSegmentBufferSize nos permite calcular el tamaño del buffer asociado a cada segmento. Se necesitan dos parámetros:

  1. mode: el modo del segmento, uno de los valores del tipo enumerado qrcodegen_Mode.
  2. numChars: el número de bytes en los datos a incluir en el segmento.
size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars);

Para obtener los valores de una estructura qrcodegen_Segment disponemos de diferentes funciones. Tendremos que elegir la adecuada en función del modo.

Para el BYTE usaremos la función qrcodegen_makeBytes, con tres parámetros:

  1. data: puntero a los datos a incluir en el segmento.
  2. len: tamaño de los datos.
  3. buf: puntero al buffer que hemos de haber obtenido previamente, cuyo tamaño calculamos mediante la función qrcodegen_calcSegmentBufferSize.
struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]);

El resultado es una estructura qrcodegen_Segment debidamente inicializara.

Para el modo NUMERIC usaremos la función qrcodegen_makeNumeric, también con tres parámetros:

  1. digits: puntero a los datos a incluir en el segmento.
  2. len: tamaño de los datos.
  3. buf: puntero al buffer que hemos de haber obtenido previamente, cuyo tamaño calculamos mediante la función qrcodegen_calcSegmentBufferSize.

Esta función fallará si los datos apuntados por digits contienen algún valor que no sea un dígito.

struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]);

Para el modo ALPHANUMERIC usaremos la función qrcodegen_makeAlphanumeric, también con tres parámetros:

  1. text: puntero a los datos a incluir en el segmento.
  2. len: tamaño de los datos.
  3. buf: puntero al buffer que hemos de haber obtenido previamente, cuyo tamaño calculamos mediante la función qrcodegen_calcSegmentBufferSize.

Esta función fallará si los datos apuntados por text contienen algún valor que no sea un dígito, de 0 a 9, una letra mayúscula, un espacio o alguno de los signos de puntuación permitidos, es decir, si alguno de los caracteres no está entre "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./" o un espacio.

struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]);

Para el modo ECI usaremos la función qrcodegen_makeEci, con dos parámetros:

  1. assignVal: valor ECI.
  2. buf: puntero al buffer que hemos de haber obtenido previamente, cuyo tamaño calculamos mediante la función qrcodegen_calcSegmentBufferSize.

El ECI permite añadir información sobre la codificación de caracteres utilizada. Puedes ver una lista de los valores válidos en código ECI.

struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]);

Una vez hemos generado un código QR con éxito, podemos acceder a él para representarlo o exportarlo según nuestras necesidades.

Para obtener el tamaño disponemos de la función qrcodegen_getSize. El tamaño se refiere al número de módulos de anchura y altura. Tan solo hay que usar como parámetro la dirección de buffer que contiene el código QR.

int qrcodegen_getSize(const uint8_t qrcode[]);

Finalmente, para obtener el valor de un módulo usaremos la función qrcodegen_getModule, indicando tres parámetros:

  1. qrcode:dirección de buffer que contiene el código QR.
  2. x: coordenada x del módulo.
  3. y: coordenada y del módulo.
bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y);

Ejemplo de código QR de texto

La librería es capaz de elegir el modo adecuado para los datos de texto. En este ejemplo se usará el modo byte, dato que el texto no se ajusta a las limitaciones del modo aldanumérico.

Nombre Fichero Fecha Tamaño Contador Descarga
Ejemplo QRCodeGen de texto qrcodegen_alfa.zip 2023-08-12 17608 bytes 286

Ejemplo de código QR de segmentos

Crear un código QR a partir de segmentos puede optimizar la versión elegida:

Nombre Fichero Fecha Tamaño Contador Descarga
Ejemplo QRCodeGen por segmentos qrcodegen_seg.zip 2023-08-12 17793 bytes 275

Librería C++ de QR-Code generator

Se trata de una encapsulación de la librería en varias clases. Se puede descargar desde QR Code generator. Solo necesitamos un par de ficheros en la carpeta correspondiente a la versión de C++:

  • qrcodegen.cpp implementación de la librería.
  • qrcodegen.hpp: declaraciones de tipos y funciones de la librería.
#include <iostream>
#include "qrcodegen.hpp"

using namespace std;

using qrcodegen::QrCode;

int main() {
	int border = 2;
        char *dot="\333\333";
        char *esp="  ";

	const char *text = "https://conclase.net";
	const QrCode::Ecc errCorLvl = QrCode::Ecc::LOW;

	const QrCode qr = QrCode::encodeText(text, errCorLvl);

	for (int y = -border; y < qr.getSize() + border; y++) {
		for (int x = -border; x < qr.getSize() + border; x++) {
			std::cout << (qr.getModule(x, y) ? dot : esp);
		}
		std::cout << std::endl;
	}
	std::cout << std::endl;
        return 0;
}

Espacio con nombre

Todas las clases de la librería están bajo el mismos espacio con el nombre qrcodegen.

Clases

La librería se compone de cuatro clases. Veremos aquí solo los miembros públicos.

Clase QrSegment

Ya vimos que se pueden crear códigos QR a partir de varios segmentos, cada uno de ellos de diferente modo. Esto permite optimizar la cantidad de datos para un mismo modelo de código QR.

Esta clase se usa para manipular esos segmentos.

Los objetos creados de esta clase no pueden ser modificados.

Constructores

Disponemos de dos constructores. Ambos con tres parámetros:

  1. md: modo.
  2. numCh: número de caracteres en el buffer.
  3. dt: buffer con los datos a incluir en el segmento.

El número de caracteres debe coincidir con el modo y tamaño del buffer. Los datos del buffer son copiados y almacenados, de modo que se puede usar el mismo buffer para crear sucesivos segmentos.

QrSegment(const Mode &md, int numCh, const std::vector<bool> &dt);

El otro constructor es similar, y usa los mismos parámetros. La única diferencia es que ahora los datos del buffer son movidos en lugar de copiados. Esto significa que no podemos usar el mismo buffer para diferentes segmentos.

QrSegment(const Mode &md, int numCh, std::vector<bool> &&dt);
Clase interna Mode

La clase QrSegment contiene una clase interna Mode en la que se definen las constantes que identifican los diferentes modos: NUMERIC, ALPHANUMERIC, BYTE, KANJI y ECI.

Métodos públicos

El método makeBytes devuelve un segmento que contiene los datos data codificados en el modo byte.

static QrSegment makeBytes(const std::vector<std::uint8_t> &data);

El método makeNumeric devuelve un segmento que contiene los datos digits codificados en el modo numérico.

static QrSegment makeNumeric(const char *digits);

El método makeAlphanumeric devuelve un segmento que contiene los datos text codificados en el modo alfanumérico. Los caracteres permitidos son "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./" y el espacio

static QrSegment makeAlphanumeric(const char *text);

El método makeSegmentsc devuelve una lista de segmentos que contiene los datos text. Se pueden usar diferentes tipos de codificación para cada segmento, para optimizar la longitud de los datos generados.

static std::vector makeSegments(const char *text);

El método makeEci permite crear un segmento ECI a partir del valor indicado en assignEci.. El ECI permite añadir información sobre la codificación de caracteres utilizada. Puedes ver una lista de los valores válidos en código ECI.

static QrSegment makeEci(long assignVal);

Para averiguar si una cadena contiene solo números podemos usar el método isNumeric:

static bool isNumeric(const char *text);

O el método isAlphanumeric que verifica si se puede utilizar el modo alfanumérico:

static bool isAlphanumeric(const char *text);

La función getMode obtiene el modo en que está codificado el segmento.

const Mode &getMode() const;

La función getNumChars devuelve el tamaño en caracteres de los datos del segmento sin codificar.

int getNumChars() const;

La función getData devuelve el vector de bits que contiene los datos del segmento.

const std::vector &getData() const;

La función getTotalBits calcula el número de bits necesarios para codificar el segmento según la versión dada. Si tiene éxito devuelve un valor positivo, en caso de error devuelve -1, ya sea poerque el segmento tenga demasiados caracteres o porque el número total de bits es mayor que INT_MAX.

static int getTotalBits(const std::vector<QrSegment> &segs, int version)
Clase QrCode

Esta clase se usa para crear objetos que representan un código QR.

Proporciona funciones estáticas para crear un Código QR a partir de texto o datos binarios.

La clase se ajusta a la especificación QR Code Model 2, soportando todas las versiones de 1 a 40, los 4 niveles de corrección de errores, y 4 modos de codificación de caracteres.

Hay tres maneras de crear un objeto QR Code:

  • Alto nivel: A partir de los datos a codificar llamar a QrCode::encodeText() o QrCode::encodeBinary().
  • Nivel medio: Crear separadamente una lista de segmentos y llamar a QrCode::encodeSegments().
  • Nivel bajo: Personalizar el array de bytes de los datos codificados (incluidas las cabeceras de segmento y el relleno final, menos los correspondientes al código de corrección de errores), proporcionar el número de versión adecuado y llamar al constructor QrCode().
Constantes

Esta clase define algunas constantes que se usan para generar códigos QR.

La versión mínima soportada pro el modelo 2 del código QR.

static constexpr int MIN_VERSION =  1;

La versión máxima soportada pro el modelo 2 del código QR.

static constexpr int MAX_VERSION = 40;
Constructor

El constructor crea un código QR, a partir de cuatro parámetros:

  1. ver: el número de versión.
  2. ecl: el nivel de corrección de errores.
  3. dataCodewords: bytes de código de datos.
  4. msk: el número de la máscara.

Se trata de una forma de bajo nivel que en general no se debería utilizar directamente.

QrCode(int ver, Ecc ecl, const std::vector<std::uint8_t> &dataCodewords, int msk);

El método encodeText devuelve un código QR a partir del texto Unicode text, y el nivel de corrección de datos ecl indicados.

Usando un nivel de corrección de errores mínimo, el éxito está asegurado para cadenas de 2953 caracteres UTF-8 o menos.

Se elegirá automáticamente la versión más pequeña posible, y se usará un nivel de corrección de errores mayor que ecl si se puede hacer sin elegir una versión mayor.

static QrCode encodeText(const char *text, Ecc ecl);

El método encodeBinary devuelve un código QR a partir de los datos binarios data, y el nivel de corrección de datos ecl indicados.

Siempre se usará el modo binario, aunque los datos contengan texto. El número máximo de byte es 2953.

Se elegirá automáticamente la versión más pequeña posible, y se usará un nivel de corrección de errores mayor que ecl si se puede hacer sin elegir una versión mayor.

static QrCode encodeBinary(const std::vector &data, Ecc ecl);

El método encodeSegments devuelve un código QR a partir de los segmentos y los parámetros indicados.

  1. segs: vector con los segmentos a incluir en el código.
  2. ecl: nivel de corrección de errores deseado.
  3. minVersion: versión mínima del código generado. Parámetro opcional, si no se especifica es 1.
  4. maxVersion: versión máxima del código generado. Parámetro opcional, si no se especifica es 40.
  5. mask: valor de la máscara, entre 0 y 7, o -1 para que se elija una de forma automática, lo que es más lento. Si no se especifica es -1.
  6. boostEcl: si es true, valor por defecto, se usará un nivel de corrección de errores mayor si es posible sin usar una versión mayor.
static QrCode encodeSegments(const std::vector<QrSegment> &segs, Ecc ecl,
		int minVersion=1, int maxVersion=40, int mask=-1, bool boostEcl=true);

El método getVersion devuelve el número de la versión de un objeto QrCode.

int getVersion() const;

El método getSize devuelve el tamaño de un objeto QrCode, es decir, el número de módulos de cada eje del código.

int getSize() const;

El método getErrorCorrectionLevel devuelve el nivel de corrección de errores utilizado en un objeto QrCode.

Ecc getErrorCorrectionLevel() const;

El método getMask devuelve el valor de la máscara utilizado en un objeto QrCode.

int getMask() const;

El método getModule devuelve el valor del módulo indicado por las coordenadas x e y de unobjeto QrCode.

bool getModule(int x, int y) const;
Clase data_too_long

La clase data_too_long está destinada a lanzar una excepción cuando los datos indicados para generar un código QR no se ajustan a ninguna versión.

En estos casos se pueden probar algunas acciones, como disminuir el nivel de error Ecc, usar un valor mayor para maxVersión si no era ya MAX_VERSION, dividir mejor los datos de texto, cambiar los datos de entrada por versiones más cortas, modificar el texto para que se ajuste el modo alfanumérico, es decir, eliminar minúsculas, o enviar un mensaje de error al usuario.

Se trata de una clase que hereda a partir de std::length_error, y solo tiene un miembro, que es el constructor.

class data_too_long : public std::length_error {
	public: explicit data_too_long(const std::string &msg);
};
Clase BitBuffer

La clase BitBuffer es usada por QrSegment. Se trata de un buffer de bits ampliable, basado en el vector de STL.

Constructor

Dispone de un constructor sin parámetros.

BitBuffer();
Métodos públicos

El método appendBits añade el número dado de bits al buffer.

  1. val: valores de los bits empaquetados en un entero sin signo de 32 bits.
  2. len: número de bits a añadir.

El valor de len> debe estar entre 0 y 31 y el de val entre 0 y 2len.

void appendBits(std::uint32_t val, int len);

Ejemplo de código QR de texto

La librería es capaz de elegir el modo adecuado para los datos de texto. En este ejemplo se usará el modo byte, dato que el texto no se ajusta a las limitaciones del modo aldanumérico.

Nombre Fichero Fecha Tamaño Contador Descarga
Ejemplo QRCodeGen de texto con clases qrcodegencpp_alfa.zip 2023-08-12 16079 bytes 281

Ejemplo de código QR de segmentos

Crear un código QR a partir de segmentos puede optimizar la versión elegida:

Nombre Fichero Fecha Tamaño Contador Descarga
Ejemplo QRCodeGen por segmentos con clases qrcodegencpp_seg.zip 2023-08-12 16142 bytes 294

Segmentos

Generalmente, los datos almacenados en un código QR no estarán codificados usando un único modo. Suele ser más óptimo separar los datos según el tipo, ya que cada modo requiere diferente número de bits para codificar cada dato individual. Por ejemplo, si los datos contienen texto que solo contienen caracteres válidos para el modo alfanumérico y secuencias de dígitos, pueden separarse en distintos fragmentos. A cada fragmento le corresponde un segmento. Como resultado, es posible que los datos se puedan presentar en un código QR de una versión menor.

La forma de nivel medio para crear un segmento es tomar los datos y llamar a una de los métodos QrSegment::makeNumeric(), QrSegment::makeAlphaNumeric() o QrSegment::makeBytes().

La forma de bajo nivel requiere crear un buffer de bits personalizado y llamar al constructorQrSegment(). Es mucho más complicado, y no es muy recomendable.

Referencias

Thonky.com's QR Code Tutorial.

Librería C Ricmoo.

Librerías Nayuki.