Showing preview only (667K chars total). Download the full file or copy to clipboard to get everything.
Repository: nayuki/QR-Code-generator
Branch: master
Commit: 2c9044de6b04
Files: 52
Total size: 641.8 KB
Directory structure:
gitextract_u8mpr9dd/
├── Readme.markdown
├── c/
│ ├── Makefile
│ ├── Readme.markdown
│ ├── qrcodegen-demo.c
│ ├── qrcodegen-test.c
│ ├── qrcodegen.c
│ └── qrcodegen.h
├── cpp/
│ ├── Makefile
│ ├── QrCodeGeneratorDemo.cpp
│ ├── Readme.markdown
│ ├── qrcodegen.cpp
│ └── qrcodegen.hpp
├── java/
│ ├── QrCodeGeneratorDemo.java
│ ├── Readme.markdown
│ ├── pom.xml
│ └── src/
│ └── main/
│ └── java/
│ ├── io/
│ │ └── nayuki/
│ │ └── qrcodegen/
│ │ ├── BitBuffer.java
│ │ ├── DataTooLongException.java
│ │ ├── QrCode.java
│ │ ├── QrSegment.java
│ │ ├── QrSegmentAdvanced.java
│ │ └── package-info.java
│ └── module-info.java
├── java-fast/
│ ├── Readme.markdown
│ └── io/
│ └── nayuki/
│ └── fastqrcodegen/
│ ├── BitBuffer.java
│ ├── DataTooLongException.java
│ ├── Memoizer.java
│ ├── QrCode.java
│ ├── QrCodeGeneratorDemo.java
│ ├── QrSegment.java
│ ├── QrSegmentAdvanced.java
│ ├── QrTemplate.java
│ ├── ReedSolomonGenerator.java
│ └── package-info.java
├── python/
│ ├── Readme.markdown
│ ├── qrcodegen-demo.py
│ ├── qrcodegen.py
│ └── setup.py
├── rust/
│ ├── Cargo.toml
│ ├── Readme.markdown
│ ├── examples/
│ │ └── qrcodegen-demo.rs
│ └── src/
│ └── lib.rs
├── rust-no-heap/
│ ├── Cargo.toml
│ ├── Readme.markdown
│ ├── examples/
│ │ └── qrcodegen-demo.rs
│ └── src/
│ └── lib.rs
└── typescript-javascript/
├── Readme.markdown
├── build.sh
├── qrcodegen-input-demo.html
├── qrcodegen-input-demo.ts
├── qrcodegen-output-demo.html
├── qrcodegen-output-demo.ts
└── qrcodegen.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: Readme.markdown
================================================
QR Code generator library
=========================
Introduction
------------
This project aims to be the best, clearest QR Code generator library in multiple languages. The primary goals are flexible options and absolute correctness. Secondary goals are compact implementation size and good documentation comments.
Home page with live JavaScript demo, extensive descriptions, and competitor comparisons: [https://www.nayuki.io/page/qr-code-generator-library](https://www.nayuki.io/page/qr-code-generator-library)
Features
--------
Core features:
* Available in 6 programming languages, all with nearly equal functionality: Java, TypeScript/JavaScript, Python, Rust, C++, C
* Significantly shorter code but more documentation comments compared to competing libraries
* Supports encoding all 40 versions (sizes) and all 4 error correction levels, as per the QR Code Model 2 standard
* Output format: Raw modules/pixels of the QR symbol
* Detects finder-like penalty patterns more accurately than other implementations
* Encodes numeric and special-alphanumeric text in less space than general text
* Open-source code under the permissive MIT License
Manual parameters:
* User can specify minimum and maximum version numbers allowed, then library will automatically choose smallest version in the range that fits the data
* User can specify mask pattern manually, otherwise library will automatically evaluate all 8 masks and select the optimal one
* User can specify absolute error correction level, or allow the library to boost it if it doesn't increase the version number
* User can create a list of data segments manually and add ECI segments
Optional advanced features (Java only):
* Encodes Japanese Unicode text in kanji mode to save a lot of space compared to UTF-8 bytes
* Computes optimal segment mode switching for text with mixed numeric/alphanumeric/general/kanji parts
More information about QR Code technology and this library's design can be found on the project home page.
Examples
--------
The code below is in Java, but the other language ports are designed with essentially the same API naming and behavior.
```java
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.List;
import javax.imageio.ImageIO;
import io.nayuki.qrcodegen.*;
// Simple operation
QrCode qr0 = QrCode.encodeText("Hello, world!", QrCode.Ecc.MEDIUM);
BufferedImage img = toImage(qr0, 4, 10); // See QrCodeGeneratorDemo
ImageIO.write(img, "png", new File("qr-code.png"));
// Manual operation
List<QrSegment> segs = QrSegment.makeSegments("3141592653589793238462643383");
QrCode qr1 = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, 5, 5, 2, false);
for (int y = 0; y < qr1.size; y++) {
for (int x = 0; x < qr1.size; x++) {
(... paint qr1.getModule(x, y) ...)
}
}
```
License
-------
Copyright © 2025 Project Nayuki. (MIT License)
[https://www.nayuki.io/page/qr-code-generator-library](https://www.nayuki.io/page/qr-code-generator-library)
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.
================================================
FILE: c/Makefile
================================================
#
# Makefile for QR Code generator (C)
#
# Copyright (c) Project Nayuki. (MIT License)
# https://www.nayuki.io/page/qr-code-generator-library
#
# 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.
#
# ---- Configuration options ----
# External/implicit variables:
# - CC: The C compiler, such as gcc or clang.
# - CFLAGS: Any extra user-specified compiler flags (can be blank).
# Recommended compiler flags:
CFLAGS += -std=c99 -O
# Extra flags for diagnostics:
# CFLAGS += -g -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -fsanitize=undefined,address
# ---- Controlling make ----
# Clear default suffix rules
.SUFFIXES:
# Don't delete object files
.SECONDARY:
# Stuff concerning goals
.DEFAULT_GOAL = all
.PHONY: all clean
# ---- Targets to build ----
LIB = qrcodegen
LIBFILE = lib$(LIB).a
LIBOBJ = qrcodegen.o
MAINS = qrcodegen-demo qrcodegen-test
# Build all binaries
all: $(LIBFILE) $(MAINS)
# Delete build output
clean:
rm -f -- $(LIBOBJ) $(LIBFILE) $(MAINS:=.o) $(MAINS)
rm -rf .deps
# Executable files
%: %.o $(LIBFILE)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -L . -l $(LIB)
# Special executable
qrcodegen-test: qrcodegen-test.c $(LIBOBJ:%.o=%.c)
$(CC) $(CFLAGS) $(LDFLAGS) -DQRCODEGEN_TEST -o $@ $^
# The library
$(LIBFILE): $(LIBOBJ)
$(AR) -crs $@ -- $^
# Object files
%.o: %.c .deps/timestamp
$(CC) $(CFLAGS) -c -o $@ -MMD -MF .deps/$*.d $<
# Have a place to store header dependencies automatically generated by compiler
.deps/timestamp:
mkdir -p .deps
touch .deps/timestamp
# Make use of said dependencies if available
-include .deps/*.d
================================================
FILE: c/Readme.markdown
================================================
QR Code generator library - C
=============================
Introduction
------------
This project aims to be the best, clearest QR Code generator library. The primary goals are flexible options and absolute correctness. Secondary goals are compact implementation size and good documentation comments.
Home page with live JavaScript demo, extensive descriptions, and competitor comparisons: https://www.nayuki.io/page/qr-code-generator-library
Features
--------
Core features:
* Significantly shorter code but more documentation comments compared to competing libraries
* Supports encoding all 40 versions (sizes) and all 4 error correction levels, as per the QR Code Model 2 standard
* Output format: Raw modules/pixels of the QR symbol
* Detects finder-like penalty patterns more accurately than other implementations
* Encodes numeric and special-alphanumeric text in less space than general text
* Completely avoids heap allocation (`malloc()`), instead relying on suitably sized buffers from the caller and fixed-size stack allocations
* Coded carefully to prevent memory corruption, integer overflow, platform-dependent inconsistencies, and undefined behavior; tested rigorously to confirm safety
* Open-source code under the permissive MIT License
Manual parameters:
* User can specify minimum and maximum version numbers allowed, then library will automatically choose smallest version in the range that fits the data
* User can specify mask pattern manually, otherwise library will automatically evaluate all 8 masks and select the optimal one
* User can specify absolute error correction level, or allow the library to boost it if it doesn't increase the version number
* User can create a list of data segments manually and add ECI segments
More information about QR Code technology and this library's design can be found on the project home page.
Examples
--------
```c
#include <stdbool.h>
#include <stdint.h>
#include "qrcodegen.h"
// Text data
uint8_t qr0[qrcodegen_BUFFER_LEN_MAX];
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
bool ok = qrcodegen_encodeText("Hello, world!",
tempBuffer, qr0, qrcodegen_Ecc_MEDIUM,
qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX,
qrcodegen_Mask_AUTO, true);
if (!ok)
return;
int size = qrcodegen_getSize(qr0);
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
(... paint qrcodegen_getModule(qr0, x, y) ...)
}
}
// Binary data
uint8_t dataAndTemp[qrcodegen_BUFFER_LEN_FOR_VERSION(7)]
= {0xE3, 0x81, 0x82};
uint8_t qr1[qrcodegen_BUFFER_LEN_FOR_VERSION(7)];
ok = qrcodegen_encodeBinary(dataAndTemp, 3, qr1,
qrcodegen_Ecc_HIGH, 2, 7, qrcodegen_Mask_4, false);
```
More complete set of examples: https://github.com/nayuki/QR-Code-generator/blob/master/c/qrcodegen-demo.c .
================================================
FILE: c/qrcodegen-demo.c
================================================
/*
* QR Code generator demo (C)
*
* Run this command-line program with no arguments. The program
* computes a demonstration QR Codes and print it to the console.
*
* Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* 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 <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "qrcodegen.h"
// Function prototypes
static void doBasicDemo(void);
static void doVarietyDemo(void);
static void doSegmentDemo(void);
static void doMaskDemo(void);
static void printQr(const uint8_t qrcode[]);
// The main application program.
int main(void) {
doBasicDemo();
doVarietyDemo();
doSegmentDemo();
doMaskDemo();
return EXIT_SUCCESS;
}
/*---- Demo suite ----*/
// Creates a single QR Code, then prints it to the console.
static void doBasicDemo(void) {
const char *text = "Hello, world!"; // User-supplied text
enum qrcodegen_Ecc errCorLvl = qrcodegen_Ecc_LOW; // Error correction level
// Make and print the QR Code symbol
uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
bool ok = qrcodegen_encodeText(text, tempBuffer, qrcode, errCorLvl,
qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
if (ok)
printQr(qrcode);
}
// Creates a variety of QR Codes that exercise different features of the library, and prints each one to the console.
static void doVarietyDemo(void) {
{ // Numeric mode encoding (3.33 bits per digit)
uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
bool ok = qrcodegen_encodeText("314159265358979323846264338327950288419716939937510", tempBuffer, qrcode,
qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
if (ok)
printQr(qrcode);
}
{ // Alphanumeric mode encoding (5.5 bits per character)
uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
bool ok = qrcodegen_encodeText("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", tempBuffer, qrcode,
qrcodegen_Ecc_HIGH, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
if (ok)
printQr(qrcode);
}
{ // Unicode text as UTF-8
const char *text = "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1wa\xE3\x80\x81"
"\xE4\xB8\x96\xE7\x95\x8C\xEF\xBC\x81\x20\xCE\xB1\xCE\xB2\xCE\xB3\xCE\xB4";
uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
bool ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
qrcodegen_Ecc_QUARTILE, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
if (ok)
printQr(qrcode);
}
{ // Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland)
const char *text =
"Alice was beginning to get very tired of sitting by her sister on the bank, "
"and of having nothing to do: once or twice she had peeped into the book her sister was reading, "
"but it had no pictures or conversations in it, 'and what is the use of a book,' thought Alice "
"'without pictures or conversations?' So she was considering in her own mind (as well as she could, "
"for the hot day made her feel very sleepy and stupid), whether the pleasure of making a "
"daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly "
"a White Rabbit with pink eyes ran close by her.";
uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
bool ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
qrcodegen_Ecc_HIGH, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
if (ok)
printQr(qrcode);
}
}
// Creates QR Codes with manually specified segments for better compactness.
static void doSegmentDemo(void) {
{ // Illustration "silver"
const char *silver0 = "THE SQUARE ROOT OF 2 IS 1.";
const char *silver1 = "41421356237309504880168872420969807856967187537694807317667973799";
uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
bool ok;
{
char *concat = calloc(strlen(silver0) + strlen(silver1) + 1, sizeof(char));
if (concat == NULL) {
perror("calloc");
exit(EXIT_FAILURE);
}
strcat(concat, silver0);
strcat(concat, silver1);
ok = qrcodegen_encodeText(concat, tempBuffer, qrcode, qrcodegen_Ecc_LOW,
qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
if (ok)
printQr(qrcode);
free(concat);
}
{
uint8_t *segBuf0 = malloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ALPHANUMERIC, strlen(silver0)) * sizeof(uint8_t));
uint8_t *segBuf1 = malloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, strlen(silver1)) * sizeof(uint8_t));
if (segBuf0 == NULL || segBuf1 == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
struct qrcodegen_Segment segs[] = {
qrcodegen_makeAlphanumeric(silver0, segBuf0),
qrcodegen_makeNumeric(silver1, segBuf1),
};
ok = qrcodegen_encodeSegments(segs, sizeof(segs) / sizeof(segs[0]), qrcodegen_Ecc_LOW, tempBuffer, qrcode);
free(segBuf0);
free(segBuf1);
if (ok)
printQr(qrcode);
}
}
{ // Illustration "golden"
const char *golden0 = "Golden ratio \xCF\x86 = 1.";
const char *golden1 = "6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374";
const char *golden2 = "......";
uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
bool ok;
{
char *concat = calloc(strlen(golden0) + strlen(golden1) + strlen(golden2) + 1, sizeof(char));
if (concat == NULL) {
perror("calloc");
exit(EXIT_FAILURE);
}
strcat(concat, golden0);
strcat(concat, golden1);
strcat(concat, golden2);
ok = qrcodegen_encodeText(concat, tempBuffer, qrcode, qrcodegen_Ecc_LOW,
qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
if (ok)
printQr(qrcode);
free(concat);
}
{
uint8_t *bytes = malloc(strlen(golden0) * sizeof(uint8_t));
if (bytes == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
for (size_t i = 0, len = strlen(golden0); i < len; i++)
bytes[i] = (uint8_t)golden0[i];
uint8_t *segBuf0 = malloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_BYTE, strlen(golden0)) * sizeof(uint8_t));
uint8_t *segBuf1 = malloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, strlen(golden1)) * sizeof(uint8_t));
uint8_t *segBuf2 = malloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ALPHANUMERIC, strlen(golden2)) * sizeof(uint8_t));
if (segBuf0 == NULL || segBuf1 == NULL || segBuf2 == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
struct qrcodegen_Segment segs[] = {
qrcodegen_makeBytes(bytes, strlen(golden0), segBuf0),
qrcodegen_makeNumeric(golden1, segBuf1),
qrcodegen_makeAlphanumeric(golden2, segBuf2),
};
free(bytes);
ok = qrcodegen_encodeSegments(segs, sizeof(segs) / sizeof(segs[0]), qrcodegen_Ecc_LOW, tempBuffer, qrcode);
free(segBuf0);
free(segBuf1);
free(segBuf2);
if (ok)
printQr(qrcode);
}
}
{ // Illustration "Madoka": kanji, kana, Cyrillic, full-width Latin, Greek characters
uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
bool ok;
{
const char *madoka = // Encoded in UTF-8
"\xE3\x80\x8C\xE9\xAD\x94\xE6\xB3\x95\xE5"
"\xB0\x91\xE5\xA5\xB3\xE3\x81\xBE\xE3\x81"
"\xA9\xE3\x81\x8B\xE2\x98\x86\xE3\x83\x9E"
"\xE3\x82\xAE\xE3\x82\xAB\xE3\x80\x8D\xE3"
"\x81\xA3\xE3\x81\xA6\xE3\x80\x81\xE3\x80"
"\x80\xD0\x98\xD0\x90\xD0\x98\xE3\x80\x80"
"\xEF\xBD\x84\xEF\xBD\x85\xEF\xBD\x93\xEF"
"\xBD\x95\xE3\x80\x80\xCE\xBA\xCE\xB1\xEF"
"\xBC\x9F";
ok = qrcodegen_encodeText(madoka, tempBuffer, qrcode, qrcodegen_Ecc_LOW,
qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
if (ok)
printQr(qrcode);
}
{
const int kanjiChars[] = { // Kanji mode encoding (13 bits per character)
0x0035, 0x1002, 0x0FC0, 0x0AED, 0x0AD7,
0x015C, 0x0147, 0x0129, 0x0059, 0x01BD,
0x018D, 0x018A, 0x0036, 0x0141, 0x0144,
0x0001, 0x0000, 0x0249, 0x0240, 0x0249,
0x0000, 0x0104, 0x0105, 0x0113, 0x0115,
0x0000, 0x0208, 0x01FF, 0x0008,
};
size_t len = sizeof(kanjiChars) / sizeof(kanjiChars[0]);
uint8_t *segBuf = calloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_KANJI, len), sizeof(uint8_t));
if (segBuf == NULL) {
perror("calloc");
exit(EXIT_FAILURE);
}
struct qrcodegen_Segment seg;
seg.mode = qrcodegen_Mode_KANJI;
seg.numChars = (int)len;
seg.bitLength = 0;
for (size_t i = 0; i < len; i++) {
for (int j = 12; j >= 0; j--, seg.bitLength++)
segBuf[seg.bitLength >> 3] |= ((kanjiChars[i] >> j) & 1) << (7 - (seg.bitLength & 7));
}
seg.data = segBuf;
ok = qrcodegen_encodeSegments(&seg, 1, qrcodegen_Ecc_LOW, tempBuffer, qrcode);
free(segBuf);
if (ok)
printQr(qrcode);
}
}
}
// Creates QR Codes with the same size and contents but different mask patterns.
static void doMaskDemo(void) {
{ // Project Nayuki URL
uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
bool ok;
ok = qrcodegen_encodeText("https://www.nayuki.io/", tempBuffer, qrcode,
qrcodegen_Ecc_HIGH, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
if (ok)
printQr(qrcode);
ok = qrcodegen_encodeText("https://www.nayuki.io/", tempBuffer, qrcode,
qrcodegen_Ecc_HIGH, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_3, true);
if (ok)
printQr(qrcode);
}
{ // Chinese text as UTF-8
const char *text =
"\xE7\xB6\xAD\xE5\x9F\xBA\xE7\x99\xBE\xE7\xA7\x91\xEF\xBC\x88\x57\x69\x6B\x69\x70"
"\x65\x64\x69\x61\xEF\xBC\x8C\xE8\x81\x86\xE8\x81\xBD\x69\x2F\xCB\x8C\x77\xC9\xAA"
"\x6B\xE1\xB5\xBB\xCB\x88\x70\x69\xCB\x90\x64\x69\x2E\xC9\x99\x2F\xEF\xBC\x89\xE6"
"\x98\xAF\xE4\xB8\x80\xE5\x80\x8B\xE8\x87\xAA\xE7\x94\xB1\xE5\x85\xA7\xE5\xAE\xB9"
"\xE3\x80\x81\xE5\x85\xAC\xE9\x96\x8B\xE7\xB7\xA8\xE8\xBC\xAF\xE4\xB8\x94\xE5\xA4"
"\x9A\xE8\xAA\x9E\xE8\xA8\x80\xE7\x9A\x84\xE7\xB6\xB2\xE8\xB7\xAF\xE7\x99\xBE\xE7"
"\xA7\x91\xE5\x85\xA8\xE6\x9B\xB8\xE5\x8D\x94\xE4\xBD\x9C\xE8\xA8\x88\xE7\x95\xAB";
uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
bool ok;
ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_0, true);
if (ok)
printQr(qrcode);
ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_1, true);
if (ok)
printQr(qrcode);
ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_5, true);
if (ok)
printQr(qrcode);
ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_7, true);
if (ok)
printQr(qrcode);
}
}
/*---- Utilities ----*/
// Prints the given QR Code to the console.
static void printQr(const uint8_t qrcode[]) {
int size = qrcodegen_getSize(qrcode);
int border = 4;
for (int y = -border; y < size + border; y++) {
for (int x = -border; x < size + border; x++) {
fputs((qrcodegen_getModule(qrcode, x, y) ? "##" : " "), stdout);
}
fputs("\n", stdout);
}
fputs("\n", stdout);
}
================================================
FILE: c/qrcodegen-test.c
================================================
/*
* QR Code generator test suite (C)
*
* When compiling this program, the library qrcodegen.c needs QRCODEGEN_TEST
* to be defined. Run this command line program with no arguments.
*
* Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* 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 <assert.h>
#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "qrcodegen.h"
#define ARRAY_LENGTH(name) (sizeof(name) / sizeof(name[0]))
// Global variables
static int numTestCases = 0;
// Prototypes of private functions under test
extern const int8_t ECC_CODEWORDS_PER_BLOCK[4][41];
extern const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41];
void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen);
void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]);
int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
int getNumRawDataModules(int version);
void reedSolomonComputeDivisor(int degree, uint8_t result[]);
void reedSolomonComputeRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]);
uint8_t reedSolomonMultiply(uint8_t x, uint8_t y);
void initializeFunctionModules(int version, uint8_t qrcode[]);
int getAlignmentPatternPositions(int version, uint8_t result[7]);
bool getModuleBounded(const uint8_t qrcode[], int x, int y);
void setModuleBounded(uint8_t qrcode[], int x, int y, bool isDark);
void setModuleUnbounded(uint8_t qrcode[], int x, int y, bool isDark);
int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars);
int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version);
/*---- Test cases ----*/
static void testAppendBitsToBuffer(void) {
{
uint8_t buf[1] = {0};
int bitLen = 0;
appendBitsToBuffer(0, 0, buf, &bitLen);
assert(bitLen == 0);
assert(buf[0] == 0);
appendBitsToBuffer(1, 1, buf, &bitLen);
assert(bitLen == 1);
assert(buf[0] == 0x80);
appendBitsToBuffer(0, 1, buf, &bitLen);
assert(bitLen == 2);
assert(buf[0] == 0x80);
appendBitsToBuffer(5, 3, buf, &bitLen);
assert(bitLen == 5);
assert(buf[0] == 0xA8);
appendBitsToBuffer(6, 3, buf, &bitLen);
assert(bitLen == 8);
assert(buf[0] == 0xAE);
numTestCases++;
}
{
uint8_t buf[6] = {0};
int bitLen = 0;
appendBitsToBuffer(16942, 16, buf, &bitLen);
assert(bitLen == 16);
assert(buf[0] == 0x42 && buf[1] == 0x2E && buf[2] == 0x00 && buf[3] == 0x00 && buf[4] == 0x00 && buf[5] == 0x00);
appendBitsToBuffer(10, 7, buf, &bitLen);
assert(bitLen == 23);
assert(buf[0] == 0x42 && buf[1] == 0x2E && buf[2] == 0x14 && buf[3] == 0x00 && buf[4] == 0x00 && buf[5] == 0x00);
appendBitsToBuffer(15, 4, buf, &bitLen);
assert(bitLen == 27);
assert(buf[0] == 0x42 && buf[1] == 0x2E && buf[2] == 0x15 && buf[3] == 0xE0 && buf[4] == 0x00 && buf[5] == 0x00);
appendBitsToBuffer(26664, 15, buf, &bitLen);
assert(bitLen == 42);
assert(buf[0] == 0x42 && buf[1] == 0x2E && buf[2] == 0x15 && buf[3] == 0xFA && buf[4] == 0x0A && buf[5] == 0x00);
numTestCases++;
}
}
// Ported from the Java version of the code.
static uint8_t *addEccAndInterleaveReference(const uint8_t *data, int version, enum qrcodegen_Ecc ecl) {
// Calculate parameter numbers
size_t numBlocks = (size_t)NUM_ERROR_CORRECTION_BLOCKS[(int)ecl][version];
size_t blockEccLen = (size_t)ECC_CODEWORDS_PER_BLOCK[(int)ecl][version];
size_t rawCodewords = (size_t)getNumRawDataModules(version) / 8;
size_t numShortBlocks = numBlocks - rawCodewords % numBlocks;
size_t shortBlockLen = rawCodewords / numBlocks;
// Split data into blocks and append ECC to each block
uint8_t **blocks = malloc(numBlocks * sizeof(uint8_t*));
uint8_t *generator = malloc(blockEccLen * sizeof(uint8_t));
if (blocks == NULL || generator == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
reedSolomonComputeDivisor((int)blockEccLen, generator);
for (size_t i = 0, k = 0; i < numBlocks; i++) {
uint8_t *block = malloc((shortBlockLen + 1) * sizeof(uint8_t));
if (block == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
size_t datLen = shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1);
memcpy(block, &data[k], datLen * sizeof(uint8_t));
reedSolomonComputeRemainder(&data[k], (int)datLen, generator, (int)blockEccLen, &block[shortBlockLen + 1 - blockEccLen]);
k += datLen;
blocks[i] = block;
}
free(generator);
// Interleave (not concatenate) the bytes from every block into a single sequence
uint8_t *result = malloc(rawCodewords * sizeof(uint8_t));
if (result == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
for (size_t i = 0, k = 0; i < shortBlockLen + 1; i++) {
for (size_t j = 0; j < numBlocks; j++) {
// Skip the padding byte in short blocks
if (i != shortBlockLen - blockEccLen || j >= numShortBlocks) {
result[k] = blocks[j][i];
k++;
}
}
}
for (size_t i = 0; i < numBlocks; i++)
free(blocks[i]);
free(blocks);
return result;
}
static void testAddEccAndInterleave(void) {
for (int version = 1; version <= 40; version++) {
for (int ecl = 0; ecl < 4; ecl++) {
size_t dataLen = (size_t)getNumDataCodewords(version, (enum qrcodegen_Ecc)ecl);
uint8_t *pureData = malloc(dataLen * sizeof(uint8_t));
if (pureData == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < dataLen; i++)
pureData[i] = (uint8_t)(rand() % 256);
uint8_t *expectOutput = addEccAndInterleaveReference(pureData, version, (enum qrcodegen_Ecc)ecl);
size_t dataAndEccLen = (size_t)getNumRawDataModules(version) / 8;
uint8_t *paddedData = malloc(dataAndEccLen * sizeof(uint8_t));
if (paddedData == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
memcpy(paddedData, pureData, dataLen * sizeof(uint8_t));
uint8_t *actualOutput = malloc(dataAndEccLen * sizeof(uint8_t));
if (actualOutput == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
addEccAndInterleave(paddedData, version, (enum qrcodegen_Ecc)ecl, actualOutput);
assert(memcmp(actualOutput, expectOutput, dataAndEccLen * sizeof(uint8_t)) == 0);
free(pureData);
free(expectOutput);
free(paddedData);
free(actualOutput);
numTestCases++;
}
}
}
static void testGetNumDataCodewords(void) {
const int cases[][3] = {
{ 3, 1, 44},
{ 3, 2, 34},
{ 3, 3, 26},
{ 6, 0, 136},
{ 7, 0, 156},
{ 9, 0, 232},
{ 9, 1, 182},
{12, 3, 158},
{15, 0, 523},
{16, 2, 325},
{19, 3, 341},
{21, 0, 932},
{22, 0, 1006},
{22, 1, 782},
{22, 3, 442},
{24, 0, 1174},
{24, 3, 514},
{28, 0, 1531},
{30, 3, 745},
{32, 3, 845},
{33, 0, 2071},
{33, 3, 901},
{35, 0, 2306},
{35, 1, 1812},
{35, 2, 1286},
{36, 3, 1054},
{37, 3, 1096},
{39, 1, 2216},
{40, 1, 2334},
};
for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
const int *tc = cases[i];
assert(getNumDataCodewords(tc[0], (enum qrcodegen_Ecc)tc[1]) == tc[2]);
numTestCases++;
}
}
static void testGetNumRawDataModules(void) {
const int cases[][2] = {
{ 1, 208},
{ 2, 359},
{ 3, 567},
{ 6, 1383},
{ 7, 1568},
{12, 3728},
{15, 5243},
{18, 7211},
{22, 10068},
{26, 13652},
{32, 19723},
{37, 25568},
{40, 29648},
};
for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
const int *tc = cases[i];
assert(getNumRawDataModules(tc[0]) == tc[1]);
numTestCases++;
}
}
static void testReedSolomonComputeDivisor(void) {
uint8_t generator[30];
reedSolomonComputeDivisor(1, generator);
assert(generator[0] == 0x01);
numTestCases++;
reedSolomonComputeDivisor(2, generator);
assert(generator[0] == 0x03);
assert(generator[1] == 0x02);
numTestCases++;
reedSolomonComputeDivisor(5, generator);
assert(generator[0] == 0x1F);
assert(generator[1] == 0xC6);
assert(generator[2] == 0x3F);
assert(generator[3] == 0x93);
assert(generator[4] == 0x74);
numTestCases++;
reedSolomonComputeDivisor(30, generator);
assert(generator[ 0] == 0xD4);
assert(generator[ 1] == 0xF6);
assert(generator[ 5] == 0xC0);
assert(generator[12] == 0x16);
assert(generator[13] == 0xD9);
assert(generator[20] == 0x12);
assert(generator[27] == 0x6A);
assert(generator[29] == 0x96);
numTestCases++;
}
static void testReedSolomonComputeRemainder(void) {
{
uint8_t data[1];
uint8_t generator[3];
uint8_t remainder[ARRAY_LENGTH(generator)];
reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator);
reedSolomonComputeRemainder(data, 0, generator, ARRAY_LENGTH(generator), remainder);
assert(remainder[0] == 0);
assert(remainder[1] == 0);
assert(remainder[2] == 0);
numTestCases++;
}
{
uint8_t data[2] = {0, 1};
uint8_t generator[4];
uint8_t remainder[ARRAY_LENGTH(generator)];
reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator);
reedSolomonComputeRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
assert(remainder[0] == generator[0]);
assert(remainder[1] == generator[1]);
assert(remainder[2] == generator[2]);
assert(remainder[3] == generator[3]);
numTestCases++;
}
{
uint8_t data[5] = {0x03, 0x3A, 0x60, 0x12, 0xC7};
uint8_t generator[5];
uint8_t remainder[ARRAY_LENGTH(generator)];
reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator);
reedSolomonComputeRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
assert(remainder[0] == 0xCB);
assert(remainder[1] == 0x36);
assert(remainder[2] == 0x16);
assert(remainder[3] == 0xFA);
assert(remainder[4] == 0x9D);
numTestCases++;
}
{
uint8_t data[43] = {
0x38, 0x71, 0xDB, 0xF9, 0xD7, 0x28, 0xF6, 0x8E, 0xFE, 0x5E,
0xE6, 0x7D, 0x7D, 0xB2, 0xA5, 0x58, 0xBC, 0x28, 0x23, 0x53,
0x14, 0xD5, 0x61, 0xC0, 0x20, 0x6C, 0xDE, 0xDE, 0xFC, 0x79,
0xB0, 0x8B, 0x78, 0x6B, 0x49, 0xD0, 0x1A, 0xAD, 0xF3, 0xEF,
0x52, 0x7D, 0x9A,
};
uint8_t generator[30];
uint8_t remainder[ARRAY_LENGTH(generator)];
reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator);
reedSolomonComputeRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
assert(remainder[ 0] == 0xCE);
assert(remainder[ 1] == 0xF0);
assert(remainder[ 2] == 0x31);
assert(remainder[ 3] == 0xDE);
assert(remainder[ 8] == 0xE1);
assert(remainder[12] == 0xCA);
assert(remainder[17] == 0xE3);
assert(remainder[19] == 0x85);
assert(remainder[20] == 0x50);
assert(remainder[24] == 0xBE);
assert(remainder[29] == 0xB3);
numTestCases++;
}
}
static void testReedSolomonMultiply(void) {
const uint8_t cases[][3] = {
{0x00, 0x00, 0x00},
{0x01, 0x01, 0x01},
{0x02, 0x02, 0x04},
{0x00, 0x6E, 0x00},
{0xB2, 0xDD, 0xE6},
{0x41, 0x11, 0x25},
{0xB0, 0x1F, 0x11},
{0x05, 0x75, 0xBC},
{0x52, 0xB5, 0xAE},
{0xA8, 0x20, 0xA4},
{0x0E, 0x44, 0x9F},
{0xD4, 0x13, 0xA0},
{0x31, 0x10, 0x37},
{0x6C, 0x58, 0xCB},
{0xB6, 0x75, 0x3E},
{0xFF, 0xFF, 0xE2},
};
for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
const uint8_t *tc = cases[i];
assert(reedSolomonMultiply(tc[0], tc[1]) == tc[2]);
numTestCases++;
}
}
static void testInitializeFunctionModulesEtc(void) {
for (int ver = 1; ver <= 40; ver++) {
uint8_t *qrcode = malloc((size_t)qrcodegen_BUFFER_LEN_FOR_VERSION(ver) * sizeof(uint8_t));
if (qrcode == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
initializeFunctionModules(ver, qrcode);
int size = qrcodegen_getSize(qrcode);
if (ver == 1)
assert(size == 21);
else if (ver == 40)
assert(size == 177);
else
assert(size == ver * 4 + 17);
bool hasLight = false;
bool hasDark = false;
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
bool color = qrcodegen_getModule(qrcode, x, y);
if (color)
hasDark = true;
else
hasLight = true;
}
}
assert(hasLight && hasDark);
free(qrcode);
numTestCases++;
}
}
static void testGetAlignmentPatternPositions(void) {
const int cases[][9] = {
{ 1, 0, -1, -1, -1, -1, -1, -1, -1},
{ 2, 2, 6, 18, -1, -1, -1, -1, -1},
{ 3, 2, 6, 22, -1, -1, -1, -1, -1},
{ 6, 2, 6, 34, -1, -1, -1, -1, -1},
{ 7, 3, 6, 22, 38, -1, -1, -1, -1},
{ 8, 3, 6, 24, 42, -1, -1, -1, -1},
{16, 4, 6, 26, 50, 74, -1, -1, -1},
{25, 5, 6, 32, 58, 84, 110, -1, -1},
{32, 6, 6, 34, 60, 86, 112, 138, -1},
{33, 6, 6, 30, 58, 86, 114, 142, -1},
{39, 7, 6, 26, 54, 82, 110, 138, 166},
{40, 7, 6, 30, 58, 86, 114, 142, 170},
};
for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
const int *tc = cases[i];
uint8_t pos[7];
int num = getAlignmentPatternPositions(tc[0], pos);
assert(num == tc[1]);
for (int j = 0; j < num; j++)
assert(pos[j] == tc[2 + j]);
numTestCases++;
}
}
static void testGetSetModule(void) {
uint8_t qrcode[qrcodegen_BUFFER_LEN_FOR_VERSION(23)];
initializeFunctionModules(23, qrcode);
int size = qrcodegen_getSize(qrcode);
for (int y = 0; y < size; y++) { // Clear all to light
for (int x = 0; x < size; x++)
setModuleBounded(qrcode, x, y, false);
}
for (int y = 0; y < size; y++) { // Check all light
for (int x = 0; x < size; x++)
assert(qrcodegen_getModule(qrcode, x, y) == false);
}
for (int y = 0; y < size; y++) { // Set all to dark
for (int x = 0; x < size; x++)
setModuleBounded(qrcode, x, y, true);
}
for (int y = 0; y < size; y++) { // Check all dark
for (int x = 0; x < size; x++)
assert(qrcodegen_getModule(qrcode, x, y) == true);
}
// Set some out of bounds modules to light
setModuleUnbounded(qrcode, -1, -1, false);
setModuleUnbounded(qrcode, -1, 0, false);
setModuleUnbounded(qrcode, 0, -1, false);
setModuleUnbounded(qrcode, size, 5, false);
setModuleUnbounded(qrcode, 72, size, false);
setModuleUnbounded(qrcode, size, size, false);
for (int y = 0; y < size; y++) { // Check all dark
for (int x = 0; x < size; x++)
assert(qrcodegen_getModule(qrcode, x, y) == true);
}
// Set some modules to light
setModuleBounded(qrcode, 3, 8, false);
setModuleBounded(qrcode, 61, 49, false);
for (int y = 0; y < size; y++) { // Check most dark
for (int x = 0; x < size; x++) {
bool light = (x == 3 && y == 8) || (x == 61 && y == 49);
assert(qrcodegen_getModule(qrcode, x, y) != light);
}
}
numTestCases++;
}
static void testGetSetModuleRandomly(void) {
uint8_t qrcode[qrcodegen_BUFFER_LEN_FOR_VERSION(1)];
initializeFunctionModules(1, qrcode);
int size = qrcodegen_getSize(qrcode);
bool modules[21][21];
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++)
modules[y][x] = qrcodegen_getModule(qrcode, x, y);
}
long trials = 100000;
for (long i = 0; i < trials; i++) {
int x = rand() % (size * 2) - size / 2;
int y = rand() % (size * 2) - size / 2;
bool isInBounds = 0 <= x && x < size && 0 <= y && y < size;
bool oldColor = isInBounds && modules[y][x];
if (isInBounds)
assert(getModuleBounded(qrcode, x, y) == oldColor);
assert(qrcodegen_getModule(qrcode, x, y) == oldColor);
bool newColor = rand() % 2 == 0;
if (isInBounds)
modules[y][x] = newColor;
if (isInBounds && rand() % 2 == 0)
setModuleBounded(qrcode, x, y, newColor);
else
setModuleUnbounded(qrcode, x, y, newColor);
}
numTestCases++;
}
static void testIsAlphanumeric(void) {
struct TestCase {
bool answer;
const char *text;
};
const struct TestCase cases[] = {
{true, ""},
{true, "0"},
{true, "A"},
{false, "a"},
{true, " "},
{true, "."},
{true, "*"},
{false, ","},
{false, "|"},
{false, "@"},
{true, "XYZ"},
{false, "XYZ!"},
{true, "79068"},
{true, "+123 ABC$"},
{false, "\x01"},
{false, "\x7F"},
{false, "\x80"},
{false, "\xC0"},
{false, "\xFF"},
};
for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
assert(qrcodegen_isAlphanumeric(cases[i].text) == cases[i].answer);
numTestCases++;
}
}
static void testIsNumeric(void) {
struct TestCase {
bool answer;
const char *text;
};
const struct TestCase cases[] = {
{true, ""},
{true, "0"},
{false, "A"},
{false, "a"},
{false, " "},
{false, "."},
{false, "*"},
{false, ","},
{false, "|"},
{false, "@"},
{false, "XYZ"},
{false, "XYZ!"},
{true, "79068"},
{false, "+123 ABC$"},
{false, "\x01"},
{false, "\x7F"},
{false, "\x80"},
{false, "\xC0"},
{false, "\xFF"},
};
for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
assert(qrcodegen_isNumeric(cases[i].text) == cases[i].answer);
numTestCases++;
}
}
static void testCalcSegmentBufferSize(void) {
{
const size_t cases[][2] = {
{0, 0},
{1, 1},
{2, 1},
{3, 2},
{4, 2},
{5, 3},
{6, 3},
{1472, 614},
{2097, 874},
{5326, 2220},
{9828, 4095},
{9829, 4096},
{9830, 4096},
{9831, SIZE_MAX},
{9832, SIZE_MAX},
{12000, SIZE_MAX},
{28453, SIZE_MAX},
{55555, SIZE_MAX},
{SIZE_MAX / 6, SIZE_MAX},
{SIZE_MAX / 4, SIZE_MAX},
{SIZE_MAX / 2, SIZE_MAX},
{SIZE_MAX / 1, SIZE_MAX},
};
for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
assert(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, cases[i][0]) == cases[i][1]);
numTestCases++;
}
}
{
const size_t cases[][2] = {
{0, 0},
{1, 1},
{2, 2},
{3, 3},
{4, 3},
{5, 4},
{6, 5},
{1472, 1012},
{2097, 1442},
{5326, 3662},
{5955, 4095},
{5956, 4095},
{5957, 4096},
{5958, SIZE_MAX},
{5959, SIZE_MAX},
{12000, SIZE_MAX},
{28453, SIZE_MAX},
{55555, SIZE_MAX},
{SIZE_MAX / 10, SIZE_MAX},
{SIZE_MAX / 8, SIZE_MAX},
{SIZE_MAX / 5, SIZE_MAX},
{SIZE_MAX / 2, SIZE_MAX},
{SIZE_MAX / 1, SIZE_MAX},
};
for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
assert(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ALPHANUMERIC, cases[i][0]) == cases[i][1]);
numTestCases++;
}
}
{
const size_t cases[][2] = {
{0, 0},
{1, 1},
{2, 2},
{3, 3},
{1472, 1472},
{2097, 2097},
{4094, 4094},
{4095, 4095},
{4096, SIZE_MAX},
{4097, SIZE_MAX},
{5957, SIZE_MAX},
{12000, SIZE_MAX},
{28453, SIZE_MAX},
{55555, SIZE_MAX},
{SIZE_MAX / 16 + 1, SIZE_MAX},
{SIZE_MAX / 14, SIZE_MAX},
{SIZE_MAX / 9, SIZE_MAX},
{SIZE_MAX / 7, SIZE_MAX},
{SIZE_MAX / 4, SIZE_MAX},
{SIZE_MAX / 3, SIZE_MAX},
{SIZE_MAX / 2, SIZE_MAX},
{SIZE_MAX / 1, SIZE_MAX},
};
for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
assert(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_BYTE, cases[i][0]) == cases[i][1]);
numTestCases++;
}
}
{
const size_t cases[][2] = {
{0, 0},
{1, 2},
{2, 4},
{3, 5},
{1472, 2392},
{2097, 3408},
{2519, 4094},
{2520, 4095},
{2521, SIZE_MAX},
{5957, SIZE_MAX},
{2522, SIZE_MAX},
{12000, SIZE_MAX},
{28453, SIZE_MAX},
{55555, SIZE_MAX},
{SIZE_MAX / 13 + 1, SIZE_MAX},
{SIZE_MAX / 12, SIZE_MAX},
{SIZE_MAX / 9, SIZE_MAX},
{SIZE_MAX / 4, SIZE_MAX},
{SIZE_MAX / 3, SIZE_MAX},
{SIZE_MAX / 2, SIZE_MAX},
{SIZE_MAX / 1, SIZE_MAX},
};
for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
assert(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_KANJI, cases[i][0]) == cases[i][1]);
numTestCases++;
}
}
{
assert(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ECI, 0) == 3);
numTestCases++;
}
}
static void testCalcSegmentBitLength(void) {
struct TestCase {
size_t numChars;
int result;
};
{
const struct TestCase CASES[] = {
{0, 0},
{1, 4},
{2, 7},
{3, 10},
{4, 14},
{5, 17},
{6, 20},
{1472, 4907},
{2097, 6990},
{5326, 17754},
{9828, 32760},
{9829, 32764},
{9830, 32767},
{9831, -1},
{9832, -1},
{12000, -1},
{28453, -1},
{SIZE_MAX / 6, -1},
{SIZE_MAX / 3, -1},
{SIZE_MAX / 2, -1},
{SIZE_MAX / 1, -1},
};
for (size_t i = 0; i < ARRAY_LENGTH(CASES); i++) {
assert(calcSegmentBitLength(qrcodegen_Mode_NUMERIC, CASES[i].numChars) == CASES[i].result);
numTestCases++;
}
}
{
const struct TestCase CASES[] = {
{0, 0},
{1, 6},
{2, 11},
{3, 17},
{4, 22},
{5, 28},
{6, 33},
{1472, 8096},
{2097, 11534},
{5326, 29293},
{5955, 32753},
{5956, 32758},
{5957, 32764},
{5958, -1},
{5959, -1},
{12000, -1},
{28453, -1},
{SIZE_MAX / 10, -1},
{SIZE_MAX / 5, -1},
{SIZE_MAX / 2, -1},
{SIZE_MAX / 1, -1},
};
for (size_t i = 0; i < ARRAY_LENGTH(CASES); i++) {
assert(calcSegmentBitLength(qrcodegen_Mode_ALPHANUMERIC, CASES[i].numChars) == CASES[i].result);
numTestCases++;
}
}
{
const struct TestCase CASES[] = {
{0, 0},
{1, 8},
{2, 16},
{3, 24},
{1472, 11776},
{2097, 16776},
{4094, 32752},
{4095, 32760},
{4096, -1},
{4097, -1},
{5957, -1},
{12000, -1},
{28453, -1},
{SIZE_MAX / 15, -1},
{SIZE_MAX / 12, -1},
{SIZE_MAX / 7, -1},
{SIZE_MAX / 3, -1},
{SIZE_MAX / 1, -1},
};
for (size_t i = 0; i < ARRAY_LENGTH(CASES); i++) {
assert(calcSegmentBitLength(qrcodegen_Mode_BYTE, CASES[i].numChars) == CASES[i].result);
numTestCases++;
}
}
{
const struct TestCase CASES[] = {
{0, 0},
{1, 13},
{2, 26},
{3, 39},
{1472, 19136},
{2097, 27261},
{2519, 32747},
{2520, 32760},
{2521, -1},
{5957, -1},
{2522, -1},
{12000, -1},
{28453, -1},
{SIZE_MAX / 25, -1},
{SIZE_MAX / 20, -1},
{SIZE_MAX / 11, -1},
{SIZE_MAX / 4, -1},
{SIZE_MAX / 2, -1},
{SIZE_MAX / 1, -1},
};
for (size_t i = 0; i < ARRAY_LENGTH(CASES); i++) {
assert(calcSegmentBitLength(qrcodegen_Mode_KANJI, CASES[i].numChars) == CASES[i].result);
numTestCases++;
}
}
{
assert(calcSegmentBitLength(qrcodegen_Mode_ECI, 0) == 24);
numTestCases++;
}
}
static void testMakeBytes(void) {
{
struct qrcodegen_Segment seg = qrcodegen_makeBytes(NULL, 0, NULL);
assert(seg.mode == qrcodegen_Mode_BYTE);
assert(seg.numChars == 0);
assert(seg.bitLength == 0);
numTestCases++;
}
{
const uint8_t data[] = {0x00};
uint8_t buf[1];
struct qrcodegen_Segment seg = qrcodegen_makeBytes(data, 1, buf);
assert(seg.numChars == 1);
assert(seg.bitLength == 8);
assert(seg.data[0] == 0x00);
numTestCases++;
}
{
const uint8_t data[] = {0xEF, 0xBB, 0xBF};
uint8_t buf[3];
struct qrcodegen_Segment seg = qrcodegen_makeBytes(data, 3, buf);
assert(seg.numChars == 3);
assert(seg.bitLength == 24);
assert(seg.data[0] == 0xEF);
assert(seg.data[1] == 0xBB);
assert(seg.data[2] == 0xBF);
numTestCases++;
}
}
static void testMakeNumeric(void) {
{
struct qrcodegen_Segment seg = qrcodegen_makeNumeric("", NULL);
assert(seg.mode == qrcodegen_Mode_NUMERIC);
assert(seg.numChars == 0);
assert(seg.bitLength == 0);
numTestCases++;
}
{
uint8_t buf[1];
struct qrcodegen_Segment seg = qrcodegen_makeNumeric("9", buf);
assert(seg.numChars == 1);
assert(seg.bitLength == 4);
assert(seg.data[0] == 0x90);
numTestCases++;
}
{
uint8_t buf[1];
struct qrcodegen_Segment seg = qrcodegen_makeNumeric("81", buf);
assert(seg.numChars == 2);
assert(seg.bitLength == 7);
assert(seg.data[0] == 0xA2);
numTestCases++;
}
{
uint8_t buf[2];
struct qrcodegen_Segment seg = qrcodegen_makeNumeric("673", buf);
assert(seg.numChars == 3);
assert(seg.bitLength == 10);
assert(seg.data[0] == 0xA8);
assert(seg.data[1] == 0x40);
numTestCases++;
}
{
uint8_t buf[5];
struct qrcodegen_Segment seg = qrcodegen_makeNumeric("3141592653", buf);
assert(seg.numChars == 10);
assert(seg.bitLength == 34);
assert(seg.data[0] == 0x4E);
assert(seg.data[1] == 0x89);
assert(seg.data[2] == 0xF4);
assert(seg.data[3] == 0x24);
assert(seg.data[4] == 0xC0);
numTestCases++;
}
}
static void testMakeAlphanumeric(void) {
{
struct qrcodegen_Segment seg = qrcodegen_makeAlphanumeric("", NULL);
assert(seg.mode == qrcodegen_Mode_ALPHANUMERIC);
assert(seg.numChars == 0);
assert(seg.bitLength == 0);
numTestCases++;
}
{
uint8_t buf[1];
struct qrcodegen_Segment seg = qrcodegen_makeAlphanumeric("A", buf);
assert(seg.numChars == 1);
assert(seg.bitLength == 6);
assert(seg.data[0] == 0x28);
numTestCases++;
}
{
uint8_t buf[2];
struct qrcodegen_Segment seg = qrcodegen_makeAlphanumeric("%:", buf);
assert(seg.numChars == 2);
assert(seg.bitLength == 11);
assert(seg.data[0] == 0xDB);
assert(seg.data[1] == 0x40);
numTestCases++;
}
{
uint8_t buf[3];
struct qrcodegen_Segment seg = qrcodegen_makeAlphanumeric("Q R", buf);
assert(seg.numChars == 3);
assert(seg.bitLength == 17);
assert(seg.data[0] == 0x96);
assert(seg.data[1] == 0xCD);
assert(seg.data[2] == 0x80);
numTestCases++;
}
}
static void testMakeEci(void) {
{
uint8_t buf[1];
struct qrcodegen_Segment seg = qrcodegen_makeEci(127, buf);
assert(seg.mode == qrcodegen_Mode_ECI);
assert(seg.numChars == 0);
assert(seg.bitLength == 8);
assert(seg.data[0] == 0x7F);
numTestCases++;
}
{
uint8_t buf[2];
struct qrcodegen_Segment seg = qrcodegen_makeEci(10345, buf);
assert(seg.numChars == 0);
assert(seg.bitLength == 16);
assert(seg.data[0] == 0xA8);
assert(seg.data[1] == 0x69);
numTestCases++;
}
{
uint8_t buf[3];
struct qrcodegen_Segment seg = qrcodegen_makeEci(999999, buf);
assert(seg.numChars == 0);
assert(seg.bitLength == 24);
assert(seg.data[0] == 0xCF);
assert(seg.data[1] == 0x42);
assert(seg.data[2] == 0x3F);
numTestCases++;
}
}
static void testGetTotalBits(void) {
{
assert(getTotalBits(NULL, 0, 1) == 0);
numTestCases++;
assert(getTotalBits(NULL, 0, 40) == 0);
numTestCases++;
}
{
struct qrcodegen_Segment segs[] = {
{qrcodegen_Mode_BYTE, 3, NULL, 24},
};
assert(getTotalBits(segs, ARRAY_LENGTH(segs), 2) == 36);
numTestCases++;
assert(getTotalBits(segs, ARRAY_LENGTH(segs), 10) == 44);
numTestCases++;
assert(getTotalBits(segs, ARRAY_LENGTH(segs), 39) == 44);
numTestCases++;
}
{
struct qrcodegen_Segment segs[] = {
{qrcodegen_Mode_ECI, 0, NULL, 8},
{qrcodegen_Mode_NUMERIC, 7, NULL, 24},
{qrcodegen_Mode_ALPHANUMERIC, 1, NULL, 6},
{qrcodegen_Mode_KANJI, 4, NULL, 52},
};
assert(getTotalBits(segs, ARRAY_LENGTH(segs), 9) == 133);
numTestCases++;
assert(getTotalBits(segs, ARRAY_LENGTH(segs), 21) == 139);
numTestCases++;
assert(getTotalBits(segs, ARRAY_LENGTH(segs), 27) == 145);
numTestCases++;
}
{
struct qrcodegen_Segment segs[] = {
{qrcodegen_Mode_BYTE, 4093, NULL, 32744},
};
assert(getTotalBits(segs, ARRAY_LENGTH(segs), 1) == -1);
numTestCases++;
assert(getTotalBits(segs, ARRAY_LENGTH(segs), 10) == 32764);
numTestCases++;
assert(getTotalBits(segs, ARRAY_LENGTH(segs), 27) == 32764);
numTestCases++;
}
{
struct qrcodegen_Segment segs[] = {
{qrcodegen_Mode_NUMERIC, 2047, NULL, 6824},
{qrcodegen_Mode_NUMERIC, 2047, NULL, 6824},
{qrcodegen_Mode_NUMERIC, 2047, NULL, 6824},
{qrcodegen_Mode_NUMERIC, 2047, NULL, 6824},
{qrcodegen_Mode_NUMERIC, 1617, NULL, 5390},
};
assert(getTotalBits(segs, ARRAY_LENGTH(segs), 1) == -1);
numTestCases++;
assert(getTotalBits(segs, ARRAY_LENGTH(segs), 10) == 32766);
numTestCases++;
assert(getTotalBits(segs, ARRAY_LENGTH(segs), 27) == -1);
numTestCases++;
}
{
struct qrcodegen_Segment segs[] = {
{qrcodegen_Mode_KANJI, 255, NULL, 3315},
{qrcodegen_Mode_KANJI, 255, NULL, 3315},
{qrcodegen_Mode_KANJI, 255, NULL, 3315},
{qrcodegen_Mode_KANJI, 255, NULL, 3315},
{qrcodegen_Mode_KANJI, 255, NULL, 3315},
{qrcodegen_Mode_KANJI, 255, NULL, 3315},
{qrcodegen_Mode_KANJI, 255, NULL, 3315},
{qrcodegen_Mode_KANJI, 255, NULL, 3315},
{qrcodegen_Mode_KANJI, 255, NULL, 3315},
{qrcodegen_Mode_ALPHANUMERIC, 511, NULL, 2811},
};
assert(getTotalBits(segs, ARRAY_LENGTH(segs), 9) == 32767);
numTestCases++;
assert(getTotalBits(segs, ARRAY_LENGTH(segs), 26) == -1);
numTestCases++;
assert(getTotalBits(segs, ARRAY_LENGTH(segs), 40) == -1);
numTestCases++;
}
}
/*---- Main runner ----*/
int main(void) {
srand((unsigned int)time(NULL));
testAppendBitsToBuffer();
testAddEccAndInterleave();
testGetNumDataCodewords();
testGetNumRawDataModules();
testReedSolomonComputeDivisor();
testReedSolomonComputeRemainder();
testReedSolomonMultiply();
testInitializeFunctionModulesEtc();
testGetAlignmentPatternPositions();
testGetSetModule();
testGetSetModuleRandomly();
testIsAlphanumeric();
testIsNumeric();
testCalcSegmentBufferSize();
testCalcSegmentBitLength();
testMakeBytes();
testMakeNumeric();
testMakeAlphanumeric();
testMakeEci();
testGetTotalBits();
printf("All %d test cases passed\n", numTestCases);
return EXIT_SUCCESS;
}
================================================
FILE: c/qrcodegen.c
================================================
/*
* QR Code generator library (C)
*
* Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* 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 <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include "qrcodegen.h"
#ifndef QRCODEGEN_TEST
#define testable static // Keep functions private
#else
#define testable // Expose private functions
#endif
/*---- Forward declarations for private functions ----*/
// Regarding all public and private functions defined in this source file:
// - They require all pointer/array arguments to be not null unless the array length is zero.
// - They only read input scalar/array arguments, write to output pointer/array
// arguments, and return scalar values; they are "pure" functions.
// - They don't read mutable global variables or write to any global variables.
// - They don't perform I/O, read the clock, print to console, etc.
// - They allocate a small and constant amount of stack memory.
// - They don't allocate or free any memory on the heap.
// - They don't recurse or mutually recurse. All the code
// could be inlined into the top-level public functions.
// - They run in at most quadratic time with respect to input arguments.
// Most functions run in linear time, and some in constant time.
// There are no unbounded loops or non-obvious termination conditions.
// - They are completely thread-safe if the caller does not give the
// same writable buffer to concurrent calls to these functions.
testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen);
testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]);
testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
testable int getNumRawDataModules(int ver);
testable void reedSolomonComputeDivisor(int degree, uint8_t result[]);
testable void reedSolomonComputeRemainder(const uint8_t data[], int dataLen,
const uint8_t generator[], int degree, uint8_t result[]);
testable uint8_t reedSolomonMultiply(uint8_t x, uint8_t y);
testable void initializeFunctionModules(int version, uint8_t qrcode[]);
static void drawLightFunctionModules(uint8_t qrcode[], int version);
static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[]);
testable int getAlignmentPatternPositions(int version, uint8_t result[7]);
static void fillRectangle(int left, int top, int width, int height, uint8_t qrcode[]);
static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]);
static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qrcodegen_Mask mask);
static long getPenaltyScore(const uint8_t qrcode[]);
static int finderPenaltyCountPatterns(const int runHistory[7], int qrsize);
static int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int runHistory[7], int qrsize);
static void finderPenaltyAddHistory(int currentRunLength, int runHistory[7], int qrsize);
testable bool getModuleBounded(const uint8_t qrcode[], int x, int y);
testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isDark);
testable void setModuleUnbounded(uint8_t qrcode[], int x, int y, bool isDark);
static bool getBit(int x, int i);
testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars);
testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version);
static int numCharCountBits(enum qrcodegen_Mode mode, int version);
/*---- Private tables of constants ----*/
// The set of all legal characters in alphanumeric mode, where each character
// value maps to the index in the string. For checking text and encoding segments.
static const char *ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
// Sentinel value for use in only some functions.
#define LENGTH_OVERFLOW -1
// For generating error correction codes.
testable const int8_t ECC_CODEWORDS_PER_BLOCK[4][41] = {
// Version: (note that index 0 is for padding, and is set to an illegal value)
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
{-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}, // Low
{-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}, // Medium
{-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}, // Quartile
{-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}, // High
};
#define qrcodegen_REED_SOLOMON_DEGREE_MAX 30 // Based on the table above
// For generating error correction codes.
testable const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41] = {
// Version: (note that index 0 is for padding, and is set to an illegal value)
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
{-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}, // Low
{-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}, // Medium
{-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}, // Quartile
{-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}, // High
};
// For automatic mask pattern selection.
static const int PENALTY_N1 = 3;
static const int PENALTY_N2 = 3;
static const int PENALTY_N3 = 40;
static const int PENALTY_N4 = 10;
/*---- High-level QR Code encoding functions ----*/
// Public function - see documentation comment in header file.
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) {
size_t textLen = strlen(text);
if (textLen == 0)
return qrcodegen_encodeSegmentsAdvanced(NULL, 0, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode);
size_t bufLen = (size_t)qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion);
struct qrcodegen_Segment seg;
if (qrcodegen_isNumeric(text)) {
if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, textLen) > bufLen)
goto fail;
seg = qrcodegen_makeNumeric(text, tempBuffer);
} else if (qrcodegen_isAlphanumeric(text)) {
if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ALPHANUMERIC, textLen) > bufLen)
goto fail;
seg = qrcodegen_makeAlphanumeric(text, tempBuffer);
} else {
if (textLen > bufLen)
goto fail;
for (size_t i = 0; i < textLen; i++)
tempBuffer[i] = (uint8_t)text[i];
seg.mode = qrcodegen_Mode_BYTE;
seg.bitLength = calcSegmentBitLength(seg.mode, textLen);
if (seg.bitLength == LENGTH_OVERFLOW)
goto fail;
seg.numChars = (int)textLen;
seg.data = tempBuffer;
}
return qrcodegen_encodeSegmentsAdvanced(&seg, 1, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode);
fail:
qrcode[0] = 0; // Set size to invalid value for safety
return false;
}
// Public function - see documentation comment in header file.
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) {
struct qrcodegen_Segment seg;
seg.mode = qrcodegen_Mode_BYTE;
seg.bitLength = calcSegmentBitLength(seg.mode, dataLen);
if (seg.bitLength == LENGTH_OVERFLOW) {
qrcode[0] = 0; // Set size to invalid value for safety
return false;
}
seg.numChars = (int)dataLen;
seg.data = dataAndTemp;
return qrcodegen_encodeSegmentsAdvanced(&seg, 1, ecl, minVersion, maxVersion, mask, boostEcl, dataAndTemp, qrcode);
}
// Appends the given number of low-order bits of the given value to the given byte-based
// bit buffer, increasing the bit length. Requires 0 <= numBits <= 16 and val < 2^numBits.
testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen) {
assert(0 <= numBits && numBits <= 16 && (unsigned long)val >> numBits == 0);
for (int i = numBits - 1; i >= 0; i--, (*bitLen)++)
buffer[*bitLen >> 3] |= ((val >> i) & 1) << (7 - (*bitLen & 7));
}
/*---- Low-level QR Code encoding functions ----*/
// Public function - see documentation comment in header file.
bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len,
enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]) {
return qrcodegen_encodeSegmentsAdvanced(segs, len, ecl,
qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true, tempBuffer, qrcode);
}
// Public function - see documentation comment in header file.
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[]) {
assert(segs != NULL || len == 0);
assert(qrcodegen_VERSION_MIN <= minVersion && minVersion <= maxVersion && maxVersion <= qrcodegen_VERSION_MAX);
assert(0 <= (int)ecl && (int)ecl <= 3 && -1 <= (int)mask && (int)mask <= 7);
// Find the minimal version number to use
int version, dataUsedBits;
for (version = minVersion; ; version++) {
int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
dataUsedBits = getTotalBits(segs, len, version);
if (dataUsedBits != LENGTH_OVERFLOW && 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
qrcode[0] = 0; // Set size to invalid value for safety
return false;
}
}
assert(dataUsedBits != LENGTH_OVERFLOW);
// Increase the error correction level while the data still fits in the current version number
for (int i = (int)qrcodegen_Ecc_MEDIUM; i <= (int)qrcodegen_Ecc_HIGH; i++) { // From low to high
if (boostEcl && dataUsedBits <= getNumDataCodewords(version, (enum qrcodegen_Ecc)i) * 8)
ecl = (enum qrcodegen_Ecc)i;
}
// Concatenate all segments to create the data bit string
memset(qrcode, 0, (size_t)qrcodegen_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0]));
int bitLen = 0;
for (size_t i = 0; i < len; i++) {
const struct qrcodegen_Segment *seg = &segs[i];
appendBitsToBuffer((unsigned int)seg->mode, 4, qrcode, &bitLen);
appendBitsToBuffer((unsigned int)seg->numChars, numCharCountBits(seg->mode, version), qrcode, &bitLen);
for (int j = 0; j < seg->bitLength; j++) {
int bit = (seg->data[j >> 3] >> (7 - (j & 7))) & 1;
appendBitsToBuffer((unsigned int)bit, 1, qrcode, &bitLen);
}
}
assert(bitLen == dataUsedBits);
// Add terminator and pad up to a byte if applicable
int dataCapacityBits = getNumDataCodewords(version, ecl) * 8;
assert(bitLen <= dataCapacityBits);
int terminatorBits = dataCapacityBits - bitLen;
if (terminatorBits > 4)
terminatorBits = 4;
appendBitsToBuffer(0, terminatorBits, qrcode, &bitLen);
appendBitsToBuffer(0, (8 - bitLen % 8) % 8, qrcode, &bitLen);
assert(bitLen % 8 == 0);
// Pad with alternating bytes until data capacity is reached
for (uint8_t padByte = 0xEC; bitLen < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
appendBitsToBuffer(padByte, 8, qrcode, &bitLen);
// Compute ECC, draw modules
addEccAndInterleave(qrcode, version, ecl, tempBuffer);
initializeFunctionModules(version, qrcode);
drawCodewords(tempBuffer, getNumRawDataModules(version) / 8, qrcode);
drawLightFunctionModules(qrcode, version);
initializeFunctionModules(version, tempBuffer);
// Do masking
if (mask == qrcodegen_Mask_AUTO) { // Automatically choose best mask
long minPenalty = LONG_MAX;
for (int i = 0; i < 8; i++) {
enum qrcodegen_Mask msk = (enum qrcodegen_Mask)i;
applyMask(tempBuffer, qrcode, msk);
drawFormatBits(ecl, msk, qrcode);
long penalty = getPenaltyScore(qrcode);
if (penalty < minPenalty) {
mask = msk;
minPenalty = penalty;
}
applyMask(tempBuffer, qrcode, msk); // Undoes the mask due to XOR
}
}
assert(0 <= (int)mask && (int)mask <= 7);
applyMask(tempBuffer, qrcode, mask); // Apply the final choice of mask
drawFormatBits(ecl, mask, qrcode); // Overwrite old format bits
return true;
}
/*---- Error correction code generation functions ----*/
// Appends error correction bytes to each block of the given data array, then interleaves
// bytes from the blocks and stores them in the result array. data[0 : dataLen] contains
// the input data. data[dataLen : rawCodewords] is used as a temporary work area and will
// be clobbered by this function. The final answer is stored in result[0 : rawCodewords].
testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]) {
// Calculate parameter numbers
assert(0 <= (int)ecl && (int)ecl < 4 && qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX);
int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[(int)ecl][version];
int blockEccLen = ECC_CODEWORDS_PER_BLOCK [(int)ecl][version];
int rawCodewords = getNumRawDataModules(version) / 8;
int dataLen = getNumDataCodewords(version, ecl);
int numShortBlocks = numBlocks - rawCodewords % numBlocks;
int shortBlockDataLen = rawCodewords / numBlocks - blockEccLen;
// Split data into blocks, calculate ECC, and interleave
// (not concatenate) the bytes into a single sequence
uint8_t rsdiv[qrcodegen_REED_SOLOMON_DEGREE_MAX];
reedSolomonComputeDivisor(blockEccLen, rsdiv);
const uint8_t *dat = data;
for (int i = 0; i < numBlocks; i++) {
int datLen = shortBlockDataLen + (i < numShortBlocks ? 0 : 1);
uint8_t *ecc = &data[dataLen]; // Temporary storage
reedSolomonComputeRemainder(dat, datLen, rsdiv, blockEccLen, ecc);
for (int j = 0, k = i; j < datLen; j++, k += numBlocks) { // Copy data
if (j == shortBlockDataLen)
k -= numShortBlocks;
result[k] = dat[j];
}
for (int j = 0, k = dataLen + i; j < blockEccLen; j++, k += numBlocks) // Copy ECC
result[k] = ecc[j];
dat += datLen;
}
}
// 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].
testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl) {
int v = version, e = (int)ecl;
assert(0 <= e && e < 4);
return getNumRawDataModules(v) / 8
- ECC_CODEWORDS_PER_BLOCK [e][v]
* NUM_ERROR_CORRECTION_BLOCKS[e][v];
}
// Returns the number of data bits that can be stored in a QR Code of the given version number, after
// all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
// The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
testable int getNumRawDataModules(int ver) {
assert(qrcodegen_VERSION_MIN <= ver && ver <= qrcodegen_VERSION_MAX);
int result = (16 * ver + 128) * ver + 64;
if (ver >= 2) {
int numAlign = ver / 7 + 2;
result -= (25 * numAlign - 10) * numAlign - 55;
if (ver >= 7)
result -= 36;
}
assert(208 <= result && result <= 29648);
return result;
}
/*---- Reed-Solomon ECC generator functions ----*/
// Computes a Reed-Solomon ECC generator polynomial for the given degree, storing in result[0 : degree].
// This could be implemented as a lookup table over all possible parameter values, instead of as an algorithm.
testable void reedSolomonComputeDivisor(int degree, uint8_t result[]) {
assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX);
// Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1.
// For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.
memset(result, 0, (size_t)degree * sizeof(result[0]));
result[degree - 1] = 1; // Start off with the monomial x^0
// Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
// drop the highest monomial term which is always 1x^degree.
// Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
uint8_t root = 1;
for (int i = 0; i < degree; i++) {
// Multiply the current product by (x - r^i)
for (int j = 0; j < degree; j++) {
result[j] = reedSolomonMultiply(result[j], root);
if (j + 1 < degree)
result[j] ^= result[j + 1];
}
root = reedSolomonMultiply(root, 0x02);
}
}
// Computes the Reed-Solomon error correction codeword for the given data and divisor polynomials.
// The remainder when data[0 : dataLen] is divided by divisor[0 : degree] is stored in result[0 : degree].
// All polynomials are in big endian, and the generator has an implicit leading 1 term.
testable void reedSolomonComputeRemainder(const uint8_t data[], int dataLen,
const uint8_t generator[], int degree, uint8_t result[]) {
assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX);
memset(result, 0, (size_t)degree * sizeof(result[0]));
for (int i = 0; i < dataLen; i++) { // Polynomial division
uint8_t factor = data[i] ^ result[0];
memmove(&result[0], &result[1], (size_t)(degree - 1) * sizeof(result[0]));
result[degree - 1] = 0;
for (int j = 0; j < degree; j++)
result[j] ^= reedSolomonMultiply(generator[j], factor);
}
}
#undef qrcodegen_REED_SOLOMON_DEGREE_MAX
// Returns the product of the two given field elements modulo GF(2^8/0x11D).
// All inputs are valid. This could be implemented as a 256*256 lookup table.
testable uint8_t reedSolomonMultiply(uint8_t x, uint8_t y) {
// Russian peasant multiplication
uint8_t z = 0;
for (int i = 7; i >= 0; i--) {
z = (uint8_t)((z << 1) ^ ((z >> 7) * 0x11D));
z ^= ((y >> i) & 1) * x;
}
return z;
}
/*---- Drawing function modules ----*/
// Clears the given QR Code grid with light modules for the given
// version's size, then marks every function module as dark.
testable void initializeFunctionModules(int version, uint8_t qrcode[]) {
// Initialize QR Code
int qrsize = version * 4 + 17;
memset(qrcode, 0, (size_t)((qrsize * qrsize + 7) / 8 + 1) * sizeof(qrcode[0]));
qrcode[0] = (uint8_t)qrsize;
// Fill horizontal and vertical timing patterns
fillRectangle(6, 0, 1, qrsize, qrcode);
fillRectangle(0, 6, qrsize, 1, qrcode);
// Fill 3 finder patterns (all corners except bottom right) and format bits
fillRectangle(0, 0, 9, 9, qrcode);
fillRectangle(qrsize - 8, 0, 8, 9, qrcode);
fillRectangle(0, qrsize - 8, 9, 8, qrcode);
// Fill numerous alignment patterns
uint8_t alignPatPos[7];
int numAlign = getAlignmentPatternPositions(version, alignPatPos);
for (int i = 0; i < numAlign; i++) {
for (int j = 0; j < numAlign; j++) {
// Don't draw on the three finder corners
if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0)))
fillRectangle(alignPatPos[i] - 2, alignPatPos[j] - 2, 5, 5, qrcode);
}
}
// Fill version blocks
if (version >= 7) {
fillRectangle(qrsize - 11, 0, 3, 6, qrcode);
fillRectangle(0, qrsize - 11, 6, 3, qrcode);
}
}
// Draws light function modules and possibly some dark modules onto the given QR Code, without changing
// non-function modules. This does not draw the format bits. This requires all function modules to be previously
// marked dark (namely by initializeFunctionModules()), because this may skip redrawing dark function modules.
static void drawLightFunctionModules(uint8_t qrcode[], int version) {
// Draw horizontal and vertical timing patterns
int qrsize = qrcodegen_getSize(qrcode);
for (int i = 7; i < qrsize - 7; i += 2) {
setModuleBounded(qrcode, 6, i, false);
setModuleBounded(qrcode, i, 6, false);
}
// Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
for (int dy = -4; dy <= 4; dy++) {
for (int dx = -4; dx <= 4; dx++) {
int dist = abs(dx);
if (abs(dy) > dist)
dist = abs(dy);
if (dist == 2 || dist == 4) {
setModuleUnbounded(qrcode, 3 + dx, 3 + dy, false);
setModuleUnbounded(qrcode, qrsize - 4 + dx, 3 + dy, false);
setModuleUnbounded(qrcode, 3 + dx, qrsize - 4 + dy, false);
}
}
}
// Draw numerous alignment patterns
uint8_t alignPatPos[7];
int numAlign = getAlignmentPatternPositions(version, alignPatPos);
for (int i = 0; i < numAlign; i++) {
for (int j = 0; j < numAlign; j++) {
if ((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0))
continue; // Don't draw on the three finder corners
for (int dy = -1; dy <= 1; dy++) {
for (int dx = -1; dx <= 1; dx++)
setModuleBounded(qrcode, alignPatPos[i] + dx, alignPatPos[j] + dy, dx == 0 && dy == 0);
}
}
}
// Draw version blocks
if (version >= 7) {
// Calculate error correction code and pack bits
int rem = version; // version is uint6, in the range [7, 40]
for (int i = 0; i < 12; i++)
rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
long bits = (long)version << 12 | rem; // uint18
assert(bits >> 18 == 0);
// Draw two copies
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 3; j++) {
int k = qrsize - 11 + j;
setModuleBounded(qrcode, k, i, (bits & 1) != 0);
setModuleBounded(qrcode, i, k, (bits & 1) != 0);
bits >>= 1;
}
}
}
}
// Draws two copies of the format bits (with its own error correction code) based
// on the given mask and error correction level. This always draws all modules of
// the format bits, unlike drawLightFunctionModules() which might skip dark modules.
static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[]) {
// Calculate error correction code and pack bits
assert(0 <= (int)mask && (int)mask <= 7);
static const int table[] = {1, 0, 3, 2};
int data = table[(int)ecl] << 3 | (int)mask; // errCorrLvl is uint2, mask is uint3
int rem = data;
for (int i = 0; i < 10; i++)
rem = (rem << 1) ^ ((rem >> 9) * 0x537);
int bits = (data << 10 | rem) ^ 0x5412; // uint15
assert(bits >> 15 == 0);
// Draw first copy
for (int i = 0; i <= 5; i++)
setModuleBounded(qrcode, 8, i, getBit(bits, i));
setModuleBounded(qrcode, 8, 7, getBit(bits, 6));
setModuleBounded(qrcode, 8, 8, getBit(bits, 7));
setModuleBounded(qrcode, 7, 8, getBit(bits, 8));
for (int i = 9; i < 15; i++)
setModuleBounded(qrcode, 14 - i, 8, getBit(bits, i));
// Draw second copy
int qrsize = qrcodegen_getSize(qrcode);
for (int i = 0; i < 8; i++)
setModuleBounded(qrcode, qrsize - 1 - i, 8, getBit(bits, i));
for (int i = 8; i < 15; i++)
setModuleBounded(qrcode, 8, qrsize - 15 + i, getBit(bits, i));
setModuleBounded(qrcode, 8, qrsize - 8, true); // Always dark
}
// Calculates and stores an ascending list of positions of alignment patterns
// for this version number, returning the length of the list (in the range [0,7]).
// Each position is in the range [0,177), and are used on both the x and y axes.
// This could be implemented as lookup table of 40 variable-length lists of unsigned bytes.
testable int getAlignmentPatternPositions(int version, uint8_t result[7]) {
if (version == 1)
return 0;
int numAlign = version / 7 + 2;
int step = (version * 8 + numAlign * 3 + 5) / (numAlign * 4 - 4) * 2;
for (int i = numAlign - 1, pos = version * 4 + 10; i >= 1; i--, pos -= step)
result[i] = (uint8_t)pos;
result[0] = 6;
return numAlign;
}
// Sets every module in the range [left : left + width] * [top : top + height] to dark.
static void fillRectangle(int left, int top, int width, int height, uint8_t qrcode[]) {
for (int dy = 0; dy < height; dy++) {
for (int dx = 0; dx < width; dx++)
setModuleBounded(qrcode, left + dx, top + dy, true);
}
}
/*---- Drawing data modules and masking ----*/
// Draws the raw codewords (including data and ECC) onto the given QR Code. This requires the initial state of
// the QR Code to be dark at function modules and light at codeword modules (including unused remainder bits).
static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]) {
int qrsize = qrcodegen_getSize(qrcode);
int i = 0; // Bit index into the data
// Do the funny zigzag scan
for (int right = qrsize - 1; right >= 1; right -= 2) { // Index of right column in each column pair
if (right == 6)
right = 5;
for (int vert = 0; vert < qrsize; vert++) { // Vertical counter
for (int j = 0; j < 2; j++) {
int x = right - j; // Actual x coordinate
bool upward = ((right + 1) & 2) == 0;
int y = upward ? qrsize - 1 - vert : vert; // Actual y coordinate
if (!getModuleBounded(qrcode, x, y) && i < dataLen * 8) {
bool dark = getBit(data[i >> 3], 7 - (i & 7));
setModuleBounded(qrcode, x, y, dark);
i++;
}
// If this QR Code has any remainder bits (0 to 7), they were assigned as
// 0/false/light by the constructor and are left unchanged by this method
}
}
}
assert(i == dataLen * 8);
}
// XORs the codeword modules in this QR Code with the given mask pattern
// and given pattern of function modules. The codeword bits must be drawn
// before masking. Due to the arithmetic of XOR, calling applyMask() with
// the same mask value a second time will undo the mask. A final well-formed
// QR Code needs exactly one (not zero, two, etc.) mask applied.
static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qrcodegen_Mask mask) {
assert(0 <= (int)mask && (int)mask <= 7); // Disallows qrcodegen_Mask_AUTO
int qrsize = qrcodegen_getSize(qrcode);
for (int y = 0; y < qrsize; y++) {
for (int x = 0; x < qrsize; x++) {
if (getModuleBounded(functionModules, x, y))
continue;
bool invert;
switch ((int)mask) {
case 0: invert = (x + y) % 2 == 0; break;
case 1: invert = y % 2 == 0; break;
case 2: invert = x % 3 == 0; break;
case 3: invert = (x + y) % 3 == 0; break;
case 4: invert = (x / 3 + y / 2) % 2 == 0; break;
case 5: invert = x * y % 2 + x * y % 3 == 0; break;
case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
default: assert(false); return;
}
bool val = getModuleBounded(qrcode, x, y);
setModuleBounded(qrcode, x, y, val ^ invert);
}
}
}
// Calculates and returns the penalty score based on state of the given QR Code's current modules.
// This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
static long getPenaltyScore(const uint8_t qrcode[]) {
int qrsize = qrcodegen_getSize(qrcode);
long result = 0;
// Adjacent modules in row having same color, and finder-like patterns
for (int y = 0; y < qrsize; y++) {
bool runColor = false;
int runX = 0;
int runHistory[7] = {0};
for (int x = 0; x < qrsize; x++) {
if (getModuleBounded(qrcode, x, y) == runColor) {
runX++;
if (runX == 5)
result += PENALTY_N1;
else if (runX > 5)
result++;
} else {
finderPenaltyAddHistory(runX, runHistory, qrsize);
if (!runColor)
result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3;
runColor = getModuleBounded(qrcode, x, y);
runX = 1;
}
}
result += finderPenaltyTerminateAndCount(runColor, runX, runHistory, qrsize) * PENALTY_N3;
}
// Adjacent modules in column having same color, and finder-like patterns
for (int x = 0; x < qrsize; x++) {
bool runColor = false;
int runY = 0;
int runHistory[7] = {0};
for (int y = 0; y < qrsize; y++) {
if (getModuleBounded(qrcode, x, y) == runColor) {
runY++;
if (runY == 5)
result += PENALTY_N1;
else if (runY > 5)
result++;
} else {
finderPenaltyAddHistory(runY, runHistory, qrsize);
if (!runColor)
result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3;
runColor = getModuleBounded(qrcode, x, y);
runY = 1;
}
}
result += finderPenaltyTerminateAndCount(runColor, runY, runHistory, qrsize) * PENALTY_N3;
}
// 2*2 blocks of modules having same color
for (int y = 0; y < qrsize - 1; y++) {
for (int x = 0; x < qrsize - 1; x++) {
bool color = getModuleBounded(qrcode, x, y);
if ( color == getModuleBounded(qrcode, x + 1, y) &&
color == getModuleBounded(qrcode, x, y + 1) &&
color == getModuleBounded(qrcode, x + 1, y + 1))
result += PENALTY_N2;
}
}
// Balance of dark and light modules
int dark = 0;
for (int y = 0; y < qrsize; y++) {
for (int x = 0; x < qrsize; x++) {
if (getModuleBounded(qrcode, x, y))
dark++;
}
}
int total = qrsize * qrsize; // Note that size is odd, so dark/total != 1/2
// Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)%
int k = (int)((labs(dark * 20L - total * 10L) + total - 1) / total) - 1;
assert(0 <= k && k <= 9);
result += k * PENALTY_N4;
assert(0 <= result && result <= 2568888L); // Non-tight upper bound based on default values of PENALTY_N1, ..., N4
return result;
}
// Can only be called immediately after a light run is added, and
// returns either 0, 1, or 2. A helper function for getPenaltyScore().
static int finderPenaltyCountPatterns(const int runHistory[7], int qrsize) {
int n = runHistory[1];
assert(n <= qrsize * 3); (void)qrsize;
bool core = n > 0 && runHistory[2] == n && runHistory[3] == n * 3 && runHistory[4] == n && runHistory[5] == n;
// The maximum QR Code size is 177, hence the dark run length n <= 177.
// Arithmetic is promoted to int, so n*4 will not overflow.
return (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0)
+ (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0);
}
// Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore().
static int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int runHistory[7], int qrsize) {
if (currentRunColor) { // Terminate dark run
finderPenaltyAddHistory(currentRunLength, runHistory, qrsize);
currentRunLength = 0;
}
currentRunLength += qrsize; // Add light border to final run
finderPenaltyAddHistory(currentRunLength, runHistory, qrsize);
return finderPenaltyCountPatterns(runHistory, qrsize);
}
// Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore().
static void finderPenaltyAddHistory(int currentRunLength, int runHistory[7], int qrsize) {
if (runHistory[0] == 0)
currentRunLength += qrsize; // Add light border to initial run
memmove(&runHistory[1], &runHistory[0], 6 * sizeof(runHistory[0]));
runHistory[0] = currentRunLength;
}
/*---- Basic QR Code information ----*/
// Public function - see documentation comment in header file.
int qrcodegen_getSize(const uint8_t qrcode[]) {
assert(qrcode != NULL);
int result = qrcode[0];
assert((qrcodegen_VERSION_MIN * 4 + 17) <= result
&& result <= (qrcodegen_VERSION_MAX * 4 + 17));
return result;
}
// Public function - see documentation comment in header file.
bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y) {
assert(qrcode != NULL);
int qrsize = qrcode[0];
return (0 <= x && x < qrsize && 0 <= y && y < qrsize) && getModuleBounded(qrcode, x, y);
}
// Returns the color of the module at the given coordinates, which must be in bounds.
testable bool getModuleBounded(const uint8_t qrcode[], int x, int y) {
int qrsize = qrcode[0];
assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize);
int index = y * qrsize + x;
return getBit(qrcode[(index >> 3) + 1], index & 7);
}
// Sets the color of the module at the given coordinates, which must be in bounds.
testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isDark) {
int qrsize = qrcode[0];
assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize);
int index = y * qrsize + x;
int bitIndex = index & 7;
int byteIndex = (index >> 3) + 1;
if (isDark)
qrcode[byteIndex] |= 1 << bitIndex;
else
qrcode[byteIndex] &= (1 << bitIndex) ^ 0xFF;
}
// Sets the color of the module at the given coordinates, doing nothing if out of bounds.
testable void setModuleUnbounded(uint8_t qrcode[], int x, int y, bool isDark) {
int qrsize = qrcode[0];
if (0 <= x && x < qrsize && 0 <= y && y < qrsize)
setModuleBounded(qrcode, x, y, isDark);
}
// Returns true iff the i'th bit of x is set to 1. Requires x >= 0 and 0 <= i <= 14.
static bool getBit(int x, int i) {
return ((x >> i) & 1) != 0;
}
/*---- Segment handling ----*/
// Public function - see documentation comment in header file.
bool qrcodegen_isNumeric(const char *text) {
assert(text != NULL);
for (; *text != '\0'; text++) {
if (*text < '0' || *text > '9')
return false;
}
return true;
}
// Public function - see documentation comment in header file.
bool qrcodegen_isAlphanumeric(const char *text) {
assert(text != NULL);
for (; *text != '\0'; text++) {
if (strchr(ALPHANUMERIC_CHARSET, *text) == NULL)
return false;
}
return true;
}
// Public function - see documentation comment in header file.
size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars) {
int temp = calcSegmentBitLength(mode, numChars);
if (temp == LENGTH_OVERFLOW)
return SIZE_MAX;
assert(0 <= temp && temp <= INT16_MAX);
return ((size_t)temp + 7) / 8;
}
// Returns the number of data bits needed to represent a segment
// containing the given number of characters using the given mode. Notes:
// - Returns LENGTH_OVERFLOW on failure, i.e. numChars > INT16_MAX
// or the number of needed bits exceeds INT16_MAX (i.e. 32767).
// - Otherwise, all valid results are in the range [0, INT16_MAX].
// - For byte mode, numChars measures the number of bytes, not Unicode code points.
// - For ECI mode, numChars must be 0, and the worst-case number of bits is returned.
// An actual ECI segment can have shorter data. For non-ECI modes, the result is exact.
testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars) {
// All calculations are designed to avoid overflow on all platforms
if (numChars > (unsigned int)INT16_MAX)
return LENGTH_OVERFLOW;
long result = (long)numChars;
if (mode == qrcodegen_Mode_NUMERIC)
result = (result * 10 + 2) / 3; // ceil(10/3 * n)
else if (mode == qrcodegen_Mode_ALPHANUMERIC)
result = (result * 11 + 1) / 2; // ceil(11/2 * n)
else if (mode == qrcodegen_Mode_BYTE)
result *= 8;
else if (mode == qrcodegen_Mode_KANJI)
result *= 13;
else if (mode == qrcodegen_Mode_ECI && numChars == 0)
result = 3 * 8;
else { // Invalid argument
assert(false);
return LENGTH_OVERFLOW;
}
assert(result >= 0);
if (result > INT16_MAX)
return LENGTH_OVERFLOW;
return (int)result;
}
// Public function - see documentation comment in header file.
struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]) {
assert(data != NULL || len == 0);
struct qrcodegen_Segment result;
result.mode = qrcodegen_Mode_BYTE;
result.bitLength = calcSegmentBitLength(result.mode, len);
assert(result.bitLength != LENGTH_OVERFLOW);
result.numChars = (int)len;
if (len > 0)
memcpy(buf, data, len * sizeof(buf[0]));
result.data = buf;
return result;
}
// Public function - see documentation comment in header file.
struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]) {
assert(digits != NULL);
struct qrcodegen_Segment result;
size_t len = strlen(digits);
result.mode = qrcodegen_Mode_NUMERIC;
int bitLen = calcSegmentBitLength(result.mode, len);
assert(bitLen != LENGTH_OVERFLOW);
result.numChars = (int)len;
if (bitLen > 0)
memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0]));
result.bitLength = 0;
unsigned int accumData = 0;
int accumCount = 0;
for (; *digits != '\0'; digits++) {
char c = *digits;
assert('0' <= c && c <= '9');
accumData = accumData * 10 + (unsigned int)(c - '0');
accumCount++;
if (accumCount == 3) {
appendBitsToBuffer(accumData, 10, buf, &result.bitLength);
accumData = 0;
accumCount = 0;
}
}
if (accumCount > 0) // 1 or 2 digits remaining
appendBitsToBuffer(accumData, accumCount * 3 + 1, buf, &result.bitLength);
assert(result.bitLength == bitLen);
result.data = buf;
return result;
}
// Public function - see documentation comment in header file.
struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]) {
assert(text != NULL);
struct qrcodegen_Segment result;
size_t len = strlen(text);
result.mode = qrcodegen_Mode_ALPHANUMERIC;
int bitLen = calcSegmentBitLength(result.mode, len);
assert(bitLen != LENGTH_OVERFLOW);
result.numChars = (int)len;
if (bitLen > 0)
memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0]));
result.bitLength = 0;
unsigned int accumData = 0;
int accumCount = 0;
for (; *text != '\0'; text++) {
const char *temp = strchr(ALPHANUMERIC_CHARSET, *text);
assert(temp != NULL);
accumData = accumData * 45 + (unsigned int)(temp - ALPHANUMERIC_CHARSET);
accumCount++;
if (accumCount == 2) {
appendBitsToBuffer(accumData, 11, buf, &result.bitLength);
accumData = 0;
accumCount = 0;
}
}
if (accumCount > 0) // 1 character remaining
appendBitsToBuffer(accumData, 6, buf, &result.bitLength);
assert(result.bitLength == bitLen);
result.data = buf;
return result;
}
// Public function - see documentation comment in header file.
struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]) {
struct qrcodegen_Segment result;
result.mode = qrcodegen_Mode_ECI;
result.numChars = 0;
result.bitLength = 0;
if (assignVal < 0)
assert(false);
else if (assignVal < (1 << 7)) {
memset(buf, 0, 1 * sizeof(buf[0]));
appendBitsToBuffer((unsigned int)assignVal, 8, buf, &result.bitLength);
} else if (assignVal < (1 << 14)) {
memset(buf, 0, 2 * sizeof(buf[0]));
appendBitsToBuffer(2, 2, buf, &result.bitLength);
appendBitsToBuffer((unsigned int)assignVal, 14, buf, &result.bitLength);
} else if (assignVal < 1000000L) {
memset(buf, 0, 3 * sizeof(buf[0]));
appendBitsToBuffer(6, 3, buf, &result.bitLength);
appendBitsToBuffer((unsigned int)(assignVal >> 10), 11, buf, &result.bitLength);
appendBitsToBuffer((unsigned int)(assignVal & 0x3FF), 10, buf, &result.bitLength);
} else
assert(false);
result.data = buf;
return result;
}
// Calculates the number of bits needed to encode the given segments at the given version.
// Returns a non-negative number if successful. Otherwise returns LENGTH_OVERFLOW if a segment
// has too many characters to fit its length field, or the total bits exceeds INT16_MAX.
testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version) {
assert(segs != NULL || len == 0);
long result = 0;
for (size_t i = 0; i < len; i++) {
int numChars = segs[i].numChars;
int bitLength = segs[i].bitLength;
assert(0 <= numChars && numChars <= INT16_MAX);
assert(0 <= bitLength && bitLength <= INT16_MAX);
int ccbits = numCharCountBits(segs[i].mode, version);
assert(0 <= ccbits && ccbits <= 16);
if (numChars >= (1L << ccbits))
return LENGTH_OVERFLOW; // The segment's length doesn't fit the field's bit width
result += 4L + ccbits + bitLength;
if (result > INT16_MAX)
return LENGTH_OVERFLOW; // The sum might overflow an int type
}
assert(0 <= result && result <= INT16_MAX);
return (int)result;
}
// Returns the bit width of the character count field for a segment in the given mode
// in a QR Code at the given version number. The result is in the range [0, 16].
static int numCharCountBits(enum qrcodegen_Mode mode, int version) {
assert(qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX);
int i = (version + 7) / 17;
switch (mode) {
case qrcodegen_Mode_NUMERIC : { static const int temp[] = {10, 12, 14}; return temp[i]; }
case qrcodegen_Mode_ALPHANUMERIC: { static const int temp[] = { 9, 11, 13}; return temp[i]; }
case qrcodegen_Mode_BYTE : { static const int temp[] = { 8, 16, 16}; return temp[i]; }
case qrcodegen_Mode_KANJI : { static const int temp[] = { 8, 10, 12}; return temp[i]; }
case qrcodegen_Mode_ECI : return 0;
default: assert(false); return -1; // Dummy value
}
}
#undef LENGTH_OVERFLOW
================================================
FILE: c/qrcodegen.h
================================================
/*
* QR Code generator library (C)
*
* Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* 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.
*/
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* This library creates QR Code symbols, which is a type of two-dimension barcode.
* Invented by Denso Wave and described in the ISO/IEC 18004 standard.
* A QR Code structure is an immutable square grid of dark and light cells.
* The library provides functions to create a QR Code from text or binary data.
* The library covers the QR Code Model 2 specification, supporting all versions (sizes)
* from 1 to 40, all 4 error correction levels, and 4 character encoding modes.
*
* Ways to create a QR Code object:
* - High level: Take the payload data and call qrcodegen_encodeText() or qrcodegen_encodeBinary().
* - Low level: Custom-make the list of segments and call
* qrcodegen_encodeSegments() or qrcodegen_encodeSegmentsAdvanced().
* (Note that all ways require supplying the desired error correction level and various byte buffers.)
*/
/*---- Enum and struct types----*/
/*
* The error correction level in a QR Code symbol.
*/
enum qrcodegen_Ecc {
// Must be declared in ascending order of error protection
// so that an internal qrcodegen function works properly
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
};
/*
* The mask pattern used in a QR Code symbol.
*/
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,
};
/*
* Describes how a segment's data bits are interpreted.
*/
enum qrcodegen_Mode {
qrcodegen_Mode_NUMERIC = 0x1,
qrcodegen_Mode_ALPHANUMERIC = 0x2,
qrcodegen_Mode_BYTE = 0x4,
qrcodegen_Mode_KANJI = 0x8,
qrcodegen_Mode_ECI = 0x7,
};
/*
* A segment of character/binary/control data in a QR Code symbol.
* The mid-level way to create a segment is to take the payload data
* and call a factory function such as qrcodegen_makeNumeric().
* The low-level way to create a segment is to custom-make the bit buffer
* and initialize a qrcodegen_Segment struct with appropriate values.
* Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.
* Any segment longer than this is meaningless for the purpose of generating QR Codes.
* Moreover, the maximum allowed bit length is 32767 because
* the largest QR Code (version 40) has 31329 modules.
*/
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;
};
/*---- Macro constants and functions ----*/
#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
// Calculates the number of bytes needed to store any QR Code up to and including the given version number,
// as a compile-time constant. For example, 'uint8_t buffer[qrcodegen_BUFFER_LEN_FOR_VERSION(25)];'
// can store any single QR Code from version 1 to 25 (inclusive). The result fits in an int (or int16).
// Requires qrcodegen_VERSION_MIN <= n <= qrcodegen_VERSION_MAX.
#define qrcodegen_BUFFER_LEN_FOR_VERSION(n) ((((n) * 4 + 17) * ((n) * 4 + 17) + 7) / 8 + 1)
// The worst-case number of bytes needed to store one QR Code, up to and including
// version 40. This value equals 3918, which is just under 4 kilobytes.
// Use this more convenient value to avoid calculating tighter memory bounds for buffers.
#define qrcodegen_BUFFER_LEN_MAX qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX)
/*---- Functions (high level) to generate QR Codes ----*/
/*
* Encodes the given text string to a QR Code, returning true if successful.
* If the data is too long to fit in any version in the given range
* at the given ECC level, then false is returned.
*
* The input text must be encoded in UTF-8 and contain no NULs.
* Requires 1 <= minVersion <= maxVersion <= 40.
*
* The smallest possible QR Code version within the given range is automatically
* chosen for the output. Iff boostEcl is true, then the ECC level of the result
* may be higher than the ecl argument if it can be done without increasing the
* version. The mask is either between qrcodegen_Mask_0 to 7 to force that mask, or
* qrcodegen_Mask_AUTO to automatically choose an appropriate mask (which may be slow).
*
* About the arrays, letting len = qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion):
* - Before calling the function:
* - The array ranges tempBuffer[0 : len] and qrcode[0 : len] must allow
* reading and writing; hence each array must have a length of at least len.
* - The two ranges must not overlap (aliasing).
* - The initial state of both ranges can be uninitialized
* because the function always writes before reading.
* - After the function returns:
* - Both ranges have no guarantee on which elements are initialized and what values are stored.
* - tempBuffer contains no useful data and should be treated as entirely uninitialized.
* - If successful, qrcode can be passed into qrcodegen_getSize() and qrcodegen_getModule().
*
* If successful, the resulting QR Code may use numeric,
* alphanumeric, or byte mode to encode the text.
*
* In the most optimistic case, a QR Code at version 40 with low ECC
* can hold any UTF-8 string up to 2953 bytes, or any alphanumeric string
* up to 4296 characters, or any digit string up to 7089 characters.
* These numbers represent the hard upper limit of the QR Code standard.
*
* Please consult the QR Code specification for information on
* data capacities per version, ECC level, and text encoding mode.
*/
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);
/*
* Encodes the given binary data to a QR Code, returning true if successful.
* If the data is too long to fit in any version in the given range
* at the given ECC level, then false is returned.
*
* Requires 1 <= minVersion <= maxVersion <= 40.
*
* The smallest possible QR Code version within the given range is automatically
* chosen for the output. Iff boostEcl is true, then the ECC level of the result
* may be higher than the ecl argument if it can be done without increasing the
* version. The mask is either between qrcodegen_Mask_0 to 7 to force that mask, or
* qrcodegen_Mask_AUTO to automatically choose an appropriate mask (which may be slow).
*
* About the arrays, letting len = qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion):
* - Before calling the function:
* - The array ranges dataAndTemp[0 : len] and qrcode[0 : len] must allow
* reading and writing; hence each array must have a length of at least len.
* - The two ranges must not overlap (aliasing).
* - The input array range dataAndTemp[0 : dataLen] should normally be
* valid UTF-8 text, but is not required by the QR Code standard.
* - The initial state of dataAndTemp[dataLen : len] and qrcode[0 : len]
* can be uninitialized because the function always writes before reading.
* - After the function returns:
* - Both ranges have no guarantee on which elements are initialized and what values are stored.
* - dataAndTemp contains no useful data and should be treated as entirely uninitialized.
* - If successful, qrcode can be passed into qrcodegen_getSize() and qrcodegen_getModule().
*
* If successful, the resulting QR Code will use byte mode to encode the data.
*
* In the most optimistic case, a QR Code at version 40 with low ECC can hold any byte
* sequence up to length 2953. This is the hard upper limit of the QR Code standard.
*
* Please consult the QR Code specification for information on
* data capacities per version, ECC level, and text encoding mode.
*/
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);
/*---- Functions (low level) to generate QR Codes ----*/
/*
* Encodes the given segments to a QR Code, returning true if successful.
* If the data is too long to fit in any version at the given ECC level,
* then false is returned.
*
* The smallest possible QR Code version is automatically chosen for
* the output. The ECC level of the result may be higher than the
* ecl argument if it can be done without increasing the version.
*
* About the byte arrays, letting len = qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX):
* - Before calling the function:
* - The array ranges tempBuffer[0 : len] and qrcode[0 : len] must allow
* reading and writing; hence each array must have a length of at least len.
* - The two ranges must not overlap (aliasing).
* - The initial state of both ranges can be uninitialized
* because the function always writes before reading.
* - The input array segs can contain segments whose data buffers overlap with tempBuffer.
* - After the function returns:
* - Both ranges have no guarantee on which elements are initialized and what values are stored.
* - tempBuffer contains no useful data and should be treated as entirely uninitialized.
* - Any segment whose data buffer overlaps with tempBuffer[0 : len]
* must be treated as having invalid values in that array.
* - If successful, qrcode can be passed into qrcodegen_getSize() and qrcodegen_getModule().
*
* Please consult the QR Code specification for information on
* data capacities per version, ECC level, and text encoding mode.
*
* This function allows the user to create a custom sequence of segments that switches
* between modes (such as alphanumeric and byte) to encode text in less space.
* This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary().
*/
bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len,
enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]);
/*
* Encodes the given segments to a QR Code, returning true if successful.
* If the data is too long to fit in any version in the given range
* at the given ECC level, then false is returned.
*
* Requires 1 <= minVersion <= maxVersion <= 40.
*
* The smallest possible QR Code version within the given range is automatically
* chosen for the output. Iff boostEcl is true, then the ECC level of the result
* may be higher than the ecl argument if it can be done without increasing the
* version. The mask is either between qrcodegen_Mask_0 to 7 to force that mask, or
* qrcodegen_Mask_AUTO to automatically choose an appropriate mask (which may be slow).
*
* About the byte arrays, letting len = qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX):
* - Before calling the function:
* - The array ranges tempBuffer[0 : len] and qrcode[0 : len] must allow
* reading and writing; hence each array must have a length of at least len.
* - The two ranges must not overlap (aliasing).
* - The initial state of both ranges can be uninitialized
* because the function always writes before reading.
* - The input array segs can contain segments whose data buffers overlap with tempBuffer.
* - After the function returns:
* - Both ranges have no guarantee on which elements are initialized and what values are stored.
* - tempBuffer contains no useful data and should be treated as entirely uninitialized.
* - Any segment whose data buffer overlaps with tempBuffer[0 : len]
* must be treated as having invalid values in that array.
* - If successful, qrcode can be passed into qrcodegen_getSize() and qrcodegen_getModule().
*
* Please consult the QR Code specification for information on
* data capacities per version, ECC level, and text encoding mode.
*
* This function allows the user to create a custom sequence of segments that switches
* between modes (such as alphanumeric and byte) to encode text in less space.
* This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary().
*/
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[]);
/*
* Tests whether the given string can be encoded as a segment in numeric mode.
* A string is encodable iff each character is in the range 0 to 9.
*/
bool qrcodegen_isNumeric(const char *text);
/*
* Tests whether the given string can be encoded as a segment in alphanumeric mode.
* A string is encodable iff each character is in the following set: 0 to 9, A to Z
* (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
*/
bool qrcodegen_isAlphanumeric(const char *text);
/*
* Returns the number of bytes (uint8_t) needed for the data buffer of a segment
* containing the given number of characters using the given mode. Notes:
* - Returns SIZE_MAX on failure, i.e. numChars > INT16_MAX or the internal
* calculation of the number of needed bits exceeds INT16_MAX (i.e. 32767).
* - Otherwise, all valid results are in the range [0, ceil(INT16_MAX / 8)], i.e. at most 4096.
* - It is okay for the user to allocate more bytes for the buffer than needed.
* - For byte mode, numChars measures the number of bytes, not Unicode code points.
* - For ECI mode, numChars must be 0, and the worst-case number of bytes is returned.
* An actual ECI segment can have shorter data. For non-ECI modes, the result is exact.
*/
size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars);
/*
* Returns a segment representing the given binary data encoded in
* byte mode. All input byte arrays are acceptable. Any text string
* can be converted to UTF-8 bytes and encoded as a byte mode segment.
*/
struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]);
/*
* Returns a segment representing the given string of decimal digits encoded in numeric mode.
*/
struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]);
/*
* Returns a segment representing the given text string encoded in alphanumeric mode.
* The characters allowed are: 0 to 9, A to Z (uppercase only), space,
* dollar, percent, asterisk, plus, hyphen, period, slash, colon.
*/
struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]);
/*
* Returns a segment representing an Extended Channel Interpretation
* (ECI) designator with the given assignment value.
*/
struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]);
/*---- Functions to extract raw data from QR Codes ----*/
/*
* Returns the side length of the given QR Code, assuming that encoding succeeded.
* The result is in the range [21, 177]. Note that the length of the array buffer
* is related to the side length - every 'uint8_t qrcode[]' must have length at least
* qrcodegen_BUFFER_LEN_FOR_VERSION(version), which equals ceil(size^2 / 8 + 1).
*/
int qrcodegen_getSize(const uint8_t qrcode[]);
/*
* Returns the color of the module (pixel) at the given coordinates, which is false
* for light or true for dark. The top left corner has the coordinates (x=0, y=0).
* If the given coordinates are out of bounds, then false (light) is returned.
*/
bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y);
#ifdef __cplusplus
}
#endif
================================================
FILE: cpp/Makefile
================================================
#
# Makefile for QR Code generator (C++)
#
# Copyright (c) Project Nayuki. (MIT License)
# https://www.nayuki.io/page/qr-code-generator-library
#
# 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.
#
# ---- Configuration options ----
# External/implicit variables:
# - CXX: The C++ compiler, such as g++ or clang++.
# - CXXFLAGS: Any extra user-specified compiler flags (can be blank).
# Recommended compiler flags:
CXXFLAGS += -std=c++11 -O
# Extra flags for diagnostics:
# CXXFLAGS += -g -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -fsanitize=undefined,address
# ---- Controlling make ----
# Clear default suffix rules
.SUFFIXES:
# Don't delete object files
.SECONDARY:
# Stuff concerning goals
.DEFAULT_GOAL = all
.PHONY: all clean
# ---- Targets to build ----
LIB = qrcodegencpp
LIBFILE = lib$(LIB).a
LIBOBJ = qrcodegen.o
MAINS = QrCodeGeneratorDemo
# Build all binaries
all: $(LIBFILE) $(MAINS)
# Delete build output
clean:
rm -f -- $(LIBOBJ) $(LIBFILE) $(MAINS:=.o) $(MAINS)
rm -rf .deps
# Executable files
%: %.o $(LIBFILE)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $< -L . -l $(LIB)
# The library
$(LIBFILE): $(LIBOBJ)
$(AR) -crs $@ -- $^
# Object files
%.o: %.cpp .deps/timestamp
$(CXX) $(CXXFLAGS) -c -o $@ -MMD -MF .deps/$*.d $<
# Have a place to store header dependencies automatically generated by compiler
.deps/timestamp:
mkdir -p .deps
touch .deps/timestamp
# Make use of said dependencies if available
-include .deps/*.d
================================================
FILE: cpp/QrCodeGeneratorDemo.cpp
================================================
/*
* QR Code generator demo (C++)
*
* Run this command-line program with no arguments. The program computes a bunch of demonstration
* QR Codes and prints them to the console. Also, the SVG code for one QR Code is printed as a sample.
*
* Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* 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 <climits>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include "qrcodegen.hpp"
using std::uint8_t;
using qrcodegen::QrCode;
using qrcodegen::QrSegment;
// Function prototypes
static void doBasicDemo();
static void doVarietyDemo();
static void doSegmentDemo();
static void doMaskDemo();
static std::string toSvgString(const QrCode &qr, int border);
static void printQr(const QrCode &qr);
// The main application program.
int main() {
doBasicDemo();
doVarietyDemo();
doSegmentDemo();
doMaskDemo();
return EXIT_SUCCESS;
}
/*---- Demo suite ----*/
// Creates a single QR Code, then prints it to the console.
static void doBasicDemo() {
const char *text = "Hello, world!"; // User-supplied text
const QrCode::Ecc errCorLvl = QrCode::Ecc::LOW; // Error correction level
// Make and print the QR Code symbol
const QrCode qr = QrCode::encodeText(text, errCorLvl);
printQr(qr);
std::cout << toSvgString(qr, 4) << std::endl;
}
// Creates a variety of QR Codes that exercise different features of the library, and prints each one to the console.
static void doVarietyDemo() {
// Numeric mode encoding (3.33 bits per digit)
const QrCode qr0 = QrCode::encodeText("314159265358979323846264338327950288419716939937510", QrCode::Ecc::MEDIUM);
printQr(qr0);
// Alphanumeric mode encoding (5.5 bits per character)
const QrCode qr1 = QrCode::encodeText("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", QrCode::Ecc::HIGH);
printQr(qr1);
// Unicode text as UTF-8
const QrCode qr2 = QrCode::encodeText("\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1wa\xE3\x80\x81"
"\xE4\xB8\x96\xE7\x95\x8C\xEF\xBC\x81\x20\xCE\xB1\xCE\xB2\xCE\xB3\xCE\xB4", QrCode::Ecc::QUARTILE);
printQr(qr2);
// Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland)
const QrCode qr3 = QrCode::encodeText(
"Alice was beginning to get very tired of sitting by her sister on the bank, "
"and of having nothing to do: once or twice she had peeped into the book her sister was reading, "
"but it had no pictures or conversations in it, 'and what is the use of a book,' thought Alice "
"'without pictures or conversations?' So she was considering in her own mind (as well as she could, "
"for the hot day made her feel very sleepy and stupid), whether the pleasure of making a "
"daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly "
"a White Rabbit with pink eyes ran close by her.", QrCode::Ecc::HIGH);
printQr(qr3);
}
// Creates QR Codes with manually specified segments for better compactness.
static void doSegmentDemo() {
// Illustration "silver"
const char *silver0 = "THE SQUARE ROOT OF 2 IS 1.";
const char *silver1 = "41421356237309504880168872420969807856967187537694807317667973799";
const QrCode qr0 = QrCode::encodeText(
(std::string(silver0) + silver1).c_str(),
QrCode::Ecc::LOW);
printQr(qr0);
const QrCode qr1 = QrCode::encodeSegments(
{QrSegment::makeAlphanumeric(silver0), QrSegment::makeNumeric(silver1)},
QrCode::Ecc::LOW);
printQr(qr1);
// Illustration "golden"
const char *golden0 = "Golden ratio \xCF\x86 = 1.";
const char *golden1 = "6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374";
const char *golden2 = "......";
const QrCode qr2 = QrCode::encodeText(
(std::string(golden0) + golden1 + golden2).c_str(),
QrCode::Ecc::LOW);
printQr(qr2);
std::vector<uint8_t> bytes(golden0, golden0 + std::strlen(golden0));
const QrCode qr3 = QrCode::encodeSegments(
{QrSegment::makeBytes(bytes), QrSegment::makeNumeric(golden1), QrSegment::makeAlphanumeric(golden2)},
QrCode::Ecc::LOW);
printQr(qr3);
// Illustration "Madoka": kanji, kana, Cyrillic, full-width Latin, Greek characters
const char *madoka = // Encoded in UTF-8
"\xE3\x80\x8C\xE9\xAD\x94\xE6\xB3\x95\xE5"
"\xB0\x91\xE5\xA5\xB3\xE3\x81\xBE\xE3\x81"
"\xA9\xE3\x81\x8B\xE2\x98\x86\xE3\x83\x9E"
"\xE3\x82\xAE\xE3\x82\xAB\xE3\x80\x8D\xE3"
"\x81\xA3\xE3\x81\xA6\xE3\x80\x81\xE3\x80"
"\x80\xD0\x98\xD0\x90\xD0\x98\xE3\x80\x80"
"\xEF\xBD\x84\xEF\xBD\x85\xEF\xBD\x93\xEF"
"\xBD\x95\xE3\x80\x80\xCE\xBA\xCE\xB1\xEF"
"\xBC\x9F";
const QrCode qr4 = QrCode::encodeText(madoka, QrCode::Ecc::LOW);
printQr(qr4);
const std::vector<int> kanjiChars{ // Kanji mode encoding (13 bits per character)
0x0035, 0x1002, 0x0FC0, 0x0AED, 0x0AD7,
0x015C, 0x0147, 0x0129, 0x0059, 0x01BD,
0x018D, 0x018A, 0x0036, 0x0141, 0x0144,
0x0001, 0x0000, 0x0249, 0x0240, 0x0249,
0x0000, 0x0104, 0x0105, 0x0113, 0x0115,
0x0000, 0x0208, 0x01FF, 0x0008,
};
qrcodegen::BitBuffer bb;
for (int c : kanjiChars)
bb.appendBits(static_cast<std::uint32_t>(c), 13);
const QrCode qr5 = QrCode::encodeSegments(
{QrSegment(QrSegment::Mode::KANJI, static_cast<int>(kanjiChars.size()), bb)},
QrCode::Ecc::LOW);
printQr(qr5);
}
// Creates QR Codes with the same size and contents but different mask patterns.
static void doMaskDemo() {
// Project Nayuki URL
std::vector<QrSegment> segs0 = QrSegment::makeSegments("https://www.nayuki.io/");
printQr(QrCode::encodeSegments(segs0, QrCode::Ecc::HIGH, QrCode::MIN_VERSION, QrCode::MAX_VERSION, -1, true)); // Automatic mask
printQr(QrCode::encodeSegments(segs0, QrCode::Ecc::HIGH, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 3, true)); // Force mask 3
// Chinese text as UTF-8
std::vector<QrSegment> segs1 = QrSegment::makeSegments(
"\xE7\xB6\xAD\xE5\x9F\xBA\xE7\x99\xBE\xE7\xA7\x91\xEF\xBC\x88\x57\x69\x6B\x69\x70"
"\x65\x64\x69\x61\xEF\xBC\x8C\xE8\x81\x86\xE8\x81\xBD\x69\x2F\xCB\x8C\x77\xC9\xAA"
"\x6B\xE1\xB5\xBB\xCB\x88\x70\x69\xCB\x90\x64\x69\x2E\xC9\x99\x2F\xEF\xBC\x89\xE6"
"\x98\xAF\xE4\xB8\x80\xE5\x80\x8B\xE8\x87\xAA\xE7\x94\xB1\xE5\x85\xA7\xE5\xAE\xB9"
"\xE3\x80\x81\xE5\x85\xAC\xE9\x96\x8B\xE7\xB7\xA8\xE8\xBC\xAF\xE4\xB8\x94\xE5\xA4"
"\x9A\xE8\xAA\x9E\xE8\xA8\x80\xE7\x9A\x84\xE7\xB6\xB2\xE8\xB7\xAF\xE7\x99\xBE\xE7"
"\xA7\x91\xE5\x85\xA8\xE6\x9B\xB8\xE5\x8D\x94\xE4\xBD\x9C\xE8\xA8\x88\xE7\x95\xAB");
printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 0, true)); // Force mask 0
printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 1, true)); // Force mask 1
printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 5, true)); // Force mask 5
printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 7, true)); // Force mask 7
}
/*---- Utilities ----*/
// Returns a string of SVG code for an image depicting the given QR Code, with the given number
// of border modules. The string always uses Unix newlines (\n), regardless of the platform.
static std::string toSvgString(const QrCode &qr, int border) {
if (border < 0)
throw std::domain_error("Border must be non-negative");
if (border > INT_MAX / 2 || border * 2 > INT_MAX - qr.getSize())
throw std::overflow_error("Border too large");
std::ostringstream sb;
sb << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
sb << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n";
sb << "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 ";
sb << (qr.getSize() + border * 2) << " " << (qr.getSize() + border * 2) << "\" stroke=\"none\">\n";
sb << "\t<rect width=\"100%\" height=\"100%\" fill=\"#FFFFFF\"/>\n";
sb << "\t<path d=\"";
for (int y = 0; y < qr.getSize(); y++) {
for (int x = 0; x < qr.getSize(); x++) {
if (qr.getModule(x, y)) {
if (x != 0 || y != 0)
sb << " ";
sb << "M" << (x + border) << "," << (y + border) << "h1v1h-1z";
}
}
}
sb << "\" fill=\"#000000\"/>\n";
sb << "</svg>\n";
return sb.str();
}
// Prints the given QrCode object to the console.
static void printQr(const QrCode &qr) {
int border = 4;
for (int y = -border; y < qr.getSize() + border; y++) {
for (int x = -border; x < qr.getSize() + border; x++) {
std::cout << (qr.getModule(x, y) ? "##" : " ");
}
std::cout << std::endl;
}
std::cout << std::endl;
}
================================================
FILE: cpp/Readme.markdown
================================================
QR Code generator library - C++
===============================
Introduction
------------
This project aims to be the best, clearest QR Code generator library. The primary goals are flexible options and absolute correctness. Secondary goals are compact implementation size and good documentation comments.
Home page with live JavaScript demo, extensive descriptions, and competitor comparisons: https://www.nayuki.io/page/qr-code-generator-library
Features
--------
Core features:
* Significantly shorter code but more documentation comments compared to competing libraries
* Supports encoding all 40 versions (sizes) and all 4 error correction levels, as per the QR Code Model 2 standard
* Output format: Raw modules/pixels of the QR symbol
* Detects finder-like penalty patterns more accurately than other implementations
* Encodes numeric and special-alphanumeric text in less space than general text
* Coded carefully to prevent memory corruption, integer overflow, platform-dependent inconsistencies, and undefined behavior; tested rigorously to confirm safety
* Open-source code under the permissive MIT License
Manual parameters:
* User can specify minimum and maximum version numbers allowed, then library will automatically choose smallest version in the range that fits the data
* User can specify mask pattern manually, otherwise library will automatically evaluate all 8 masks and select the optimal one
* User can specify absolute error correction level, or allow the library to boost it if it doesn't increase the version number
* User can create a list of data segments manually and add ECI segments
More information about QR Code technology and this library's design can be found on the project home page.
Examples
--------
```c++
#include <string>
#include <vector>
#include "QrCode.hpp"
using namespace qrcodegen;
// Simple operation
QrCode qr0 = QrCode::encodeText("Hello, world!", QrCode::Ecc::MEDIUM);
std::string svg = toSvgString(qr0, 4); // See QrCodeGeneratorDemo
// Manual operation
std::vector<QrSegment> segs =
QrSegment::makeSegments("3141592653589793238462643383");
QrCode qr1 = QrCode::encodeSegments(
segs, QrCode::Ecc::HIGH, 5, 5, 2, false);
for (int y = 0; y < qr1.getSize(); y++) {
for (int x = 0; x < qr1.getSize(); x++) {
(... paint qr1.getModule(x, y) ...)
}
}
```
More complete set of examples: https://github.com/nayuki/QR-Code-generator/blob/master/cpp/QrCodeGeneratorDemo.cpp .
================================================
FILE: cpp/qrcodegen.cpp
================================================
/*
* QR Code generator library (C++)
*
* Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* 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 <algorithm>
#include <cassert>
#include <climits>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <utility>
#include "qrcodegen.hpp"
using std::int8_t;
using std::uint8_t;
using std::size_t;
using std::vector;
namespace qrcodegen {
/*---- Class QrSegment ----*/
QrSegment::Mode::Mode(int mode, int cc0, int cc1, int cc2) :
modeBits(mode) {
numBitsCharCount[0] = cc0;
numBitsCharCount[1] = cc1;
numBitsCharCount[2] = cc2;
}
int QrSegment::Mode::getModeBits() const {
return modeBits;
}
int QrSegment::Mode::numCharCountBits(int ver) const {
return numBitsCharCount[(ver + 7) / 17];
}
const QrSegment::Mode QrSegment::Mode::NUMERIC (0x1, 10, 12, 14);
const QrSegment::Mode QrSegment::Mode::ALPHANUMERIC(0x2, 9, 11, 13);
const QrSegment::Mode QrSegment::Mode::BYTE (0x4, 8, 16, 16);
const QrSegment::Mode QrSegment::Mode::KANJI (0x8, 8, 10, 12);
const QrSegment::Mode QrSegment::Mode::ECI (0x7, 0, 0, 0);
QrSegment QrSegment::makeBytes(const vector<uint8_t> &data) {
if (data.size() > static_cast<unsigned int>(INT_MAX))
throw std::length_error("Data too long");
BitBuffer bb;
for (uint8_t b : data)
bb.appendBits(b, 8);
return QrSegment(Mode::BYTE, static_cast<int>(data.size()), std::move(bb));
}
QrSegment QrSegment::makeNumeric(const char *digits) {
BitBuffer bb;
int accumData = 0;
int accumCount = 0;
int charCount = 0;
for (; *digits != '\0'; digits++, charCount++) {
char c = *digits;
if (c < '0' || c > '9')
throw std::domain_error("String contains non-numeric characters");
accumData = accumData * 10 + (c - '0');
accumCount++;
if (accumCount == 3) {
bb.appendBits(static_cast<uint32_t>(accumData), 10);
accumData = 0;
accumCount = 0;
}
}
if (accumCount > 0) // 1 or 2 digits remaining
bb.appendBits(static_cast<uint32_t>(accumData), accumCount * 3 + 1);
return QrSegment(Mode::NUMERIC, charCount, std::move(bb));
}
QrSegment QrSegment::makeAlphanumeric(const char *text) {
BitBuffer bb;
int accumData = 0;
int accumCount = 0;
int charCount = 0;
for (; *text != '\0'; text++, charCount++) {
const char *temp = std::strchr(ALPHANUMERIC_CHARSET, *text);
if (temp == nullptr)
throw std::domain_error("String contains unencodable characters in alphanumeric mode");
accumData = accumData * 45 + static_cast<int>(temp - ALPHANUMERIC_CHARSET);
accumCount++;
if (accumCount == 2) {
bb.appendBits(static_cast<uint32_t>(accumData), 11);
accumData = 0;
accumCount = 0;
}
}
if (accumCount > 0) // 1 character remaining
bb.appendBits(static_cast<uint32_t>(accumData), 6);
return QrSegment(Mode::ALPHANUMERIC, charCount, std::move(bb));
}
vector<QrSegment> QrSegment::makeSegments(const char *text) {
// Select the most efficient segment encoding automatically
vector<QrSegment> result;
if (*text == '\0'); // Leave result empty
else if (isNumeric(text))
result.push_back(makeNumeric(text));
else if (isAlphanumeric(text))
result.push_back(makeAlphanumeric(text));
else {
vector<uint8_t> bytes;
for (; *text != '\0'; text++)
bytes.push_back(static_cast<uint8_t>(*text));
result.push_back(makeBytes(bytes));
}
return result;
}
QrSegment QrSegment::makeEci(long assignVal) {
BitBuffer bb;
if (assignVal < 0)
throw std::domain_error("ECI assignment value out of range");
else if (assignVal < (1 << 7))
bb.appendBits(static_cast<uint32_t>(assignVal), 8);
else if (assignVal < (1 << 14)) {
bb.appendBits(2, 2);
bb.appendBits(static_cast<uint32_t>(assignVal), 14);
} else if (assignVal < 1000000L) {
bb.appendBits(6, 3);
bb.appendBits(static_cast<uint32_t>(assignVal), 21);
} else
throw std::domain_error("ECI assignment value out of range");
return QrSegment(Mode::ECI, 0, std::move(bb));
}
QrSegment::QrSegment(const Mode &md, int numCh, const std::vector<bool> &dt) :
mode(&md),
numChars(numCh),
data(dt) {
if (numCh < 0)
throw std::domain_error("Invalid value");
}
QrSegment::QrSegment(const Mode &md, int numCh, std::vector<bool> &&dt) :
mode(&md),
numChars(numCh),
data(std::move(dt)) {
if (numCh < 0)
throw std::domain_error("Invalid value");
}
int QrSegment::getTotalBits(const vector<QrSegment> &segs, int version) {
int result = 0;
for (const QrSegment &seg : segs) {
int ccbits = seg.mode->numCharCountBits(version);
if (seg.numChars >= (1L << ccbits))
return -1; // The segment's length doesn't fit the field's bit width
if (4 + ccbits > INT_MAX - result)
return -1; // The sum will overflow an int type
result += 4 + ccbits;
if (seg.data.size() > static_cast<unsigned int>(INT_MAX - result))
return -1; // The sum will overflow an int type
result += static_cast<int>(seg.data.size());
}
return result;
}
bool QrSegment::isNumeric(const char *text) {
for (; *text != '\0'; text++) {
char c = *text;
if (c < '0' || c > '9')
return false;
}
return true;
}
bool QrSegment::isAlphanumeric(const char *text) {
for (; *text != '\0'; text++) {
if (std::strchr(ALPHANUMERIC_CHARSET, *text) == nullptr)
return false;
}
return true;
}
const QrSegment::Mode &QrSegment::getMode() const {
return *mode;
}
int QrSegment::getNumChars() const {
return numChars;
}
const std::vector<bool> &QrSegment::getData() const {
return data;
}
const char *QrSegment::ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
/*---- Class QrCode ----*/
int QrCode::getFormatBits(Ecc ecl) {
switch (ecl) {
case Ecc::LOW : return 1;
case Ecc::MEDIUM : return 0;
case Ecc::QUARTILE: return 3;
case Ecc::HIGH : return 2;
default: throw std::logic_error("Unreachable");
}
}
QrCode QrCode::encodeText(const char *text, Ecc ecl) {
vector<QrSegment> segs = QrSegment::makeSegments(text);
return encodeSegments(segs, ecl);
}
QrCode QrCode::encodeBinary(const vector<uint8_t> &data, Ecc ecl) {
vector<QrSegment> segs{QrSegment::makeBytes(data)};
return encodeSegments(segs, ecl);
}
QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl,
int minVersion, int maxVersion, int mask, bool boostEcl) {
if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
throw std::invalid_argument("Invalid value");
// Find the minimal version number to use
int version, dataUsedBits;
for (version = minVersion; ; version++) {
int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
dataUsedBits = QrSegment::getTotalBits(segs, version);
if (dataUsedBits != -1 && 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
std::ostringstream sb;
if (dataUsedBits == -1)
sb << "Segment too long";
else {
sb << "Data length = " << dataUsedBits << " bits, ";
sb << "Max capacity = " << dataCapacityBits << " bits";
}
throw data_too_long(sb.str());
}
}
assert(dataUsedBits != -1);
// Increase the error correction level while the data still fits in the current version number
for (Ecc newEcl : {Ecc::MEDIUM, Ecc::QUARTILE, Ecc::HIGH}) { // From low to high
if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8)
ecl = newEcl;
}
// Concatenate all segments to create the data bit string
BitBuffer bb;
for (const QrSegment &seg : segs) {
bb.appendBits(static_cast<uint32_t>(seg.getMode().getModeBits()), 4);
bb.appendBits(static_cast<uint32_t>(seg.getNumChars()), seg.getMode().numCharCountBits(version));
bb.insert(bb.end(), seg.getData().begin(), seg.getData().end());
}
assert(bb.size() == static_cast<unsigned int>(dataUsedBits));
// Add terminator and pad up to a byte if applicable
size_t dataCapacityBits = static_cast<size_t>(getNumDataCodewords(version, ecl)) * 8;
assert(bb.size() <= dataCapacityBits);
bb.appendBits(0, std::min(4, static_cast<int>(dataCapacityBits - bb.size())));
bb.appendBits(0, (8 - static_cast<int>(bb.size() % 8)) % 8);
assert(bb.size() % 8 == 0);
// Pad with alternating bytes until data capacity is reached
for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
bb.appendBits(padByte, 8);
// Pack bits into bytes in big endian
vector<uint8_t> dataCodewords(bb.size() / 8);
for (size_t i = 0; i < bb.size(); i++)
dataCodewords.at(i >> 3) |= (bb.at(i) ? 1 : 0) << (7 - (i & 7));
// Create the QR Code object
return QrCode(version, ecl, dataCodewords, mask);
}
QrCode::QrCode(int ver, Ecc ecl, const vector<uint8_t> &dataCodewords, int msk) :
// Initialize fields and check arguments
version(ver),
errorCorrectionLevel(ecl) {
if (ver < MIN_VERSION || ver > MAX_VERSION)
throw std::domain_error("Version value out of range");
if (msk < -1 || msk > 7)
throw std::domain_error("Mask value out of range");
size = ver * 4 + 17;
size_t sz = static_cast<size_t>(size);
modules = vector<vector<bool> >(sz, vector<bool>(sz)); // Initially all light
isFunction = vector<vector<bool> >(sz, vector<bool>(sz));
// Compute ECC, draw modules
drawFunctionPatterns();
const vector<uint8_t> allCodewords = addEccAndInterleave(dataCodewords);
drawCodewords(allCodewords);
// Do masking
if (msk == -1) { // Automatically choose best mask
long minPenalty = LONG_MAX;
for (int i = 0; i < 8; i++) {
applyMask(i);
drawFormatBits(i);
long penalty = getPenaltyScore();
if (penalty < minPenalty) {
msk = i;
minPenalty = penalty;
}
applyMask(i); // Undoes the mask due to XOR
}
}
assert(0 <= msk && msk <= 7);
mask = msk;
applyMask(msk); // Apply the final choice of mask
drawFormatBits(msk); // Overwrite old format bits
isFunction.clear();
isFunction.shrink_to_fit();
}
int QrCode::getVersion() const {
return version;
}
int QrCode::getSize() const {
return size;
}
QrCode::Ecc QrCode::getErrorCorrectionLevel() const {
return errorCorrectionLevel;
}
int QrCode::getMask() const {
return mask;
}
bool QrCode::getModule(int x, int y) const {
return 0 <= x && x < size && 0 <= y && y < size && module(x, y);
}
void QrCode::drawFunctionPatterns() {
// Draw horizontal and vertical timing patterns
for (int i = 0; i < size; i++) {
setFunctionModule(6, i, i % 2 == 0);
setFunctionModule(i, 6, i % 2 == 0);
}
// Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
drawFinderPattern(3, 3);
drawFinderPattern(size - 4, 3);
drawFinderPattern(3, size - 4);
// Draw numerous alignment patterns
const vector<int> alignPatPos = getAlignmentPatternPositions();
size_t numAlign = alignPatPos.size();
for (size_t i = 0; i < numAlign; i++) {
for (size_t j = 0; j < numAlign; j++) {
// Don't draw on the three finder corners
if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0)))
drawAlignmentPattern(alignPatPos.at(i), alignPatPos.at(j));
}
}
// Draw configuration data
drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
drawVersion();
}
void QrCode::drawFormatBits(int msk) {
// Calculate error correction code and pack bits
int data = getFormatBits(errorCorrectionLevel) << 3 | msk; // errCorrLvl is uint2, msk is uint3
int rem = data;
for (int i = 0; i < 10; i++)
rem = (rem << 1) ^ ((rem >> 9) * 0x537);
int bits = (data << 10 | rem) ^ 0x5412; // uint15
assert(bits >> 15 == 0);
// Draw first copy
for (int i = 0; i <= 5; i++)
setFunctionModule(8, i, getBit(bits, i));
setFunctionModule(8, 7, getBit(bits, 6));
setFunctionModule(8, 8, getBit(bits, 7));
setFunctionModule(7, 8, getBit(bits, 8));
for (int i = 9; i < 15; i++)
setFunctionModule(14 - i, 8, getBit(bits, i));
// Draw second copy
for (int i = 0; i < 8; i++)
setFunctionModule(size - 1 - i, 8, getBit(bits, i));
for (int i = 8; i < 15; i++)
setFunctionModule(8, size - 15 + i, getBit(bits, i));
setFunctionModule(8, size - 8, true); // Always dark
}
void QrCode::drawVersion() {
if (version < 7)
return;
// Calculate error correction code and pack bits
int rem = version; // version is uint6, in the range [7, 40]
for (int i = 0; i < 12; i++)
rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
long bits = static_cast<long>(version) << 12 | rem; // uint18
assert(bits >> 18 == 0);
// Draw two copies
for (int i = 0; i < 18; i++) {
bool bit = getBit(bits, i);
int a = size - 11 + i % 3;
int b = i / 3;
setFunctionModule(a, b, bit);
setFunctionModule(b, a, bit);
}
}
void QrCode::drawFinderPattern(int x, int y) {
for (int dy = -4; dy <= 4; dy++) {
for (int dx = -4; dx <= 4; dx++) {
int dist = std::max(std::abs(dx), std::abs(dy)); // Chebyshev/infinity norm
int xx = x + dx, yy = y + dy;
if (0 <= xx && xx < size && 0 <= yy && yy < size)
setFunctionModule(xx, yy, dist != 2 && dist != 4);
}
}
}
void QrCode::drawAlignmentPattern(int x, int y) {
for (int dy = -2; dy <= 2; dy++) {
for (int dx = -2; dx <= 2; dx++)
setFunctionModule(x + dx, y + dy, std::max(std::abs(dx), std::abs(dy)) != 1);
}
}
void QrCode::setFunctionModule(int x, int y, bool isDark) {
size_t ux = static_cast<size_t>(x);
size_t uy = static_cast<size_t>(y);
modules .at(uy).at(ux) = isDark;
isFunction.at(uy).at(ux) = true;
}
bool QrCode::module(int x, int y) const {
return modules.at(static_cast<size_t>(y)).at(static_cast<size_t>(x));
}
vector<uint8_t> QrCode::addEccAndInterleave(const vector<uint8_t> &data) const {
if (data.size() != static_cast<unsigned int>(getNumDataCodewords(version, errorCorrectionLevel)))
throw std::invalid_argument("Invalid argument");
// Calculate parameter numbers
int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[static_cast<int>(errorCorrectionLevel)][version];
int blockEccLen = ECC_CODEWORDS_PER_BLOCK [static_cast<int>(errorCorrectionLevel)][version];
int rawCodewords = getNumRawDataModules(version) / 8;
int numShortBlocks = numBlocks - rawCodewords % numBlocks;
int shortBlockLen = rawCodewords / numBlocks;
// Split data into blocks and append ECC to each block
vector<vector<uint8_t> > blocks;
const vector<uint8_t> rsDiv = reedSolomonComputeDivisor(blockEccLen);
for (int i = 0, k = 0; i < numBlocks; i++) {
vector<uint8_t> dat(data.cbegin() + k, data.cbegin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1)));
k += static_cast<int>(dat.size());
const vector<uint8_t> ecc = reedSolomonComputeRemainder(dat, rsDiv);
if (i < numShortBlocks)
dat.push_back(0);
dat.insert(dat.end(), ecc.cbegin(), ecc.cend());
blocks.push_back(std::move(dat));
}
// Interleave (not concatenate) the bytes from every block into a single sequence
vector<uint8_t> result;
for (size_t i = 0; i < blocks.at(0).size(); i++) {
for (size_t j = 0; j < blocks.size(); j++) {
// Skip the padding byte in short blocks
if (i != static_cast<unsigned int>(shortBlockLen - blockEccLen) || j >= static_cast<unsigned int>(numShortBlocks))
result.push_back(blocks.at(j).at(i));
}
}
assert(result.size() == static_cast<unsigned int>(rawCodewords));
return result;
}
void QrCode::drawCodewords(const vector<uint8_t> &data) {
if (data.size() != static_cast<unsigned int>(getNumRawDataModules(version) / 8))
throw std::invalid_argument("Invalid argument");
size_t i = 0; // Bit index into the data
// Do the funny zigzag scan
for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
if (right == 6)
right = 5;
for (int vert = 0; vert < size; vert++) { // Vertical counter
for (int j = 0; j < 2; j++) {
size_t x = static_cast<size_t>(right - j); // Actual x coordinate
bool upward = ((right + 1) & 2) == 0;
size_t y = static_cast<size_t>(upward ? size - 1 - vert : vert); // Actual y coordinate
if (!isFunction.at(y).at(x) && i < data.size() * 8) {
modules.at(y).at(x) = getBit(data.at(i >> 3), 7 - static_cast<int>(i & 7));
i++;
}
// If this QR Code has any remainder bits (0 to 7), they were assigned as
// 0/false/light by the constructor and are left unchanged by this method
}
}
}
assert(i == data.size() * 8);
}
void QrCode::applyMask(int msk) {
if (msk < 0 || msk > 7)
throw std::domain_error("Mask value out of range");
size_t sz = static_cast<size_t>(size);
for (size_t y = 0; y < sz; y++) {
for (size_t x = 0; x < sz; x++) {
bool invert;
switch (msk) {
case 0: invert = (x + y) % 2 == 0; break;
case 1: invert = y % 2 == 0; break;
case 2: invert = x % 3 == 0; break;
case 3: invert = (x + y) % 3 == 0; break;
case 4: invert = (x / 3 + y / 2) % 2 == 0; break;
case 5: invert = x * y % 2 + x * y % 3 == 0; break;
case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
default: throw std::logic_error("Unreachable");
}
modules.at(y).at(x) = modules.at(y).at(x) ^ (invert & !isFunction.at(y).at(x));
}
}
}
long QrCode::getPenaltyScore() const {
long result = 0;
// Adjacent modules in row having same color, and finder-like patterns
for (int y = 0; y < size; y++) {
bool runColor = false;
int runX = 0;
std::array<int,7> runHistory = {};
for (int x = 0; x < size; x++) {
if (module(x, y) == runColor) {
runX++;
if (runX == 5)
result += PENALTY_N1;
else if (runX > 5)
result++;
} else {
finderPenaltyAddHistory(runX, runHistory);
if (!runColor)
result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
runColor = module(x, y);
runX = 1;
}
}
result += finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3;
}
// Adjacent modules in column having same color, and finder-like patterns
for (int x = 0; x < size; x++) {
bool runColor = false;
int runY = 0;
std::array<int,7> runHistory = {};
for (int y = 0; y < size; y++) {
if (module(x, y) == runColor) {
runY++;
if (runY == 5)
result += PENALTY_N1;
else if (runY > 5)
result++;
} else {
finderPenaltyAddHistory(runY, runHistory);
if (!runColor)
result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
runColor = module(x, y);
runY = 1;
}
}
result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3;
}
// 2*2 blocks of modules having same color
for (int y = 0; y < size - 1; y++) {
for (int x = 0; x < size - 1; x++) {
bool color = module(x, y);
if ( color == module(x + 1, y) &&
color == module(x, y + 1) &&
color == module(x + 1, y + 1))
result += PENALTY_N2;
}
}
// Balance of dark and light modules
int dark = 0;
for (const vector<bool> &row : modules) {
for (bool color : row) {
if (color)
dark++;
}
}
int total = size * size; // Note that size is odd, so dark/total != 1/2
// Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)%
int k = static_cast<int>((std::abs(dark * 20L - total * 10L) + total - 1) / total) - 1;
assert(0 <= k && k <= 9);
result += k * PENALTY_N4;
assert(0 <= result && result <= 2568888L); // Non-tight upper bound based on default values of PENALTY_N1, ..., N4
return result;
}
vector<int> QrCode::getAlignmentPatternPositions() const {
if (version == 1)
return vector<int>();
else {
int numAlign = version / 7 + 2;
int step = (version * 8 + numAlign * 3 + 5) / (numAlign * 4 - 4) * 2;
vector<int> result;
for (int i = 0, pos = size - 7; i < numAlign - 1; i++, pos -= step)
result.insert(result.begin(), pos);
result.insert(result.begin(), 6);
return result;
}
}
int QrCode::getNumRawDataModules(int ver) {
if (ver < MIN_VERSION || ver > MAX_VERSION)
throw std::domain_error("Version number out of range");
int result = (16 * ver + 128) * ver + 64;
if (ver >= 2) {
int numAlign = ver / 7 + 2;
result -= (25 * numAlign - 10) * numAlign - 55;
if (ver >= 7)
result -= 36;
}
assert(208 <= result && result <= 29648);
return result;
}
int QrCode::getNumDataCodewords(int ver, Ecc ecl) {
return getNumRawDataModules(ver) / 8
- ECC_CODEWORDS_PER_BLOCK [static_cast<int>(ecl)][ver]
* NUM_ERROR_CORRECTION_BLOCKS[static_cast<int>(ecl)][ver];
}
vector<uint8_t> QrCode::reedSolomonComputeDivisor(int degree) {
if (degree < 1 || degree > 255)
throw std::domain_error("Degree out of range");
// Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1.
// For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.
vector<uint8_t> result(static_cast<size_t>(degree));
result.at(result.size() - 1) = 1; // Start off with the monomial x^0
// Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
// and drop the highest monomial term which is always 1x^degree.
// Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
uint8_t root = 1;
for (int i = 0; i < degree; i++) {
// Multiply the current product by (x - r^i)
for (size_t j = 0; j < result.size(); j++) {
result.at(j) = reedSolomonMultiply(result.at(j), root);
if (j + 1 < result.size())
result.at(j) ^= result.at(j + 1);
}
root = reedSolomonMultiply(root, 0x02);
}
return result;
}
vector<uint8_t> QrCode::reedSolomonComputeRemainder(const vector<uint8_t> &data, const vector<uint8_t> &divisor) {
vector<uint8_t> result(divisor.size());
for (uint8_t b : data) { // Polynomial division
uint8_t factor = b ^ result.at(0);
result.erase(result.begin());
result.push_back(0);
for (size_t i = 0; i < result.size(); i++)
result.at(i) ^= reedSolomonMultiply(divisor.at(i), factor);
}
return result;
}
uint8_t QrCode::reedSolomonMultiply(uint8_t x, uint8_t y) {
// Russian peasant multiplication
int z = 0;
for (int i = 7; i >= 0; i--) {
z = (z << 1) ^ ((z >> 7) * 0x11D);
z ^= ((y >> i) & 1) * x;
}
assert(z >> 8 == 0);
return static_cast<uint8_t>(z);
}
int QrCode::finderPenaltyCountPatterns(const std::array<int,7> &runHistory) const {
int n = runHistory.at(1);
assert(n <= size * 3);
bool core = n > 0 && runHistory.at(2) == n && runHistory.at(3) == n * 3 && runHistory.at(4) == n && runHistory.at(5) == n;
return (core && runHistory.at(0) >= n * 4 && runHistory.at(6) >= n ? 1 : 0)
+ (core && runHistory.at(6) >= n * 4 && runHistory.at(0) >= n ? 1 : 0);
}
int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array<int,7> &runHistory) const {
if (currentRunColor) { // Terminate dark run
finderPenaltyAddHistory(currentRunLength, runHistory);
currentRunLength = 0;
}
currentRunLength += size; // Add light border to final run
finderPenaltyAddHistory(currentRunLength, runHistory);
return finderPenaltyCountPatterns(runHistory);
}
void QrCode::finderPenaltyAddHistory(int currentRunLength, std::array<int,7> &runHistory) const {
if (runHistory.at(0) == 0)
currentRunLength += size; // Add light border to initial run
std::copy_backward(runHistory.cbegin(), runHistory.cend() - 1, runHistory.end());
runHistory.at(0) = currentRunLength;
}
bool QrCode::getBit(long x, int i) {
return ((x >> i) & 1) != 0;
}
/*---- Tables of constants ----*/
const int QrCode::PENALTY_N1 = 3;
const int QrCode::PENALTY_N2 = 3;
const int QrCode::PENALTY_N3 = 40;
const int QrCode::PENALTY_N4 = 10;
const int8_t QrCode::ECC_CODEWORDS_PER_BLOCK[4][41] = {
// Version: (note that index 0 is for padding, and is set to an illegal value)
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
{-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}, // Low
{-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}, // Medium
{-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}, // Quartile
{-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}, // High
};
const int8_t QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][41] = {
// Version: (note that index 0 is for padding, and is set to an illegal value)
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
{-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}, // Low
{-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}, // Medium
{-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}, // Quartile
{-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}, // High
};
data_too_long::data_too_long(const std::string &msg) :
std::length_error(msg) {}
/*---- Class BitBuffer ----*/
BitBuffer::BitBuffer()
: std::vector<bool>() {}
void BitBuffer::appendBits(std::uint32_t val, int len) {
if (len < 0 || len > 31 || val >> len != 0)
throw std::domain_error("Value out of range");
for (int i = len - 1; i >= 0; i--) // Append bit by bit
this->push_back(((val >> i) & 1) != 0);
}
}
================================================
FILE: cpp/qrcodegen.hpp
================================================
/*
* QR Code generator library (C++)
*
* Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* 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.
*/
#pragma once
#include <array>
#include <cstdint>
#include <stdexcept>
#include <string>
#include <vector>
namespace qrcodegen {
/*
* A segment of character/binary/control data in a QR Code symbol.
* Instances of this class are immutable.
* The mid-level way to create a segment is to take the payload data
* and call a static factory function such as QrSegment::makeNumeric().
* The low-level way to create a segment is to custom-make the bit buffer
* and call the QrSegment() constructor with appropriate values.
* This segment class imposes no length restrictions, but QR Codes have restrictions.
* Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.
* Any segment longer than this is meaningless for the purpose of generating QR Codes.
*/
class QrSegment final {
/*---- Public helper enumeration ----*/
/*
* Describes how a segment's data bits are interpreted. Immutable.
*/
public: class Mode final {
/*-- Constants --*/
public: static const Mode NUMERIC;
public: static const Mode ALPHANUMERIC;
public: static const Mode BYTE;
public: static const Mode KANJI;
public: static const Mode ECI;
/*-- Fields --*/
// The mode indicator bits, which is a uint4 value (range 0 to 15).
private: int modeBits;
// Number of character count bits for three different version ranges.
private: int numBitsCharCount[3];
/*-- Constructor --*/
private: Mode(int mode, int cc0, int cc1, int cc2);
/*-- Methods --*/
/*
* (Package-private) Returns the mode indicator bits, which is an unsigned 4-bit value (range 0 to 15).
*/
public: int getModeBits() const;
/*
* (Package-private) Returns the bit width of the character count field for a segment in
* this mode in a QR Code at the given version number. The result is in the range [0, 16].
*/
public: int numCharCountBits(int ver) const;
};
/*---- Static factory functions (mid level) ----*/
/*
* Returns a segment representing the given binary data encoded in
* byte mode. All input byte vectors are acceptable. Any text string
* can be converted to UTF-8 bytes and encoded as a byte mode segment.
*/
public: static QrSegment makeBytes(const std::vector<std::uint8_t> &data);
/*
* Returns a segment representing the given string of decimal digits encoded in numeric mode.
*/
public: static QrSegment makeNumeric(const char *digits);
/*
* Returns a segment representing the given text string encoded in alphanumeric mode.
* The characters allowed are: 0 to 9, A to Z (uppercase only), space,
* dollar, percent, asterisk, plus, hyphen, period, slash, colon.
*/
public: static QrSegment makeAlphanumeric(const char *text);
/*
* Returns a list of zero or more segments to represent the given text string. The result
* may use various segment modes and switch modes to optimize the length of the bit stream.
*/
public: static std::vector<QrSegment> makeSegments(const char *text);
/*
* Returns a segment representing an Extended Channel Interpretation
* (ECI) designator with the given assignment value.
*/
public: static QrSegment makeEci(long assignVal);
/*---- Public static helper functions ----*/
/*
* Tests whether the given string can be encoded as a segment in numeric mode.
* A string is encodable iff each character is in the range 0 to 9.
*/
public: static bool isNumeric(const char *text);
/*
* Tests whether the given string can be encoded as a segment in alphanumeric mode.
* A string is encodable iff each character is in the following set: 0 to 9, A to Z
* (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
*/
public: static bool isAlphanumeric(const char *text);
/*---- Instance fields ----*/
/* The mode indicator of this segment. Accessed through getMode(). */
private: const 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.
* Accessed through getNumChars(). */
private: int numChars;
/* The data bits of this segment. Accessed through getData(). */
private: std::vector<bool> data;
/*---- Constructors (low level) ----*/
/*
* Creates a new QR Code segment with the given attributes and data.
* The character count (numCh) must agree with the mode and the bit buffer length,
* but the constraint isn't checked. The given bit buffer is copied and stored.
*/
public: QrSegment(const Mode &md, int numCh, const std::vector<bool> &dt);
/*
* Creates a new QR Code segment with the given parameters and data.
* The character count (numCh) must agree with the mode and the bit buffer length,
* but the constraint isn't checked. The given bit buffer is moved and stored.
*/
public: QrSegment(const Mode &md, int numCh, std::vector<bool> &&dt);
/*---- Methods ----*/
/*
* Returns the mode field of this segment.
*/
public: const Mode &getMode() const;
/*
* Returns the character count field of this segment.
*/
public: int getNumChars() const;
/*
* Returns the data bits of this segment.
*/
public: const std::vector<bool> &getData() const;
// (Package-private) Calculates the number of bits needed to encode the given segments at
// the given version. Returns a non-negative number if successful. Otherwise returns -1 if a
// segment has too many characters to fit its length field, or the total bits exceeds INT_MAX.
public: static int getTotalBits(const std::vector<QrSegment> &segs, int version);
/*---- Private constant ----*/
/* The set of all legal characters in alphanumeric mode, where
* each character value maps to the index in the string. */
private: static const char *ALPHANUMERIC_CHARSET;
};
/*
* A QR Code symbol, which is a type of two-dimension barcode.
* Invented by Denso Wave and described in the ISO/IEC 18004 standard.
* Instances of this class represent an immutable square grid of dark and light cells.
* The class provides static factory functions to create a QR Code from text or binary data.
* The class covers the QR Code Model 2 specification, supporting all versions (sizes)
* from 1 to 40, all 4 error correction levels, and 4 character encoding modes.
*
* Ways to create a QR Code object:
* - High level: Take the payload data and call QrCode::encodeText() or QrCode::encodeBinary().
* - Mid level: Custom-make the list of segments and call QrCode::encodeSegments().
* - Low level: Custom-make the array of data codeword bytes (including
* segment headers and final padding, excluding error correction codewords),
* supply the appropriate version number, and call the QrCode() constructor.
* (Note that all ways require supplying the desired error correction level.)
*/
class QrCode final {
/*---- Public helper enumeration ----*/
/*
* The error correction level in a QR Code symbol.
*/
public: enum class Ecc {
LOW = 0 , // The QR Code can tolerate about 7% erroneous codewords
MEDIUM , // The QR Code can tolerate about 15% erroneous codewords
QUARTILE, // The QR Code can tolerate about 25% erroneous codewords
HIGH , // The QR Code can tolerate about 30% erroneous codewords
};
// Returns a value in the range 0 to 3 (unsigned 2-bit integer).
private: static int getFormatBits(Ecc ecl);
/*---- Static factory functions (high level) ----*/
/*
* Returns a QR Code representing the given Unicode text string at the given error correction level.
* As a conservative upper bound, this function is guaranteed to succeed for strings that have 2953 or fewer
* UTF-8 code units (not Unicode code points) if the low error correction level is used. The smallest possible
* QR Code version is automatically chosen for the output. The ECC level of the result may be higher than
* the ecl argument if it can be done without increasing the version.
*/
public: static QrCode encodeText(const char *text, Ecc ecl);
/*
* Returns a QR Code representing the given binary data at the given error correction level.
* This function always encodes using the binary segment mode, not any text mode. The maximum number of
* bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
* The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
*/
public: static QrCode encodeBinary(const std::vector<std::uint8_t> &data, Ecc ecl);
/*---- Static factory functions (mid level) ----*/
/*
* Returns a QR Code representing the given segments with the given encoding parameters.
* The smallest possible QR Code version within the given range is automatically
* chosen for the output. Iff boostEcl is true, then the ECC level of the result
* may be higher than the ecl argument if it can be done without increasing the
* version. The mask number is either between 0 to 7 (inclusive) to force that
* mask, or -1 to automatically choose an appropriate mask (which may be slow).
* This function allows the user to create a custom sequence of segments that switches
* between modes (such as alphanumeric and byte) to encode text in less space.
* This is a mid-level API; the high-level API is encodeText() and encodeBinary().
*/
public: static QrCode encodeSegments(const std::vector<QrSegment> &segs, Ecc ecl,
int minVersion=1, int maxVersion=40, int mask=-1, bool boostEcl=true); // All optional parameters
/*---- Instance fields ----*/
// Immutable scalar parameters:
/* The version number of this QR Code, which is between 1 and 40 (inclusive).
* This determines the size of this barcode. */
private: int version;
/* The width and height of this QR Code, measured in modules, between
* 21 and 177 (inclusive). This is equal to version * 4 + 17. */
private: int size;
/* The error correction level used in this QR Code. */
private: Ecc errorCorrectionLevel;
/* The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive).
* Even if a QR Code is created with automatic masking requested (mask = -1),
* the resulting object still has a mask value between 0 and 7. */
private: int mask;
// Private grids of modules/pixels, with dimensions of size*size:
// The modules of this QR Code (false = light, true = dark).
// Immutable after constructor finishes. Accessed through getModule().
private: std::vector<std::vector<bool> > modules;
// Indicates function modules that are not subjected to masking. Discarded when constructor finishes.
private: std::vector<std::vector<bool> > isFunction;
/*---- Constructor (low level) ----*/
/*
* Creates a new QR Code with the given version number,
* error correction level, data codeword bytes, and mask number.
* This is a low-level API that most users should not use directly.
* A mid-level API is the encodeSegments() function.
*/
public: QrCode(int ver, Ecc ecl, const std::vector<std::uint8_t> &dataCodewords, int msk);
/*---- Public instance methods ----*/
/*
* Returns this QR Code's version, in the range [1, 40].
*/
public: int getVersion() const;
/*
* Returns this QR Code's size, in the range [21, 177].
*/
public: int getSize() const;
/*
* Returns this QR Code's error correction level.
*/
public: Ecc getErrorCorrectionLevel() const;
/*
* Returns this QR Code's mask, in the range [0, 7].
*/
public: int getMask() const;
/*
* Returns the color of the module (pixel) at the given coordinates, which is false
* for light or true for dark. The top left corner has the coordinates (x=0, y=0).
* If the given coordinates are out of bounds, then false (light) is returned.
*/
public: bool getModule(int x, int y) const;
/*---- Private helper methods for constructor: Drawing function modules ----*/
// Reads this object's version field, and draws and marks all function modules.
private: void drawFunctionPatterns();
// Draws two copies of the format bits (with its own error correction code)
// based on the given mask and this object's error correction level field.
private: void drawFormatBits(int msk);
// Draws two copies of the version bits (with its own error correction code),
// based on this object's version field, iff 7 <= version <= 40.
private: void drawVersion();
// Draws a 9*9 finder pattern including the border separator,
// with the center module at (x, y). Modules can be out of bounds.
private: void drawFinderPattern(int x, int y);
// Draws a 5*5 alignment pattern, with the center module
// at (x, y). All modules must be in bounds.
private: void drawAlignmentPattern(int x, int y);
// Sets the color of a module and marks it as a function module.
// Only used by the constructor. Coordinates must be in bounds.
private: void setFunctionModule(int x, int y, bool isDark);
// Returns the color of the module at the given coordinates, which must be in range.
private: bool module(int x, int y) const;
/*---- Private helper methods for constructor: Codewords and masking ----*/
// Returns a new byte string representing the given data with the appropriate error correction
// codewords appended to it, based on this object's version and error correction level.
private: std::vector<std::uint8_t> addEccAndInterleave(const std::vector<std::uint8_t> &data) const;
// Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
// data area of this QR Code. Function modules need to be marked off before this is called.
private: void drawCodewords(const std::vector<std::uint8_t> &data);
// XORs the codeword modules in this QR Code with the given mask pattern.
// The function modules must be marked and the codeword bits must be drawn
// before masking. Due to the arithmetic of XOR, calling applyMask() with
// the same mask value a second time will undo the mask. A final well-formed
// QR Code needs exactly one (not zero, two, etc.) mask applied.
private: void applyMask(int msk);
// Calculates and returns the penalty score based on state of this QR Code's current modules.
// This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
private: long getPenaltyScore() const;
/*---- Private helper functions ----*/
// Returns an ascending list of positions of alignment patterns for this version number.
// Each position is in the range [0,177), and are used on both the x and y axes.
// This could be implemented as lookup table of 40 variable-length lists of unsigned bytes.
private: std::vector<int> getAlignmentPatternPositions() const;
// Returns the number of data bits that can be stored in a QR Code of the given version number, after
// all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
// The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
private: static int getNumRawDataModules(int ver);
// Returns the number of 8-bit data (i.e. not error correction) codewords contained in any
// QR Code of the given version number and error correction level, with remainder bits discarded.
// This stateless pure function could be implemented as a (40*4)-cell lookup table.
private: static int getNumDataCodewords(int ver, Ecc ecl);
// Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be
// implemented as a lookup table over all possible parameter values, instead of as an algorithm.
private: static std::vector<std::uint8_t> reedSolomonComputeDivisor(int degree);
// Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials.
private: static std::vector<std::uint8_t> reedSolomonComputeRemainder(const std::vector<std::uint8_t> &data, const std::vector<std::uint8_t> &divisor);
// Returns the product of the two given field elements modulo GF(2^8/0x11D).
// All inputs are valid. This could be implemented as a 256*256 lookup table.
private: static std::uint8_t reedSolomonMultiply(std::uint8_t x, std::uint8_t y);
// Can only be called immediately after a light run is added, and
// returns either 0, 1, or 2. A helper function for getPenaltyScore().
private: int finderPenaltyCountPatterns(const std::array<int,7> &runHistory) const;
// Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore().
private: int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array<int,7> &runHistory) const;
// Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore().
private: void finderPenaltyAddHistory(int currentRunLength, std::array<int,7> &runHistory) const;
// Returns true iff the i'th bit of x is set to 1.
private: static bool getBit(long x, int i);
/*---- Constants and tables ----*/
// The minimum version number supported in the QR Code Model 2 standard.
public: static constexpr int MIN_VERSION = 1;
// The maximum version number supported in the QR Code Model 2 standard.
public: static constexpr int MAX_VERSION = 40;
// For use in getPenaltyScore(), when evaluating which mask is best.
private: static const int PENALTY_N1;
private: static const int PENALTY_N2;
private: static const int PENALTY_N3;
private: static const int PENALTY_N4;
private: static const std::int8_t ECC_CODEWORDS_PER_BLOCK[4][41];
private: static const std::int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41];
};
/*---- Public exception class ----*/
/*
* Thrown when the supplied data does not fit any QR Code version. Ways to handle this exception include:
* - Decrease the error correction level if it was greater than Ecc::LOW.
* - If the encodeSegments() function was called with a maxVersion argument, then increase
* it if it was less than QrCode::MAX_VERSION. (This advice does not apply to the other
* factory functions because they search all versions up to QrCode::MAX_VERSION.)
* - Split the text data into better or optimal segments in order to reduce the number of bits required.
* - Change the text or binary data to be shorter.
* - Change the text to fit the character set of a particular segment mode (e.g. alphanumeric).
* - Propagate the error upward to the caller/user.
*/
class data_too_long : public std::length_error {
public: explicit data_too_long(const std::string &msg);
};
/*
* An appendable sequence of bits (0s and 1s). Mainly used by QrSegment.
*/
class BitBuffer final : public std::vector<bool> {
/*---- Constructor ----*/
// Creates an empty bit buffer (length 0).
public: BitBuffer();
/*---- Method ----*/
// Appends the given number of low-order bits of the given value
// to this buffer. Requires 0 <= len <= 31 and val < 2^len.
public: void appendBits(std::uint32_t val, int len);
};
}
================================================
FILE: java/QrCodeGeneratorDemo.java
================================================
/*
* QR Code generator demo (Java)
*
* Run this command-line program with no arguments. The program creates/overwrites a bunch of
* PNG and SVG files in the current working directory to demonstrate the creation of QR Codes.
*
* Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* 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.
*/
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import javax.imageio.ImageIO;
import io.nayuki.qrcodegen.QrCode;
import io.nayuki.qrcodegen.QrSegment;
import io.nayuki.qrcodegen.QrSegmentAdvanced;
public final class QrCodeGeneratorDemo {
// The main application program.
public static void main(String[] args) throws IOException {
doBasicDemo();
doVarietyDemo();
doSegmentDemo();
doMaskDemo();
}
/*---- Demo suite ----*/
// Creates a single QR Code, then writes it to a PNG file and an SVG file.
private static void doBasicDemo() throws IOException {
String text = "Hello, world!"; // User-supplied Unicode text
QrCode.Ecc errCorLvl = QrCode.Ecc.LOW; // Error correction level
QrCode qr = QrCode.encodeText(text, errCorLvl); // Make the QR Code symbol
BufferedImage img = toImage(qr, 10, 4); // Convert to bitmap image
File imgFile = new File("hello-world-QR.png"); // File path for output
ImageIO.write(img, "png", imgFile); // Write image to file
String svg = toSvgString(qr, 4, "#FFFFFF", "#000000"); // Convert to SVG XML code
File svgFile = new File("hello-world-QR.svg"); // File path for output
Files.write(svgFile.toPath(), // Write image to file
svg.getBytes(StandardCharsets.UTF_8));
}
// Creates a variety of QR Codes that exercise different features of the library, and writes each one to file.
private static void doVarietyDemo() throws IOException {
QrCode qr;
// Numeric mode encoding (3.33 bits per digit)
qr = QrCode.encodeText("314159265358979323846264338327950288419716939937510", QrCode.Ecc.MEDIUM);
writePng(toImage(qr, 13, 1), "pi-digits-QR.png");
// Alphanumeric mode encoding (5.5 bits per character)
qr = QrCode.encodeText("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", QrCode.Ecc.HIGH);
writePng(toImage(qr, 10, 2), "alphanumeric-QR.png");
// Unicode text as UTF-8
qr = QrCode.encodeText("こんにちwa、世界! αβγδ", QrCode.Ecc.QUARTILE);
writePng(toImage(qr, 10, 3), "unicode-QR.png");
// Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland)
qr = QrCode.encodeText(
"Alice was beginning to get very tired of sitting by her sister on the bank, "
+ "and of having nothing to do: once or twice she had peeped into the book her sister was reading, "
+ "but it had no pictures or conversations in it, 'and what is the use of a book,' thought Alice "
+ "'without pictures or conversations?' So she was considering in her own mind (as well as she could, "
+ "for the hot day made her feel very sleepy and stupid), whether the pleasure of making a "
+ "daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly "
+ "a White Rabbit with pink eyes ran close by her.", QrCode.Ecc.HIGH);
writePng(toImage(qr, 6, 10), "alice-wonderland-QR.png");
}
// Creates QR Codes with manually specified segments for better compactness.
private static void doSegmentDemo() throws IOException {
QrCode qr;
List<QrSegment> segs;
// Illustration "silver"
String silver0 = "THE SQUARE ROOT OF 2 IS 1.";
String silver1 = "41421356237309504880168872420969807856967187537694807317667973799";
qr = QrCode.encodeText(silver0 + silver1, QrCode.Ecc.LOW);
writePng(toImage(qr, 10, 3), "sqrt2-monolithic-QR.png");
segs = Arrays.asList(
QrSegment.makeAlphanumeric(silver0),
QrSegment.makeNumeric(silver1));
qr = QrCode.encodeSegments(segs, QrCode.Ecc.LOW);
writePng(toImage(qr, 10, 3), "sqrt2-segmented-QR.png");
// Illustration "golden"
String golden0 = "Golden ratio φ = 1.";
String golden1 = "6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374";
String golden2 = "......";
qr = QrCode.encodeText(golden0 + golden1 + golden2, QrCode.Ecc.LOW);
writePng(toImage(qr, 8, 5), "phi-monolithic-QR.png");
segs = Arrays.asList(
QrSegment.makeBytes(golden0.getBytes(StandardCharsets.UTF_8)),
QrSegment.makeNumeric(golden1),
QrSegment.makeAlphanumeric(golden2));
qr = QrCode.encodeSegments(segs, QrCode.Ecc.LOW);
writePng(toImage(qr, 8, 5), "phi-segmented-QR.png");
// Illustration "Madoka": kanji, kana, Cyrillic, full-width Latin, Greek characters
String madoka = "「魔法少女まどか☆マギカ」って、 ИАИ desu κα?";
qr = QrCode.encodeText(madoka, QrCode.Ecc.LOW);
writePng(toImage(qr, 9, 4, 0xFFFFE0, 0x303080), "madoka-utf8-QR.png");
segs = Arrays.asList(QrSegmentAdvanced.makeKanji(madoka));
qr = QrCode.encodeSegments(segs, QrCode.Ecc.LOW);
writePng(toImage(qr, 9, 4, 0xE0F0FF, 0x404040), "madoka-kanji-QR.png");
}
// Creates QR Codes with the same size and contents but different mask patterns.
private static void doMaskDemo() throws IOException {
QrCode qr;
List<QrSegment> segs;
// Project Nayuki URL
segs = QrSegment.makeSegments("https://www.nayuki.io/");
qr = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, QrCode.MIN_VERSION, QrCode.MAX_VERSION, -1, true); // Automatic mask
writePng(toImage(qr, 8, 6, 0xE0FFE0, 0x206020), "project-nayuki-automask-QR.png");
qr = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 3, true); // Force mask 3
writePng(toImage(qr, 8, 6, 0xFFE0E0, 0x602020), "project-nayuki-mask3-QR.png");
// Chinese text as UTF-8
segs = QrSegment.makeSegments("維基百科(Wikipedia,聆聽i/ˌwɪkᵻˈpiːdi.ə/)是一個自由內容、公開編輯且多語言的網路百科全書協作計畫");
qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 0, true); // Force mask 0
writePng(toImage(qr, 10, 3), "unicode-mask0-QR.png");
qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 1, true); // Force mask 1
writePng(toImage(qr, 10, 3), "unicode-mask1-QR.png");
qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 5, true); // Force mask 5
writePng(toImage(qr, 10, 3), "unicode-mask5-QR.png");
qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 7, true); // Force mask 7
writePng(toImage(qr, 10, 3), "unicode-mask7-QR.png");
}
/*---- Utilities ----*/
private static BufferedImage toImage(QrCode qr, int scale, int border) {
return toImage(qr, scale, border, 0xFFFFFF, 0x000000);
}
/**
* Returns a raster image depicting the specified QR Code, with
* the specified module scale, border modules, and module colors.
* <p>For example, scale=10 and border=4 means to pad the QR Code with 4 light border
* modules on all four sides, and use 10×10 pixels to represent each module.
* @param qr the QR Code to render (not {@code null})
* @param scale the side length (measured in pixels, must be positive) of each module
* @param border the number of border modules to add, which must be non-negative
* @param lightColor the color to use for light modules, in 0xRRGGBB format
* @param darkColor the color to use for dark modules, in 0xRRGGBB format
* @return a new image representing the QR Code, with padding and scaling
* @throws NullPointerException if the QR Code is {@code null}
* @throws IllegalArgumentException if the scale or border is out of range, or if
* {scale, border, size} cause the image dimensions to exceed Integer.MAX_VALUE
*/
private static BufferedImage toImage(QrCode qr, int scale, int border, int lightColor, int darkColor) {
Objects.requireNonNull(qr);
if (scale <= 0 || border < 0)
throw new IllegalArgumentException("Value out of range");
if (border > Integer.MAX_VALUE / 2 || qr.size + border * 2L > Integer.MAX_VALUE / scale)
throw new IllegalArgumentException("Scale or border too large");
BufferedImage result = new BufferedImage((qr.size + border * 2) * scale, (qr.size + border * 2) * scale, BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < result.getHeight(); y++) {
for (int x = 0; x < result.getWidth(); x++) {
boolean color = qr.getModule(x / scale - border, y / scale - border);
result.setRGB(x, y, color ? darkColor : lightColor);
}
}
return result;
}
// Helper function to reduce code duplication.
private static void writePng(BufferedImage img, String filepath) throws IOException {
ImageIO.write(img, "png", new File(filepath));
}
/**
* Returns a string of SVG code for an image depicting the specified QR Code, with the specified
* number of border modules. The string always uses Unix newlines (\n), regardless of the platform.
* @param qr the QR Code to render (not {@code null})
* @param border the number of border modules to add, which must be non-negative
* @param lightColor the color to use for light modules, in any format supported by CSS, not {@code null}
* @param darkColor the color to use for dark modules, in any format supported by CSS, not {@code null}
* @return a string representing the QR Code as an SVG XML document
* @throws NullPointerException if any object is {@code null}
* @throws IllegalArgumentException if the border is negative
*/
private static String toSvgString(QrCode qr, int border, String lightColor, String darkColor) {
Objects.requireNonNull(qr);
Objects.requireNonNull(lightColor);
Objects.requireNonNull(darkColor);
if (border < 0)
throw new IllegalArgumentException("Border must be non-negative");
long brd = border;
StringBuilder sb = new StringBuilder()
.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
.append("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n")
.append(String.format("<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 %1$d %1$d\" stroke=\"none\">\n",
qr.size + brd * 2))
.append("\t<rect width=\"100%\" height=\"100%\" fill=\"" + lightColor + "\"/>\n")
.append("\t<path d=\"");
for (int y = 0; y < qr.size; y++) {
for (int x = 0; x < qr.size; x++) {
if (qr.getModule(x, y)) {
if (x != 0 || y != 0)
sb.append(" ");
sb.append(String.format("M%d,%dh1v1h-1z", x + brd, y + brd));
}
}
}
return sb
.append("\" fill=\"" + darkColor + "\"/>\n")
.append("</svg>\n")
.toString();
}
}
================================================
FILE: java/Readme.markdown
================================================
QR Code generator library - Java
================================
Introduction
------------
This project aims to be the best, clearest QR Code generator library. The primary goals are flexible options and absolute correctness. Secondary goals are compact implementation size and good documentation comments.
Home page with live JavaScript demo, extensive descriptions, and competitor comparisons: https://www.nayuki.io/page/qr-code-generator-library
Features
--------
Core features:
* Significantly shorter code but more documentation comments compared to competing libraries
* Supports encoding all 40 versions (sizes) and all 4 error correction levels, as per the QR Code Model 2 standard
* Output format: Raw modules/pixels of the QR symbol
* Detects finder-like penalty patterns more accurately than other implementations
* Encodes numeric and special-alphanumeric text in less space than general text
* Open-source code under the permissive MIT License
Manual parameters:
* User can specify minimum and maximum version numbers allowed, then library will automatically choose smallest version in the range that fits the data
* User can specify mask pattern manually, otherwise library will automatically evaluate all 8 masks and select the optimal one
* User can specify absolute error correction level, or allow the library to boost it if it doesn't increase the version number
* User can create a list of data segments manually and add ECI segments
Optional advanced features:
* Encodes Japanese Unicode text in kanji mode to save a lot of space compared to UTF-8 bytes
* Computes optimal segment mode switching for text with mixed numeric/alphanumeric/general/kanji parts
More information about QR Code technology and this library's design can be found on the project home page.
Examples
--------
```java
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.List;
import javax.imageio.ImageIO;
import io.nayuki.qrcodegen.*;
// Simple operation
QrCode qr0 = QrCode.encodeText("Hello, world!", QrCode.Ecc.MEDIUM);
BufferedImage img = toImage(qr0, 4, 10); // See QrCodeGeneratorDemo
ImageIO.write(img, "png", new File("qr-code.png"));
// Manual operation
List<QrSegment> segs = QrSegment.makeSegments("3141592653589793238462643383");
QrCode qr1 = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, 5, 5, 2, false);
for (int y = 0; y < qr1.size; y++) {
for (int x = 0; x < qr1.size; x++) {
(... paint qr1.getModule(x, y) ...)
}
}
```
More complete set of examples: https://github.com/nayuki/QR-Code-generator/blob/master/java/QrCodeGeneratorDemo.java .
================================================
FILE: java/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.nayuki</groupId>
<artifactId>qrcodegen</artifactId>
<version>1.8.0</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<executions>
<execution>
<id>default-compile</id>
<configuration>
<release>9</release>
</configuration>
</execution>
<execution>
<id>java8-compile</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<source>1.8</source>
<target>1.8</target>
<excludes>
<exclude>module-info.java</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<configuration>
<checkModificationExcludes>
<checkModificationExclude>java/pom.xml</checkModificationExclude>
</checkModificationExcludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<name>QR Code generator library</name>
<description>High quality QR Code generator library</description>
<url>https://www.nayuki.io/page/qr-code-generator-library</url>
<inceptionYear>2016</inceptionYear>
<licenses>
<license>
<name>The MIT License</name>
<url>https://opensource.org/licenses/MIT</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<name>Project Nayuki</name>
<email>me@nayuki.io</email>
<url>https://www.nayuki.io/</url>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/nayuki/QR-Code-generator.git</connection>
<developerConnection>scm:git:ssh://github.com:nayuki/QR-Code-generator.git</developerConnection>
<url>https://github.com/nayuki/QR-Code-generator/tree/master/java</url>
</scm>
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
</project>
================================================
FILE: java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java
================================================
/*
* QR Code generator library (Java)
*
* Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* 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.
*/
package io.nayuki.qrcodegen;
import java.util.BitSet;
import java.util.Objects;
/**
* An appendable sequence of bits (0s and 1s). Mainly used by {@link QrSegment}.
*/
public final class BitBuffer implements Cloneable {
/*---- Fields ----*/
private BitSet data;
private int bitLength; // Non-negative
/*---- Constructor ----*/
/**
* Constructs an empty bit buffer (length 0).
*/
public BitBuffer() {
data = new BitSet();
bitLength = 0;
}
/*---- Methods ----*/
/**
* Returns the length of this sequence, which is a non-negative value.
* @return the length of this sequence
*/
public int bitLength() {
assert bitLength >= 0;
return bitLength;
}
/**
* Returns the bit at the specified index, yielding 0 or 1.
* @param index the index to get the bit at
* @return the bit at the specified index
* @throws IndexOutOfBoundsException if index < 0 or index ≥ bitLength
*/
public int getBit(int index) {
if (index < 0 || index >= bitLength)
throw new IndexOutOfBoundsException();
return data.get(index) ? 1 : 0;
}
/**
* Appends the specified number of low-order bits of the specified value to this
* buffer. Requires 0 ≤ len ≤ 31 and 0 ≤ val < 2<sup>len</sup>.
* @param val the value to append
* @param len the number of low-order bits in the value to take
* @throws IllegalArgumentException if the value or number of bits is out of range
* @throws IllegalStateException if appending the data
* would make bitLength exceed Integer.MAX_VALUE
*/
public void appendBits(int val, int len) {
if (len < 0 || len > 31 || val >>> len != 0)
throw new IllegalArgumentException("Value out of range");
if (Integer.MAX_VALUE - bitLength < len)
throw new IllegalStateException("Maximum length reached");
for (int i = len - 1; i >= 0; i--, bitLength++) // Append bit by bit
data.set(bitLength, QrCode.getBit(val, i));
}
/**
* Appends the content of the specified bit buffer to this buffer.
* @param bb the bit buffer whose data to append (not {@code null})
* @throws NullPointerException if the bit buffer is {@code null}
* @throws IllegalStateException if appending the data
* would make bitLength exceed Integer.MAX_VALUE
*/
public void appendData(BitBuffer bb) {
Objects.requireNonNull(bb);
if (Integer.MAX_VALUE - bitLength < bb.bitLength)
throw new IllegalStateException("Maximum length reached");
for (int i = 0; i < bb.bitLength; i++, bitLength++) // Append bit by bit
data.set(bitLength, bb.data.get(i));
}
/**
* Returns a new copy of this buffer.
* @return a new copy of this buffer (not {@code null})
*/
public BitBuffer clone() {
try {
BitBuffer result = (BitBuffer)super.clone();
result.data = (BitSet)result.data.clone();
return result;
} catch (CloneNotSupportedException e) {
throw new AssertionError(e);
}
}
}
================================================
FILE: java/src/main/java/io/nayuki/qrcodegen/DataTooLongException.java
================================================
/*
* QR Code generator library (Java)
*
* Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* 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.
*/
package io.nayuki.qrcodegen;
/**
* Thrown when the supplied data does not fit any QR Code version. Ways to handle this exception include:
* <ul>
* <li><p>Decrease the error correction level if it was greater than {@code Ecc.LOW}.
gitextract_u8mpr9dd/
├── Readme.markdown
├── c/
│ ├── Makefile
│ ├── Readme.markdown
│ ├── qrcodegen-demo.c
│ ├── qrcodegen-test.c
│ ├── qrcodegen.c
│ └── qrcodegen.h
├── cpp/
│ ├── Makefile
│ ├── QrCodeGeneratorDemo.cpp
│ ├── Readme.markdown
│ ├── qrcodegen.cpp
│ └── qrcodegen.hpp
├── java/
│ ├── QrCodeGeneratorDemo.java
│ ├── Readme.markdown
│ ├── pom.xml
│ └── src/
│ └── main/
│ └── java/
│ ├── io/
│ │ └── nayuki/
│ │ └── qrcodegen/
│ │ ├── BitBuffer.java
│ │ ├── DataTooLongException.java
│ │ ├── QrCode.java
│ │ ├── QrSegment.java
│ │ ├── QrSegmentAdvanced.java
│ │ └── package-info.java
│ └── module-info.java
├── java-fast/
│ ├── Readme.markdown
│ └── io/
│ └── nayuki/
│ └── fastqrcodegen/
│ ├── BitBuffer.java
│ ├── DataTooLongException.java
│ ├── Memoizer.java
│ ├── QrCode.java
│ ├── QrCodeGeneratorDemo.java
│ ├── QrSegment.java
│ ├── QrSegmentAdvanced.java
│ ├── QrTemplate.java
│ ├── ReedSolomonGenerator.java
│ └── package-info.java
├── python/
│ ├── Readme.markdown
│ ├── qrcodegen-demo.py
│ ├── qrcodegen.py
│ └── setup.py
├── rust/
│ ├── Cargo.toml
│ ├── Readme.markdown
│ ├── examples/
│ │ └── qrcodegen-demo.rs
│ └── src/
│ └── lib.rs
├── rust-no-heap/
│ ├── Cargo.toml
│ ├── Readme.markdown
│ ├── examples/
│ │ └── qrcodegen-demo.rs
│ └── src/
│ └── lib.rs
└── typescript-javascript/
├── Readme.markdown
├── build.sh
├── qrcodegen-input-demo.html
├── qrcodegen-input-demo.ts
├── qrcodegen-output-demo.html
├── qrcodegen-output-demo.ts
└── qrcodegen.ts
SYMBOL INDEX (560 symbols across 31 files)
FILE: c/qrcodegen-demo.c
function main (line 44) | int main(void) {
function doBasicDemo (line 57) | static void doBasicDemo(void) {
function doVarietyDemo (line 72) | static void doVarietyDemo(void) {
function doSegmentDemo (line 122) | static void doSegmentDemo(void) {
function doMaskDemo (line 268) | static void doMaskDemo(void) {
function printQr (line 325) | static void printQr(const uint8_t qrcode[]) {
FILE: c/qrcodegen-test.c
type qrcodegen_Ecc (line 49) | enum qrcodegen_Ecc
type qrcodegen_Ecc (line 50) | enum qrcodegen_Ecc
type qrcodegen_Mode (line 60) | enum qrcodegen_Mode
type qrcodegen_Segment (line 61) | struct qrcodegen_Segment
function testAppendBitsToBuffer (line 66) | static void testAppendBitsToBuffer(void) {
type qrcodegen_Ecc (line 108) | enum qrcodegen_Ecc
function testAddEccAndInterleave (line 160) | static void testAddEccAndInterleave(void) {
function testGetNumDataCodewords (line 198) | static void testGetNumDataCodewords(void) {
function testGetNumRawDataModules (line 238) | static void testGetNumRawDataModules(void) {
function testReedSolomonComputeDivisor (line 262) | static void testReedSolomonComputeDivisor(void) {
function testReedSolomonComputeRemainder (line 295) | static void testReedSolomonComputeRemainder(void) {
function testReedSolomonMultiply (line 360) | static void testReedSolomonMultiply(void) {
function testInitializeFunctionModulesEtc (line 387) | static void testInitializeFunctionModulesEtc(void) {
function testGetAlignmentPatternPositions (line 422) | static void testGetAlignmentPatternPositions(void) {
function testGetSetModule (line 449) | static void testGetSetModule(void) {
function testGetSetModuleRandomly (line 496) | static void testGetSetModuleRandomly(void) {
function testIsAlphanumeric (line 529) | static void testIsAlphanumeric(void) {
function testIsNumeric (line 562) | static void testIsNumeric(void) {
function testCalcSegmentBufferSize (line 595) | static void testCalcSegmentBufferSize(void) {
function testCalcSegmentBitLength (line 723) | static void testCalcSegmentBitLength(void) {
function testMakeBytes (line 846) | static void testMakeBytes(void) {
function testMakeNumeric (line 877) | static void testMakeNumeric(void) {
function testMakeAlphanumeric (line 925) | static void testMakeAlphanumeric(void) {
function testMakeEci (line 963) | static void testMakeEci(void) {
function testGetTotalBits (line 995) | static void testGetTotalBits(void) {
function main (line 1078) | int main(void) {
FILE: c/qrcodegen.c
type qrcodegen_Ecc (line 57) | enum qrcodegen_Ecc
type qrcodegen_Ecc (line 58) | enum qrcodegen_Ecc
type qrcodegen_Ecc (line 68) | enum qrcodegen_Ecc
type qrcodegen_Mask (line 68) | enum qrcodegen_Mask
type qrcodegen_Mask (line 73) | enum qrcodegen_Mask
type qrcodegen_Mode (line 84) | enum qrcodegen_Mode
type qrcodegen_Segment (line 85) | struct qrcodegen_Segment
type qrcodegen_Mode (line 86) | enum qrcodegen_Mode
function qrcodegen_encodeText (line 132) | bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_...
function qrcodegen_encodeBinary (line 170) | bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8...
function testable (line 188) | testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t ...
function qrcodegen_encodeSegments (line 199) | bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], siz...
function qrcodegen_encodeSegmentsAdvanced (line 207) | bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment seg...
function testable (line 297) | testable void addEccAndInterleave(uint8_t data[], int version, enum qrco...
function testable (line 330) | testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl) {
function testable (line 342) | testable int getNumRawDataModules(int ver) {
function testable (line 361) | testable void reedSolomonComputeDivisor(int degree, uint8_t result[]) {
function testable (line 387) | testable void reedSolomonComputeRemainder(const uint8_t data[], int data...
function testable (line 405) | testable uint8_t reedSolomonMultiply(uint8_t x, uint8_t y) {
function testable (line 421) | testable void initializeFunctionModules(int version, uint8_t qrcode[]) {
function drawLightFunctionModules (line 458) | static void drawLightFunctionModules(uint8_t qrcode[], int version) {
function drawFormatBits (line 519) | static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask m...
function testable (line 553) | testable int getAlignmentPatternPositions(int version, uint8_t result[7]) {
function fillRectangle (line 566) | static void fillRectangle(int left, int top, int width, int height, uint...
function drawCodewords (line 579) | static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrc...
function applyMask (line 610) | static void applyMask(const uint8_t functionModules[], uint8_t qrcode[],...
function getPenaltyScore (line 638) | static long getPenaltyScore(const uint8_t qrcode[]) {
function finderPenaltyCountPatterns (line 718) | static int finderPenaltyCountPatterns(const int runHistory[7], int qrsiz...
function finderPenaltyTerminateAndCount (line 730) | static int finderPenaltyTerminateAndCount(bool currentRunColor, int curr...
function finderPenaltyAddHistory (line 742) | static void finderPenaltyAddHistory(int currentRunLength, int runHistory...
function qrcodegen_getSize (line 754) | int qrcodegen_getSize(const uint8_t qrcode[]) {
function qrcodegen_getModule (line 764) | bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y) {
function testable (line 772) | testable bool getModuleBounded(const uint8_t qrcode[], int x, int y) {
function testable (line 781) | testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isDa...
function testable (line 795) | testable void setModuleUnbounded(uint8_t qrcode[], int x, int y, bool is...
function getBit (line 803) | static bool getBit(int x, int i) {
function qrcodegen_isNumeric (line 812) | bool qrcodegen_isNumeric(const char *text) {
function qrcodegen_isAlphanumeric (line 823) | bool qrcodegen_isAlphanumeric(const char *text) {
function qrcodegen_calcSegmentBufferSize (line 834) | size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t ...
function testable (line 851) | testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numCh...
function qrcodegen_makeBytes (line 878) | struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_...
function qrcodegen_makeNumeric (line 893) | struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8...
function qrcodegen_makeAlphanumeric (line 927) | struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, ui...
function qrcodegen_makeEci (line 961) | struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]) {
function testable (line 990) | testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t ...
function numCharCountBits (line 1013) | static int numCharCountBits(enum qrcodegen_Mode mode, int version) {
FILE: c/qrcodegen.h
type qrcodegen_Ecc (line 57) | enum qrcodegen_Ecc {
type qrcodegen_Mask (line 70) | enum qrcodegen_Mask {
type qrcodegen_Mode (line 89) | enum qrcodegen_Mode {
type qrcodegen_Segment (line 109) | struct qrcodegen_Segment {
type qrcodegen_Ecc (line 188) | enum qrcodegen_Ecc
type qrcodegen_Mask (line 188) | enum qrcodegen_Mask
type qrcodegen_Ecc (line 227) | enum qrcodegen_Ecc
type qrcodegen_Mask (line 227) | enum qrcodegen_Mask
type qrcodegen_Segment (line 263) | struct qrcodegen_Segment
type qrcodegen_Ecc (line 264) | enum qrcodegen_Ecc
type qrcodegen_Segment (line 302) | struct qrcodegen_Segment
type qrcodegen_Ecc (line 302) | enum qrcodegen_Ecc
type qrcodegen_Mask (line 303) | enum qrcodegen_Mask
type qrcodegen_Mode (line 332) | enum qrcodegen_Mode
type qrcodegen_Segment (line 340) | struct qrcodegen_Segment
type qrcodegen_Segment (line 346) | struct qrcodegen_Segment
type qrcodegen_Segment (line 354) | struct qrcodegen_Segment
type qrcodegen_Segment (line 361) | struct qrcodegen_Segment
FILE: cpp/QrCodeGeneratorDemo.cpp
function main (line 52) | int main() {
function doBasicDemo (line 65) | static void doBasicDemo() {
function doVarietyDemo (line 77) | static void doVarietyDemo() {
function doSegmentDemo (line 105) | static void doSegmentDemo() {
function doMaskDemo (line 167) | static void doMaskDemo() {
function toSvgString (line 194) | static std::string toSvgString(const QrCode &qr, int border) {
function printQr (line 223) | static void printQr(const QrCode &qr) {
FILE: cpp/qrcodegen.cpp
type qrcodegen (line 40) | namespace qrcodegen {
function QrSegment (line 69) | QrSegment QrSegment::makeBytes(const vector<uint8_t> &data) {
function QrSegment (line 79) | QrSegment QrSegment::makeNumeric(const char *digits) {
function QrSegment (line 102) | QrSegment QrSegment::makeAlphanumeric(const char *text) {
function QrSegment (line 143) | QrSegment QrSegment::makeEci(long assignVal) {
function QrCode (line 247) | QrCode QrCode::encodeText(const char *text, Ecc ecl) {
function QrCode (line 253) | QrCode QrCode::encodeBinary(const vector<uint8_t> &data, Ecc ecl) {
function QrCode (line 259) | QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl,
FILE: cpp/qrcodegen.hpp
type qrcodegen (line 33) | namespace qrcodegen {
class QrSegment (line 46) | class QrSegment final {
class Mode (line 53) | class Mode final {
class QrCode (line 236) | class QrCode final {
type Ecc (line 243) | enum class Ecc {
class data_too_long (line 521) | class data_too_long : public std::length_error {
class BitBuffer (line 532) | class BitBuffer final : public std::vector<bool> {
FILE: java-fast/io/nayuki/fastqrcodegen/BitBuffer.java
class BitBuffer (line 31) | final class BitBuffer {
method BitBuffer (line 44) | public BitBuffer() {
method getBit (line 54) | public int getBit(int index) {
method getBytes (line 63) | public byte[] getBytes() {
method appendBits (line 75) | public void appendBits(int val, int len) {
method appendBits (line 102) | public void appendBits(int[] vals, int len) {
FILE: java-fast/io/nayuki/fastqrcodegen/DataTooLongException.java
class DataTooLongException (line 48) | public class DataTooLongException extends IllegalArgumentException {
method DataTooLongException (line 50) | public DataTooLongException() {}
method DataTooLongException (line 53) | public DataTooLongException(String msg) {
FILE: java-fast/io/nayuki/fastqrcodegen/Memoizer.java
class Memoizer (line 35) | final class Memoizer<T,R> {
method Memoizer (line 43) | public Memoizer(Function<T,R> func) {
method get (line 49) | public R get(T arg) {
FILE: java-fast/io/nayuki/fastqrcodegen/QrCode.java
class QrCode (line 52) | public final class QrCode {
method encodeText (line 69) | public static QrCode encodeText(String text, Ecc ecl) {
method encodeBinary (line 89) | public static QrCode encodeBinary(byte[] data, Ecc ecl) {
method encodeSegments (line 114) | public static QrCode encodeSegments(List<QrSegment> segs, Ecc ecl) {
method encodeSegments (line 143) | public static QrCode encodeSegments(List<QrSegment> segs, Ecc ecl, int...
method QrCode (line 238) | public QrCode(int ver, Ecc ecl, byte[] dataCodewords, int msk) {
method getModule (line 271) | public boolean getModule(int x, int y) {
method drawFormatBits (line 285) | private void drawFormatBits(int msk) {
method setModule (line 314) | private void setModule(int x, int y, int dark) {
method addEccAndInterleave (line 328) | private byte[] addEccAndInterleave(byte[] data) {
method drawCodewords (line 362) | private void drawCodewords(int[] dataOutputBitIndexes, byte[] allCodew...
method applyMask (line 380) | private void applyMask(int[] msk) {
method handleConstructorMasking (line 391) | private int handleConstructorMasking(int[][] masks, int msk) {
method getPenaltyScore (line 414) | private int getPenaltyScore() {
method getNumDataCodewords (line 492) | static int getNumDataCodewords(int ver, Ecc ecl) {
method finderPenaltyCountPatterns (line 501) | private int finderPenaltyCountPatterns(int[] runHistory) {
method finderPenaltyTerminateAndCount (line 511) | private int finderPenaltyTerminateAndCount(int currentRunColor, int cu...
method finderPenaltyAddHistory (line 523) | private void finderPenaltyAddHistory(int currentRunLength, int[] runHi...
method getBit (line 532) | static int getBit(int x, int i) {
type Ecc (line 578) | public enum Ecc {
method Ecc (line 590) | private Ecc(int fb) {
FILE: java-fast/io/nayuki/fastqrcodegen/QrCodeGeneratorDemo.java
class QrCodeGeneratorDemo (line 40) | public final class QrCodeGeneratorDemo {
method main (line 43) | public static void main(String[] args) throws IOException {
method doBasicDemo (line 55) | private static void doBasicDemo() throws IOException {
method doVarietyDemo (line 73) | private static void doVarietyDemo() throws IOException {
method doSegmentDemo (line 102) | private static void doSegmentDemo() throws IOException {
method doMaskDemo (line 144) | private static void doMaskDemo() throws IOException {
method toImage (line 171) | private static BufferedImage toImage(QrCode qr, int scale, int border) {
method toImage (line 191) | private static BufferedImage toImage(QrCode qr, int scale, int border,...
method writePng (line 210) | private static void writePng(BufferedImage img, String filepath) throw...
method toSvgString (line 226) | private static String toSvgString(QrCode qr, int border, String lightC...
FILE: java-fast/io/nayuki/fastqrcodegen/QrSegment.java
class QrSegment (line 46) | public final class QrSegment {
method makeBytes (line 59) | public static QrSegment makeBytes(byte[] data) {
method makeNumeric (line 77) | public static QrSegment makeNumeric(String digits) {
method makeAlphanumeric (line 109) | public static QrSegment makeAlphanumeric(String text) {
method makeSegments (line 139) | public static List<QrSegment> makeSegments(String text) {
method makeEci (line 162) | public static QrSegment makeEci(int assignVal) {
method isNumeric (line 188) | public static boolean isNumeric(String text) {
method isAlphanumeric (line 207) | public static boolean isAlphanumeric(String text) {
method QrSegment (line 248) | public QrSegment(Mode md, int numCh, int[] data, int bitLen) {
method getTotalBits (line 261) | static int getTotalBits(List<QrSegment> segs, int version) {
type Mode (line 299) | public enum Mode {
method Mode (line 321) | private Mode(int mode, int... ccbits) {
method numCharCountBits (line 331) | int numCharCountBits(int ver) {
FILE: java-fast/io/nayuki/fastqrcodegen/QrSegmentAdvanced.java
class QrSegmentAdvanced (line 41) | public final class QrSegmentAdvanced {
method makeSegmentsOptimally (line 63) | public static List<QrSegment> makeSegmentsOptimally(String text, QrCod...
method makeSegmentsOptimally (line 94) | private static List<QrSegment> makeSegmentsOptimally(int[] codePoints,...
method computeCharacterModes (line 103) | private static Mode[] computeCharacterModes(int[] codePoints, int vers...
method splitIntoSegments (line 186) | private static List<QrSegment> splitIntoSegments(int[] codePoints, Mod...
method toCodePoints (line 218) | private static int[] toCodePoints(String s) {
method countUtf8Bytes (line 229) | private static int countUtf8Bytes(int cp) {
method makeKanji (line 254) | public static QrSegment makeKanji(String text) {
method isEncodableAsKanji (line 278) | public static boolean isEncodableAsKanji(String text) {
method isKanji (line 285) | private static boolean isKanji(int c) {
method QrSegmentAdvanced (line 422) | private QrSegmentAdvanced() {}
FILE: java-fast/io/nayuki/fastqrcodegen/QrTemplate.java
class QrTemplate (line 29) | final class QrTemplate {
method QrTemplate (line 49) | private QrTemplate(int ver) {
method drawFunctionPatterns (line 65) | private void drawFunctionPatterns() {
method drawDummyFormatBits (line 95) | private void drawDummyFormatBits() {
method drawVersion (line 116) | private void drawVersion() {
method drawFinderPattern (line 140) | private void drawFinderPattern(int x, int y) {
method drawAlignmentPattern (line 154) | private void drawAlignmentPattern(int x, int y) {
method generateMasks (line 163) | private int[][] generateMasks() {
method generateZigzagScan (line 191) | private int[] generateZigzagScan() {
method getModule (line 215) | private int getModule(int[] grid, int x, int y) {
method darkenFunctionModule (line 225) | private void darkenFunctionModule(int x, int y, int enable) {
method getAlignmentPatternPositions (line 238) | private int[] getAlignmentPatternPositions() {
method getNumRawDataModules (line 256) | static int getNumRawDataModules(int ver) {
FILE: java-fast/io/nayuki/fastqrcodegen/ReedSolomonGenerator.java
class ReedSolomonGenerator (line 31) | final class ReedSolomonGenerator {
method ReedSolomonGenerator (line 44) | private ReedSolomonGenerator(int degree) {
method getRemainder (line 76) | public void getRemainder(byte[] data, int dataOff, int dataLen, byte[]...
method multiply (line 94) | private static int multiply(int x, int y) {
FILE: java/QrCodeGeneratorDemo.java
class QrCodeGeneratorDemo (line 41) | public final class QrCodeGeneratorDemo {
method main (line 44) | public static void main(String[] args) throws IOException {
method doBasicDemo (line 56) | private static void doBasicDemo() throws IOException {
method doVarietyDemo (line 74) | private static void doVarietyDemo() throws IOException {
method doSegmentDemo (line 103) | private static void doSegmentDemo() throws IOException {
method doMaskDemo (line 145) | private static void doMaskDemo() throws IOException {
method toImage (line 172) | private static BufferedImage toImage(QrCode qr, int scale, int border) {
method toImage (line 192) | private static BufferedImage toImage(QrCode qr, int scale, int border,...
method writePng (line 211) | private static void writePng(BufferedImage img, String filepath) throw...
method toSvgString (line 227) | private static String toSvgString(QrCode qr, int border, String lightC...
FILE: java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java
class BitBuffer (line 33) | public final class BitBuffer implements Cloneable {
method BitBuffer (line 48) | public BitBuffer() {
method bitLength (line 61) | public int bitLength() {
method getBit (line 73) | public int getBit(int index) {
method appendBits (line 89) | public void appendBits(int val, int len) {
method appendData (line 106) | public void appendData(BitBuffer bb) {
method clone (line 119) | public BitBuffer clone() {
FILE: java/src/main/java/io/nayuki/qrcodegen/DataTooLongException.java
class DataTooLongException (line 48) | public class DataTooLongException extends IllegalArgumentException {
method DataTooLongException (line 50) | public DataTooLongException() {}
method DataTooLongException (line 53) | public DataTooLongException(String msg) {
FILE: java/src/main/java/io/nayuki/qrcodegen/QrCode.java
class QrCode (line 52) | public final class QrCode {
method encodeText (line 69) | public static QrCode encodeText(CharSequence text, Ecc ecl) {
method encodeBinary (line 89) | public static QrCode encodeBinary(byte[] data, Ecc ecl) {
method encodeSegments (line 114) | public static QrCode encodeSegments(List<QrSegment> segs, Ecc ecl) {
method encodeSegments (line 143) | public static QrCode encodeSegments(List<QrSegment> segs, Ecc ecl, int...
method QrCode (line 248) | public QrCode(int ver, Ecc ecl, byte[] dataCodewords, int msk) {
method getModule (line 301) | public boolean getModule(int x, int y) {
method drawFunctionPatterns (line 310) | private void drawFunctionPatterns() {
method drawFormatBits (line 341) | private void drawFormatBits(int msk) {
method drawVersion (line 370) | private void drawVersion() {
method drawFinderPattern (line 394) | private void drawFinderPattern(int x, int y) {
method drawAlignmentPattern (line 408) | private void drawAlignmentPattern(int x, int y) {
method setFunctionModule (line 418) | private void setFunctionModule(int x, int y, boolean isDark) {
method addEccAndInterleave (line 428) | private byte[] addEccAndInterleave(byte[] data) {
method drawCodewords (line 469) | private void drawCodewords(byte[] data) {
method applyMask (line 502) | private void applyMask(int msk) {
method getPenaltyScore (line 527) | private int getPenaltyScore() {
method getAlignmentPatternPositions (line 610) | private int[] getAlignmentPatternPositions() {
method getNumRawDataModules (line 628) | private static int getNumRawDataModules(int ver) {
method reedSolomonComputeDivisor (line 653) | private static byte[] reedSolomonComputeDivisor(int degree) {
method reedSolomonComputeRemainder (line 679) | private static byte[] reedSolomonComputeRemainder(byte[] data, byte[] ...
method reedSolomonMultiply (line 696) | private static int reedSolomonMultiply(int x, int y) {
method getNumDataCodewords (line 712) | static int getNumDataCodewords(int ver, Ecc ecl) {
method finderPenaltyCountPatterns (line 721) | private int finderPenaltyCountPatterns(int[] runHistory) {
method finderPenaltyTerminateAndCount (line 731) | private int finderPenaltyTerminateAndCount(boolean currentRunColor, in...
method finderPenaltyAddHistory (line 743) | private void finderPenaltyAddHistory(int currentRunLength, int[] runHi...
method getBit (line 752) | static boolean getBit(int x, int i) {
type Ecc (line 798) | public enum Ecc {
method Ecc (line 810) | private Ecc(int fb) {
FILE: java/src/main/java/io/nayuki/qrcodegen/QrSegment.java
class QrSegment (line 46) | public final class QrSegment {
method makeBytes (line 59) | public static QrSegment makeBytes(byte[] data) {
method makeNumeric (line 75) | public static QrSegment makeNumeric(CharSequence digits) {
method makeAlphanumeric (line 99) | public static QrSegment makeAlphanumeric(CharSequence text) {
method makeSegments (line 124) | public static List<QrSegment> makeSegments(CharSequence text) {
method makeEci (line 147) | public static QrSegment makeEci(int assignVal) {
method isNumeric (line 173) | public static boolean isNumeric(CharSequence text) {
method isAlphanumeric (line 187) | public static boolean isAlphanumeric(CharSequence text) {
method QrSegment (line 219) | public QrSegment(Mode md, int numCh, BitBuffer data) {
method getData (line 235) | public BitBuffer getData() {
method getTotalBits (line 243) | static int getTotalBits(List<QrSegment> segs, int version) {
type Mode (line 278) | public enum Mode {
method Mode (line 300) | private Mode(int mode, int... ccbits) {
method numCharCountBits (line 310) | int numCharCountBits(int ver) {
FILE: java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java
class QrSegmentAdvanced (line 41) | public final class QrSegmentAdvanced {
method makeSegmentsOptimally (line 63) | public static List<QrSegment> makeSegmentsOptimally(CharSequence text,...
method makeSegmentsOptimally (line 94) | private static List<QrSegment> makeSegmentsOptimally(int[] codePoints,...
method computeCharacterModes (line 103) | private static Mode[] computeCharacterModes(int[] codePoints, int vers...
method splitIntoSegments (line 194) | private static List<QrSegment> splitIntoSegments(int[] codePoints, Mod...
method toCodePoints (line 226) | private static int[] toCodePoints(CharSequence s) {
method countUtf8Bytes (line 237) | private static int countUtf8Bytes(int cp) {
method makeKanji (line 262) | public static QrSegment makeKanji(CharSequence text) {
method isEncodableAsKanji (line 286) | public static boolean isEncodableAsKanji(CharSequence text) {
method isKanji (line 293) | private static boolean isKanji(int c) {
method QrSegmentAdvanced (line 430) | private QrSegmentAdvanced() {}
FILE: python/qrcodegen-demo.py
function main (line 31) | def main() -> None:
function do_basic_demo (line 42) | def do_basic_demo() -> None:
function do_variety_demo (line 53) | def do_variety_demo() -> None:
function do_segment_demo (line 80) | def do_segment_demo() -> None:
function do_mask_demo (line 150) | def do_mask_demo() -> None:
function to_svg_str (line 174) | def to_svg_str(qr: QrCode, border: int) -> str:
function print_qr (line 193) | def print_qr(qrcode: QrCode) -> None:
FILE: python/qrcodegen.py
class QrCode (line 32) | class QrCode:
method encode_text (line 51) | def encode_text(text: str, ecl: QrCode.Ecc) -> QrCode:
method encode_binary (line 62) | def encode_binary(data: Union[bytes,Sequence[int]], ecl: QrCode.Ecc) -...
method encode_segments (line 73) | def encode_segments(segs: Sequence[QrSegment], ecl: QrCode.Ecc, minver...
method __init__ (line 163) | def __init__(self, version: int, errcorlvl: QrCode.Ecc, datacodewords:...
method get_version (line 209) | def get_version(self) -> int:
method get_size (line 213) | def get_size(self) -> int:
method get_error_correction_level (line 217) | def get_error_correction_level(self) -> QrCode.Ecc:
method get_mask (line 221) | def get_mask(self) -> int:
method get_module (line 225) | def get_module(self, x: int, y: int) -> bool:
method _draw_function_patterns (line 234) | def _draw_function_patterns(self) -> None:
method _draw_format_bits (line 260) | def _draw_format_bits(self, mask: int) -> None:
method _draw_version (line 288) | def _draw_version(self) -> None:
method _draw_finder_pattern (line 310) | def _draw_finder_pattern(self, x: int, y: int) -> None:
method _draw_alignment_pattern (line 321) | def _draw_alignment_pattern(self, x: int, y: int) -> None:
method _set_function_module (line 329) | def _set_function_module(self, x: int, y: int, isdark: bool) -> None:
method _add_ecc_and_interleave (line 339) | def _add_ecc_and_interleave(self, data: bytearray) -> bytes:
method _draw_codewords (line 376) | def _draw_codewords(self, data: bytes) -> None:
method _apply_mask (line 399) | def _apply_mask(self, mask: int) -> None:
method _get_penalty_score (line 413) | def _get_penalty_score(self) -> int:
method _get_alignment_pattern_positions (line 478) | def _get_alignment_pattern_positions(self) -> list[int]:
method _get_num_raw_data_modules (line 492) | def _get_num_raw_data_modules(ver: int) -> int:
method _get_num_data_codewords (line 509) | def _get_num_data_codewords(ver: int, ecl: QrCode.Ecc) -> int:
method _reed_solomon_compute_divisor (line 519) | def _reed_solomon_compute_divisor(degree: int) -> bytes:
method _reed_solomon_compute_remainder (line 543) | def _reed_solomon_compute_remainder(data: bytes, divisor: bytes) -> by...
method _reed_solomon_multiply (line 555) | def _reed_solomon_multiply(x: int, y: int) -> int:
method _finder_penalty_count_patterns (line 569) | def _finder_penalty_count_patterns(self, runhistory: collections.deque...
method _finder_penalty_terminate_and_count (line 579) | def _finder_penalty_terminate_and_count(self, currentruncolor: bool, c...
method _finder_penalty_add_history (line 589) | def _finder_penalty_add_history(self, currentrunlength: int, runhistor...
class Ecc (line 636) | class Ecc:
method __init__ (line 642) | def __init__(self, i: int, fb: int) -> None:
class QrSegment (line 662) | class QrSegment:
method make_bytes (line 676) | def make_bytes(data: Union[bytes,Sequence[int]]) -> QrSegment:
method make_numeric (line 687) | def make_numeric(digits: str) -> QrSegment:
method make_alphanumeric (line 701) | def make_alphanumeric(text: str) -> QrSegment:
method make_segments (line 718) | def make_segments(text: str) -> list[QrSegment]:
method make_eci (line 734) | def make_eci(assignval: int) -> QrSegment:
method is_numeric (line 756) | def is_numeric(text: str) -> bool:
method is_alphanumeric (line 764) | def is_alphanumeric(text: str) -> bool:
method __init__ (line 785) | def __init__(self, mode: QrSegment.Mode, numch: int, bitdata: Sequence...
method get_mode (line 798) | def get_mode(self) -> QrSegment.Mode:
method get_num_chars (line 802) | def get_num_chars(self) -> int:
method get_data (line 806) | def get_data(self) -> list[int]:
method get_total_bits (line 813) | def get_total_bits(segs: Sequence[QrSegment], version: int) -> Optiona...
class Mode (line 840) | class Mode:
method __init__ (line 847) | def __init__(self, modebits: int, charcounts: tuple[int,int,int]):
method get_mode_bits (line 852) | def get_mode_bits(self) -> int:
method num_char_count_bits (line 857) | def num_char_count_bits(self, ver: int) -> int:
class _BitBuffer (line 880) | class _BitBuffer(list[int]):
method append_bits (line 883) | def append_bits(self, val: int, n: int) -> None:
function _get_bit (line 891) | def _get_bit(x: int, i: int) -> bool:
class DataTooLongError (line 897) | class DataTooLongError(ValueError):
FILE: rust-no-heap/examples/qrcodegen-demo.rs
function main (line 37) | fn main() {
function do_basic_demo (line 49) | fn do_basic_demo() {
function do_variety_demo (line 66) | fn do_variety_demo() {
function do_segment_demo (line 110) | fn do_segment_demo() {
function do_mask_demo (line 189) | fn do_mask_demo() {
function to_svg_string (line 230) | fn to_svg_string(qr: &QrCode, border: i32) -> String {
function print_qr (line 257) | fn print_qr(qr: &QrCode) {
FILE: rust-no-heap/src/lib.rs
type QrCode (line 118) | pub struct QrCode<'a> {
function encode_text (line 164) | pub fn encode_text<'b>(text: &str, tempbuffer: &'b mut [u8], mut outbuff...
function encode_binary (line 220) | pub fn encode_binary<'b>(dataandtempbuffer: &'b mut [u8], datalen: usize...
function encode_segments_to_codewords (line 250) | pub fn encode_segments_to_codewords(segs: &[QrSegment], outbuffer: &'a m...
function encode_codewords (line 319) | pub fn encode_codewords<'b>(mut datacodewordsandoutbuffer: &'a mut [u8],...
function version (line 362) | pub fn version(&self) -> Version {
function size (line 368) | pub fn size(&self) -> i32 {
function error_correction_level (line 374) | pub fn error_correction_level(&self) -> QrCodeEcc {
function mask (line 384) | pub fn mask(&self) -> Mask {
function get_module (line 397) | pub fn get_module(&self, x: i32, y: i32) -> bool {
function get_module_bounded (line 404) | fn get_module_bounded(&self, x: u8, y: u8) -> bool {
function set_module_unbounded (line 415) | fn set_module_unbounded(&mut self, x: i32, y: i32, isdark: bool) {
function set_module_bounded (line 424) | fn set_module_bounded(&mut self, x: u8, y: u8, isdark: bool) {
function add_ecc_and_interleave (line 443) | fn add_ecc_and_interleave<'b>(data: &[u8], ver: Version, ecl: QrCodeEcc,...
function function_modules_marked (line 486) | fn function_modules_marked(outbuffer: &'a mut [u8], ver: Version) -> Self {
function draw_light_function_modules (line 531) | fn draw_light_function_modules(&mut self) {
function draw_format_bits (line 595) | fn draw_format_bits(&mut self, ecl: QrCodeEcc, mask: Mask) {
function fill_rectangle (line 632) | fn fill_rectangle(&mut self, left: u8, top: u8, width: u8, height: u8) {
function draw_codewords (line 645) | fn draw_codewords(&mut self, data: &[u8]) {
function apply_mask (line 680) | fn apply_mask(&mut self, functionmodules: &QrCode, mask: Mask) {
function get_penalty_score (line 710) | fn get_penalty_score(&self) -> i32 {
function get_alignment_pattern_positions (line 793) | fn get_alignment_pattern_positions<'b>(&self, resultbuf: &'b mut [u8; 7]...
function get_num_raw_data_modules (line 815) | fn get_num_raw_data_modules(ver: Version) -> usize {
function get_num_data_codewords (line 833) | fn get_num_data_codewords(ver: Version, ecl: QrCodeEcc) -> usize {
function table_get (line 841) | fn table_get(table: &'static [[i8; 41]; 4], ver: Version, ecl: QrCodeEcc...
method eq (line 849) | fn eq(&self, other: &QrCode<'_>) -> bool{
type ReedSolomonGenerator (line 860) | struct ReedSolomonGenerator {
method new (line 876) | fn new(degree: usize) -> Self {
method compute_remainder (line 904) | fn compute_remainder(&self, data: &[u8], result: &mut [u8]) {
method multiply (line 920) | fn multiply(x: u8, y: u8) -> u8 {
type FinderPenalty (line 935) | struct FinderPenalty {
method new (line 943) | pub fn new(size: u8) -> Self {
method add_history (line 952) | pub fn add_history(&mut self, mut currentrunlength: i32) {
method count_patterns (line 963) | pub fn count_patterns(&self) -> i32 {
method terminate_and_count (line 975) | pub fn terminate_and_count(mut self, currentruncolor: bool, mut curren...
constant PENALTY_N1 (line 991) | const PENALTY_N1: i32 = 3;
constant PENALTY_N2 (line 992) | const PENALTY_N2: i32 = 3;
constant PENALTY_N3 (line 993) | const PENALTY_N3: i32 = 40;
constant PENALTY_N4 (line 994) | const PENALTY_N4: i32 = 10;
type QrCodeEcc (line 1021) | pub enum QrCodeEcc {
method ordinal (line 1036) | fn ordinal(self) -> usize {
method format_bits (line 1048) | fn format_bits(self) -> u8 {
type QrSegment (line 1076) | pub struct QrSegment<'a> {
function make_bytes (line 1105) | pub fn make_bytes(data: &'a [u8]) -> Self {
function make_numeric (line 1113) | pub fn make_numeric(text: &str, buf: &'a mut [u8]) -> Self {
function make_alphanumeric (line 1131) | pub fn make_alphanumeric(text: &str, buf: &'a mut [u8]) -> Self {
function make_eci (line 1144) | pub fn make_eci(assignval: u32, buf: &'a mut [u8]) -> Self {
function new (line 1167) | pub fn new(mode: QrSegmentMode, numchars: usize, data: &'a [u8], bitleng...
function mode (line 1176) | pub fn mode(&self) -> QrSegmentMode {
function num_chars (line 1182) | pub fn num_chars(&self) -> usize {
function calc_buffer_size (line 1197) | pub fn calc_buffer_size(mode: QrSegmentMode, numchars: usize) -> Option<...
function calc_bit_length (line 1209) | fn calc_bit_length(mode: QrSegmentMode, numchars: usize) -> Option<usize> {
function get_total_bits (line 1234) | fn get_total_bits(segs: &[Self], version: Version) -> Option<usize> {
function is_numeric (line 1253) | pub fn is_numeric(text: &str) -> bool {
function is_alphanumeric (line 1261) | pub fn is_alphanumeric(text: &str) -> bool {
type QrSegmentMode (line 1278) | pub enum QrSegmentMode {
method mode_bits (line 1291) | fn mode_bits(self) -> u32 {
method num_char_count_bits (line 1305) | fn num_char_count_bits(self, ver: Version) -> u8 {
type BitBuffer (line 1324) | pub struct BitBuffer<'a> {
function new (line 1336) | pub fn new(buffer: &'a mut [u8]) -> Self {
function len (line 1345) | pub fn len(&self) -> usize {
function append_bits (line 1352) | pub fn append_bits(&mut self, val: u32, len: u8) {
type DataTooLong (line 1385) | pub enum DataTooLong {
method fmt (line 1391) | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
type Version (line 1403) | pub struct Version(u8);
constant MIN (line 1407) | pub const MIN: Version = Version( 1);
constant MAX (line 1410) | pub const MAX: Version = Version(40);
method new (line 1415) | pub const fn new(ver: u8) -> Self {
method value (line 1421) | pub const fn value(self) -> u8 {
method buffer_len (line 1427) | pub const fn buffer_len(self) -> usize {
type Mask (line 1436) | pub struct Mask(u8);
method new (line 1442) | pub const fn new(mask: u8) -> Self {
method value (line 1448) | pub const fn value(self) -> u8 {
function get_bit (line 1455) | fn get_bit(x: u32, i: u8) -> bool {
FILE: rust/examples/qrcodegen-demo.rs
function main (line 36) | fn main() {
function do_basic_demo (line 48) | fn do_basic_demo() {
function do_variety_demo (line 60) | fn do_variety_demo() {
function do_segment_demo (line 87) | fn do_segment_demo() {
function do_mask_demo (line 142) | fn do_mask_demo() {
function to_svg_string (line 169) | fn to_svg_string(qr: &QrCode, border: i32) -> String {
function print_qr (line 196) | fn print_qr(qr: &QrCode) {
FILE: rust/src/lib.rs
type QrCode (line 114) | pub struct QrCode {
method encode_text (line 159) | pub fn encode_text(text: &str, ecl: QrCodeEcc) -> Result<Self,DataTooL...
method encode_binary (line 173) | pub fn encode_binary(data: &[u8], ecl: QrCodeEcc) -> Result<Self,DataT...
method encode_segments (line 192) | pub fn encode_segments(segs: &[QrSegment], ecl: QrCodeEcc) -> Result<S...
method encode_segments_advanced (line 211) | pub fn encode_segments_advanced(segs: &[QrSegment], mut ecl: QrCodeEcc,
method encode_codewords (line 285) | pub fn encode_codewords(ver: Version, ecl: QrCodeEcc, datacodewords: &...
method version (line 331) | pub fn version(&self) -> Version {
method size (line 337) | pub fn size(&self) -> i32 {
method error_correction_level (line 343) | pub fn error_correction_level(&self) -> QrCodeEcc {
method mask (line 349) | pub fn mask(&self) -> Mask {
method get_module (line 359) | pub fn get_module(&self, x: i32, y: i32) -> bool {
method module (line 365) | fn module(&self, x: i32, y: i32) -> bool {
method module_mut (line 371) | fn module_mut(&mut self, x: i32, y: i32) -> &mut bool {
method draw_function_patterns (line 379) | fn draw_function_patterns(&mut self) {
method draw_format_bits (line 412) | fn draw_format_bits(&mut self, mask: Mask) {
method draw_version (line 450) | fn draw_version(&mut self) {
method draw_finder_pattern (line 479) | fn draw_finder_pattern(&mut self, x: i32, y: i32) {
method draw_alignment_pattern (line 495) | fn draw_alignment_pattern(&mut self, x: i32, y: i32) {
method set_function_module (line 506) | fn set_function_module(&mut self, x: i32, y: i32, isdark: bool) {
method add_ecc_and_interleave (line 516) | fn add_ecc_and_interleave(&self, data: &[u8]) -> Vec<u8> {
method draw_codewords (line 560) | fn draw_codewords(&mut self, data: &[u8]) {
method apply_mask (line 594) | fn apply_mask(&mut self, mask: Mask) {
method get_penalty_score (line 616) | fn get_penalty_score(&self) -> i32 {
method get_alignment_pattern_positions (line 698) | fn get_alignment_pattern_positions(&self) -> Vec<i32> {
method get_num_raw_data_modules (line 717) | fn get_num_raw_data_modules(ver: Version) -> usize {
method get_num_data_codewords (line 735) | fn get_num_data_codewords(ver: Version, ecl: QrCodeEcc) -> usize {
method table_get (line 743) | fn table_get(table: &'static [[i8; 41]; 4], ver: Version, ecl: QrCodeE...
method reed_solomon_compute_divisor (line 750) | fn reed_solomon_compute_divisor(degree: usize) -> Vec<u8> {
method reed_solomon_compute_remainder (line 776) | fn reed_solomon_compute_remainder(data: &[u8], divisor: &[u8]) -> Vec<...
method reed_solomon_multiply (line 791) | fn reed_solomon_multiply(x: u8, y: u8) -> u8 {
type FinderPenalty (line 806) | struct FinderPenalty {
method new (line 814) | pub fn new(size: i32) -> Self {
method add_history (line 823) | pub fn add_history(&mut self, mut currentrunlength: i32) {
method count_patterns (line 836) | pub fn count_patterns(&self) -> i32 {
method terminate_and_count (line 848) | pub fn terminate_and_count(mut self, currentruncolor: bool, mut curren...
constant PENALTY_N1 (line 864) | const PENALTY_N1: i32 = 3;
constant PENALTY_N2 (line 865) | const PENALTY_N2: i32 = 3;
constant PENALTY_N3 (line 866) | const PENALTY_N3: i32 = 40;
constant PENALTY_N4 (line 867) | const PENALTY_N4: i32 = 10;
type QrCodeEcc (line 894) | pub enum QrCodeEcc {
method ordinal (line 909) | fn ordinal(self) -> usize {
method format_bits (line 921) | fn format_bits(self) -> u8 {
type QrSegment (line 950) | pub struct QrSegment {
method make_bytes (line 975) | pub fn make_bytes(data: &[u8]) -> Self {
method make_numeric (line 987) | pub fn make_numeric(text: &str) -> Self {
method make_alphanumeric (line 1006) | pub fn make_alphanumeric(text: &str) -> Self {
method make_segments (line 1022) | pub fn make_segments(text: &str) -> Vec<Self> {
method make_eci (line 1041) | pub fn make_eci(assignval: u32) -> Self {
method new (line 1064) | pub fn new(mode: QrSegmentMode, numchars: usize, data: Vec<bool>) -> S...
method mode (line 1072) | pub fn mode(&self) -> QrSegmentMode {
method num_chars (line 1078) | pub fn num_chars(&self) -> usize {
method data (line 1084) | pub fn data(&self) -> &Vec<bool> {
method get_total_bits (line 1094) | fn get_total_bits(segs: &[Self], version: Version) -> Option<usize> {
method is_numeric (line 1114) | pub fn is_numeric(text: &str) -> bool {
method is_alphanumeric (line 1123) | pub fn is_alphanumeric(text: &str) -> bool {
type QrSegmentMode (line 1140) | pub enum QrSegmentMode {
method mode_bits (line 1153) | fn mode_bits(self) -> u32 {
method num_char_count_bits (line 1167) | fn num_char_count_bits(self, ver: Version) -> u8 {
type BitBuffer (line 1187) | pub struct BitBuffer(pub Vec<bool>);
method append_bits (line 1194) | pub fn append_bits(&mut self, val: u32, len: u8) {
type DataTooLong (line 1217) | pub enum DataTooLong {
method fmt (line 1225) | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
type Version (line 1237) | pub struct Version(u8);
constant MIN (line 1241) | pub const MIN: Version = Version( 1);
constant MAX (line 1244) | pub const MAX: Version = Version(40);
method new (line 1249) | pub const fn new(ver: u8) -> Self {
method value (line 1255) | pub const fn value(self) -> u8 {
type Mask (line 1263) | pub struct Mask(u8);
method new (line 1269) | pub const fn new(mask: u8) -> Self {
method value (line 1275) | pub const fn value(self) -> u8 {
function get_bit (line 1282) | fn get_bit(x: u32, i: i32) -> bool {
FILE: typescript-javascript/qrcodegen-input-demo.ts
function initialize (line 29) | function initialize(): void {
function redrawQrCode (line 44) | function redrawQrCode(): void {
function drawCanvas (line 148) | function drawCanvas(qr: qrcodegen.QrCode, scale: number, border: number,...
function toSvgString (line 166) | function toSvgString(qr: qrcodegen.QrCode, border: number, lightColor: s...
function handleVersionMinMax (line 186) | function handleVersionMinMax(which: "min"|"max"): void {
function getElem (line 203) | function getElem(id: string): HTMLElement {
function getInput (line 211) | function getInput(id: string): HTMLInputElement {
FILE: typescript-javascript/qrcodegen-output-demo.ts
function main (line 33) | function main(): void {
function doBasicDemo (line 44) | function doBasicDemo(): void {
function doVarietyDemo (line 54) | function doVarietyDemo(): void {
function doSegmentDemo (line 85) | function doSegmentDemo(): void {
function doMaskDemo (line 161) | function doMaskDemo(): void {
function appendHeading (line 188) | function appendHeading(text: string): void {
function appendCanvas (line 194) | function appendCanvas(caption: string): HTMLCanvasElement {
function drawCanvas (line 207) | function drawCanvas(qr: qrcodegen.QrCode, scale: number, border: number,...
function toUtf8ByteArray (line 223) | function toUtf8ByteArray(str: string): Array<number> {
FILE: typescript-javascript/qrcodegen.ts
type bit (line 29) | type bit = number;
type byte (line 30) | type byte = number;
type int (line 31) | type int = number;
class QrCode (line 52) | class QrCode {
method encodeText (line 61) | public static encodeText(text: string, ecl: QrCode.Ecc): QrCode {
method encodeBinary (line 71) | public static encodeBinary(data: Readonly<Array<byte>>, ecl: QrCode.Ec...
method encodeSegments (line 88) | public static encodeSegments(segs: Readonly<Array<QrSegment>>, ecl: Qr...
method constructor (line 174) | public constructor(
method getModule (line 235) | public getModule(x: int, y: int): boolean {
method drawFunctionPatterns (line 243) | private drawFunctionPatterns(): void {
method drawFormatBits (line 274) | private drawFormatBits(mask: int): void {
method drawVersion (line 303) | private drawVersion(): void {
method drawFinderPattern (line 327) | private drawFinderPattern(x: int, y: int): void {
method drawAlignmentPattern (line 342) | private drawAlignmentPattern(x: int, y: int): void {
method setFunctionModule (line 352) | private setFunctionModule(x: int, y: int, isDark: boolean): void {
method addEccAndInterleave (line 362) | private addEccAndInterleave(data: Readonly<Array<byte>>): Array<byte> {
method drawCodewords (line 403) | private drawCodewords(data: Readonly<Array<byte>>): void {
method applyMask (line 434) | private applyMask(mask: int): void {
method getPenaltyScore (line 460) | private getPenaltyScore(): int {
method getAlignmentPatternPositions (line 538) | private getAlignmentPatternPositions(): Array<int> {
method getNumRawDataModules (line 555) | private static getNumRawDataModules(ver: int): int {
method getNumDataCodewords (line 573) | private static getNumDataCodewords(ver: int, ecl: QrCode.Ecc): int {
method reedSolomonComputeDivisor (line 582) | private static reedSolomonComputeDivisor(degree: int): Array<byte> {
method reedSolomonComputeRemainder (line 610) | private static reedSolomonComputeRemainder(data: Readonly<Array<byte>>...
method reedSolomonMultiply (line 624) | private static reedSolomonMultiply(x: byte, y: byte): byte {
method finderPenaltyCountPatterns (line 640) | private finderPenaltyCountPatterns(runHistory: Readonly<Array<int>>): ...
method finderPenaltyTerminateAndCount (line 650) | private finderPenaltyTerminateAndCount(currentRunColor: boolean, curre...
method finderPenaltyAddHistory (line 662) | private finderPenaltyAddHistory(currentRunLength: int, runHistory: Arr...
function appendBits (line 706) | function appendBits(val: int, len: int, bb: Array<bit>): void {
function getBit (line 715) | function getBit(x: int, i: int): boolean {
function assert (line 721) | function assert(cond: boolean): void {
class QrSegment (line 741) | class QrSegment {
method makeBytes (line 748) | public static makeBytes(data: Readonly<Array<byte>>): QrSegment {
method makeNumeric (line 757) | public static makeNumeric(digits: string): QrSegment {
method makeAlphanumeric (line 773) | public static makeAlphanumeric(text: string): QrSegment {
method makeSegments (line 791) | public static makeSegments(text: string): Array<QrSegment> {
method makeEci (line 806) | public static makeEci(assignVal: int): QrSegment {
method isNumeric (line 826) | public static isNumeric(text: string): boolean {
method isAlphanumeric (line 834) | public static isAlphanumeric(text: string): boolean {
method constructor (line 844) | public constructor(
method getData (line 865) | public getData(): Array<bit> {
method getTotalBits (line 872) | public static getTotalBits(segs: Readonly<Array<QrSegment>>, version: ...
method toUtf8ByteArray (line 885) | private static toUtf8ByteArray(str: string): Array<byte> {
type int (line 922) | type int = number;
class Ecc (line 928) | class Ecc {
method constructor (line 940) | private constructor(
type int (line 955) | type int = number;
class Mode (line 961) | class Mode {
method constructor (line 974) | private constructor(
method numCharCountBits (line 985) | public numCharCountBits(ver: int): int {
Condensed preview — 52 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (705K chars).
[
{
"path": "Readme.markdown",
"chars": 4031,
"preview": "QR Code generator library\n=========================\n\n\nIntroduction\n------------\n\nThis project aims to be the best, clear"
},
{
"path": "c/Makefile",
"chars": 2603,
"preview": "# \n# Makefile for QR Code generator (C)\n# \n# Copyright (c) Project Nayuki. (MIT License)\n# https://www.nayuki.io/page/qr"
},
{
"path": "c/Readme.markdown",
"chars": 2789,
"preview": "QR Code generator library - C\n=============================\n\n\nIntroduction\n------------\n\nThis project aims to be the bes"
},
{
"path": "c/qrcodegen-demo.c",
"chars": 12720,
"preview": "/* \n * QR Code generator demo (C)\n * \n * Run this command-line program with no arguments. The program\n * computes a demo"
},
{
"path": "c/qrcodegen-test.c",
"chars": 29710,
"preview": "/* \n * QR Code generator test suite (C)\n * \n * When compiling this program, the library qrcodegen.c needs QRCODEGEN_TEST"
},
{
"path": "c/qrcodegen.c",
"chars": 42044,
"preview": "/* \n * QR Code generator library (C)\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.io/page/qr"
},
{
"path": "c/qrcodegen.h",
"chars": 17866,
"preview": "/* \n * QR Code generator library (C)\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.io/page/qr"
},
{
"path": "cpp/Makefile",
"chars": 2492,
"preview": "# \n# Makefile for QR Code generator (C++)\n# \n# Copyright (c) Project Nayuki. (MIT License)\n# https://www.nayuki.io/page/"
},
{
"path": "cpp/QrCodeGeneratorDemo.cpp",
"chars": 9693,
"preview": "/* \n * QR Code generator demo (C++)\n * \n * Run this command-line program with no arguments. The program computes a bunch"
},
{
"path": "cpp/Readme.markdown",
"chars": 2462,
"preview": "QR Code generator library - C++\n===============================\n\n\nIntroduction\n------------\n\nThis project aims to be the"
},
{
"path": "cpp/qrcodegen.cpp",
"chars": 27296,
"preview": "/* \n * QR Code generator library (C++)\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.io/page/"
},
{
"path": "cpp/qrcodegen.hpp",
"chars": 20431,
"preview": "/* \n * QR Code generator library (C++)\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.io/page/"
},
{
"path": "java/QrCodeGeneratorDemo.java",
"chars": 11844,
"preview": "/* \n * QR Code generator demo (Java)\n * \n * Run this command-line program with no arguments. The program creates/overwri"
},
{
"path": "java/Readme.markdown",
"chars": 2608,
"preview": "QR Code generator library - Java\n================================\n\n\nIntroduction\n------------\n\nThis project aims to be t"
},
{
"path": "java/pom.xml",
"chars": 3585,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "java/src/main/java/io/nayuki/qrcodegen/BitBuffer.java",
"chars": 4159,
"preview": "/* \n * QR Code generator library (Java)\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.io/page"
},
{
"path": "java/src/main/java/io/nayuki/qrcodegen/DataTooLongException.java",
"chars": 2890,
"preview": "/* \n * QR Code generator library (Java)\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.io/page"
},
{
"path": "java/src/main/java/io/nayuki/qrcodegen/QrCode.java",
"chars": 35238,
"preview": "/* \n * QR Code generator library (Java)\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.io/page"
},
{
"path": "java/src/main/java/io/nayuki/qrcodegen/QrSegment.java",
"chars": 12234,
"preview": "/* \n * QR Code generator library (Java)\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.io/page"
},
{
"path": "java/src/main/java/io/nayuki/qrcodegen/QrSegmentAdvanced.java",
"chars": 35692,
"preview": "/* \n * QR Code generator library - Optional advanced logic (Java)\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * "
},
{
"path": "java/src/main/java/io/nayuki/qrcodegen/package-info.java",
"chars": 3046,
"preview": "/**\n * Generates QR Codes from text strings and byte arrays.\n * \n * <p>This project aims to be the best, clearest QR Cod"
},
{
"path": "java/src/main/java/module-info.java",
"chars": 1306,
"preview": "/* \n * QR Code generator library (Java)\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.io/page"
},
{
"path": "java-fast/Readme.markdown",
"chars": 2827,
"preview": "QR Code generator library - Java, fast\n======================================\n\n\nIntroduction\n------------\n\nThis project "
},
{
"path": "java-fast/io/nayuki/fastqrcodegen/BitBuffer.java",
"chars": 4454,
"preview": "/* \n * Fast QR Code generator library\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.io/page/f"
},
{
"path": "java-fast/io/nayuki/fastqrcodegen/DataTooLongException.java",
"chars": 2879,
"preview": "/* \n * Fast QR Code generator library\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.io/page/f"
},
{
"path": "java-fast/io/nayuki/fastqrcodegen/Memoizer.java",
"chars": 2782,
"preview": "/* \n * Fast QR Code generator library\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.io/page/f"
},
{
"path": "java-fast/io/nayuki/fastqrcodegen/QrCode.java",
"chars": 26849,
"preview": "/* \n * Fast QR Code generator library\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.io/page/f"
},
{
"path": "java-fast/io/nayuki/fastqrcodegen/QrCodeGeneratorDemo.java",
"chars": 11762,
"preview": "/* \n * Fast QR Code generator demo\n * \n * Run this command-line program with no arguments. The program creates/overwrite"
},
{
"path": "java-fast/io/nayuki/fastqrcodegen/QrSegment.java",
"chars": 12662,
"preview": "/* \n * Fast QR Code generator library\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.io/page/f"
},
{
"path": "java-fast/io/nayuki/fastqrcodegen/QrSegmentAdvanced.java",
"chars": 35141,
"preview": "/* \n * Fast QR Code generator library\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.io/page/f"
},
{
"path": "java-fast/io/nayuki/fastqrcodegen/QrTemplate.java",
"chars": 9755,
"preview": "/* \n * Fast QR Code generator library\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.io/page/f"
},
{
"path": "java-fast/io/nayuki/fastqrcodegen/ReedSolomonGenerator.java",
"chars": 4308,
"preview": "/* \n * Fast QR Code generator library\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.io/page/f"
},
{
"path": "java-fast/io/nayuki/fastqrcodegen/package-info.java",
"chars": 3307,
"preview": "/**\n * Generates QR Codes from text strings and byte arrays.\n * \n * <p>This project aims to be the best, clearest QR Cod"
},
{
"path": "python/Readme.markdown",
"chars": 2143,
"preview": "QR Code generator library - Python\n==================================\n\n\nIntroduction\n------------\n\nThis project aims to "
},
{
"path": "python/qrcodegen-demo.py",
"chars": 8534,
"preview": "# \n# QR Code generator demo (Python)\n# \n# Run this command-line program with no arguments. The program computes a bunch "
},
{
"path": "python/qrcodegen.py",
"chars": 39349,
"preview": "# \n# QR Code generator library (Python)\n# \n# Copyright (c) Project Nayuki. (MIT License)\n# https://www.nayuki.io/page/qr"
},
{
"path": "python/setup.py",
"chars": 4257,
"preview": "# \n# QR Code generator Distutils script (Python)\n# \n# Copyright (c) Project Nayuki. (MIT License)\n# https://www.nayuki.i"
},
{
"path": "rust/Cargo.toml",
"chars": 426,
"preview": "[package]\nname = \"qrcodegen\"\nversion = \"1.8.0\"\nauthors = [\"Project Nayuki\"]\ndescription = \"High-quality QR Code generato"
},
{
"path": "rust/Readme.markdown",
"chars": 2394,
"preview": "QR Code generator library - Rust\n================================\n\n\nIntroduction\n------------\n\nThis project aims to be t"
},
{
"path": "rust/examples/qrcodegen-demo.rs",
"chars": 8253,
"preview": "/* \n * QR Code generator demo (Rust)\n * \n * Run this command-line program with no arguments. The program computes a bunc"
},
{
"path": "rust/src/lib.rs",
"chars": 45836,
"preview": "/* \n * QR Code generator library (Rust)\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.io/page"
},
{
"path": "rust-no-heap/Cargo.toml",
"chars": 434,
"preview": "[package]\nname = \"qrcodegen-no-heap\"\nversion = \"1.8.1\"\nauthors = [\"Project Nayuki\"]\ndescription = \"High-quality QR Code "
},
{
"path": "rust-no-heap/Readme.markdown",
"chars": 2888,
"preview": "QR Code generator library - Rust, no heap\n=========================================\n\n\nIntroduction\n------------\n\nThis pr"
},
{
"path": "rust-no-heap/examples/qrcodegen-demo.rs",
"chars": 11701,
"preview": "/* \n * QR Code generator demo (Rust, no heap)\n * \n * Run this command-line program with no arguments. The program comput"
},
{
"path": "rust-no-heap/src/lib.rs",
"chars": 54299,
"preview": "/* \n * QR Code generator library (Rust, no heap)\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuk"
},
{
"path": "typescript-javascript/Readme.markdown",
"chars": 2289,
"preview": "QR Code generator library - TypeScript\n======================================\n\n\nIntroduction\n------------\n\nThis project "
},
{
"path": "typescript-javascript/build.sh",
"chars": 1414,
"preview": "# \n# Build script for QR Code generator (TypeScript)\n# \n# Copyright (c) Project Nayuki. (MIT License)\n# https://www.nayu"
},
{
"path": "typescript-javascript/qrcodegen-input-demo.html",
"chars": 5685,
"preview": "<!--\n - QR Code generator input demo (HTML+JavaScript)\n - \n - Copyright (c) Project Nayuki. (MIT License)\n - https:/"
},
{
"path": "typescript-javascript/qrcodegen-input-demo.ts",
"chars": 9319,
"preview": "/* \n * QR Code generator input demo (TypeScript)\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuk"
},
{
"path": "typescript-javascript/qrcodegen-output-demo.html",
"chars": 2391,
"preview": "<!--\n - QR Code generator output demo (HTML+JavaScript)\n - \n - Copyright (c) Project Nayuki. (MIT License)\n - https:"
},
{
"path": "typescript-javascript/qrcodegen-output-demo.ts",
"chars": 11135,
"preview": "/* \n * QR Code generator output demo (TypeScript)\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayu"
},
{
"path": "typescript-javascript/qrcodegen.ts",
"chars": 41022,
"preview": "/* \n * QR Code generator library (TypeScript)\n * \n * Copyright (c) Project Nayuki. (MIT License)\n * https://www.nayuki.i"
}
]
About this extraction
This page contains the full source code of the nayuki/QR-Code-generator GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 52 files (641.8 KB), approximately 213.8k tokens, and a symbol index with 560 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.