pull/118/head
Project Nayuki 3 years ago
commit 0532c7a237

@ -175,7 +175,7 @@ Rust language:
License
-------
Copyright © 2020 Project Nayuki. (MIT License)
Copyright © 2021 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

@ -65,11 +65,11 @@ clean:
# Executable files
%: %.o $(LIBFILE)
$(CC) $(CFLAGS) -o $@ $< -L . -l $(LIB)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -L . -l $(LIB)
# Special executable
qrcodegen-test: qrcodegen-test.c $(LIBOBJ:%.o=%.c)
$(CC) $(CFLAGS) -DQRCODEGEN_TEST -o $@ $^
$(CC) $(CFLAGS) $(LDFLAGS) -DQRCODEGEN_TEST -o $@ $^
# The library
$(LIBFILE): $(LIBOBJ)

@ -65,7 +65,7 @@ clean:
# Executable files
%: %.o $(LIBFILE)
$(CXX) $(CXXFLAGS) -o $@ $< -L . -l $(LIB)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $< -L . -l $(LIB)
# The library
$(LIBFILE): $(LIBOBJ)

@ -279,7 +279,7 @@ QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl,
throw std::logic_error("Assertion error");
// Increase the error correction level while the data still fits in the current version number
for (Ecc newEcl : vector<Ecc>{Ecc::MEDIUM, Ecc::QUARTILE, Ecc::HIGH}) { // From low to high
for (Ecc newEcl : {Ecc::MEDIUM, Ecc::QUARTILE, Ecc::HIGH}) { // From low to high
if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8)
ecl = newEcl;
}
@ -310,7 +310,7 @@ QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl,
// Pack bits into bytes in big endian
vector<uint8_t> dataCodewords(bb.size() / 8);
for (size_t i = 0; i < bb.size(); i++)
dataCodewords[i >> 3] |= (bb.at(i) ? 1 : 0) << (7 - (i & 7));
dataCodewords.at(i >> 3) |= (bb.at(i) ? 1 : 0) << (7 - (i & 7));
// Create the QR Code object
return QrCode(version, ecl, dataCodewords, mask);
@ -351,7 +351,7 @@ QrCode::QrCode(int ver, Ecc ecl, const vector<uint8_t> &dataCodewords, int msk)
}
if (msk < 0 || msk > 7)
throw std::logic_error("Assertion error");
this->mask = msk;
mask = msk;
applyMask(msk); // Apply the final choice of mask
drawFormatBits(msk); // Overwrite old format bits

@ -263,7 +263,7 @@ public final class QrCode {
drawFunctionPatterns();
byte[] allCodewords = addEccAndInterleave(dataCodewords);
drawCodewords(allCodewords);
this.mask = handleConstructorMasking(msk);
mask = handleConstructorMasking(msk);
isFunction = null;
}

@ -68,7 +68,9 @@ def main() -> None:
def do_trial() -> None:
mode = random.randrange(4)
mode: int = random.randrange(4)
length: int
data: List[int]
if mode == 0: # Numeric
length = round((2 * 7089) ** random.random())
data = random.choices(b"0123456789", k=length)
@ -88,12 +90,12 @@ def do_trial() -> None:
for b in data:
write_all(b)
errcorlvl = random.randrange(4)
minversion = random.randint(1, 40)
maxversion = random.randint(1, 40)
errcorlvl: int = random.randrange(4)
minversion: int = random.randint(1, 40)
maxversion: int = random.randint(1, 40)
if minversion > maxversion:
minversion, maxversion = maxversion, minversion
mask = -1
mask: int = -1
if random.random() < 0.5:
mask = random.randrange(8)
boostecl = int(random.random() < 0.2)
@ -106,11 +108,11 @@ def do_trial() -> None:
write_all(boostecl)
flush_all()
version = read_verify()
version: int = read_verify()
print(" version={}".format(version), end="")
if version == -1:
return
size = version * 4 + 17
size: int = version * 4 + 17
for _ in range(size**2):
read_verify()
@ -124,7 +126,7 @@ def flush_all() -> None:
not_none(proc.stdin).flush()
def read_verify() -> int:
val = not_none(subprocs[0].stdout).readline().rstrip("\r\n")
val: str = not_none(subprocs[0].stdout).readline().rstrip("\r\n")
for proc in subprocs[1 : ]:
if not_none(proc.stdout).readline().rstrip("\r\n") != val:
raise ValueError("Mismatch")

@ -27,6 +27,7 @@
#
import sys
from typing import List, Sequence
import qrcodegen
@ -38,26 +39,26 @@ def main() -> None:
while True:
# Read data or exit
length = read_int()
length: int = read_int()
if length == -1:
break
data = bytearray(read_int() for _ in range(length))
# Read encoding parameters
errcorlvl = read_int()
minversion = read_int()
maxversion = read_int()
mask = read_int()
boostecl = read_int()
errcorlvl : int = read_int()
minversion: int = read_int()
maxversion: int = read_int()
mask : int = read_int()
boostecl : int = read_int()
# Make segments for encoding
if all((b < 128) for b in data): # Is ASCII
segs = qrcodegen.QrSegment.make_segments(data.decode("ASCII"))
segs: List[qrcodegen.QrSegment] = qrcodegen.QrSegment.make_segments(data.decode("ASCII"))
else:
segs = [qrcodegen.QrSegment.make_bytes(data)]
try: # Try to make QR Code symbol
qr = qrcodegen.QrCode.encode_segments(segs, ECC_LEVELS[errcorlvl], minversion, maxversion, mask, boostecl != 0)
qr: qrcodegen.QrCode = qrcodegen.QrCode.encode_segments(segs, ECC_LEVELS[errcorlvl], minversion, maxversion, mask, boostecl != 0)
# Print grid of modules
print(qr.get_version())
for y in range(qr.get_size()):
@ -69,7 +70,7 @@ def main() -> None:
sys.stdout.flush()
ECC_LEVELS = (
ECC_LEVELS: Sequence[qrcodegen.QrCode.Ecc] = (
qrcodegen.QrCode.Ecc.LOW,
qrcodegen.QrCode.Ecc.MEDIUM,
qrcodegen.QrCode.Ecc.QUARTILE,

@ -23,41 +23,8 @@
from __future__ import annotations
import collections, itertools, re
from typing import List, Optional, Tuple
"""
This module "qrcodegen", public members:
- Class QrCode:
- Function encode_text(str text, QrCode.Ecc ecl) -> QrCode
- Function encode_binary(bytes data, QrCode.Ecc ecl) -> QrCode
- Function encode_segments(list<QrSegment> segs, QrCode.Ecc ecl,
int minversion=1, int maxversion=40, mask=-1, boostecl=true) -> QrCode
- Constants int MIN_VERSION, MAX_VERSION
- Constructor QrCode(int version, QrCode.Ecc ecl, bytes datacodewords, int mask)
- Method get_version() -> int
- Method get_size() -> int
- Method get_error_correction_level() -> QrCode.Ecc
- Method get_mask() -> int
- Method get_module(int x, int y) -> bool
- Method to_svg_str(int border) -> str
- Enum Ecc:
- Constants LOW, MEDIUM, QUARTILE, HIGH
- Field int ordinal
- Class QrSegment:
- Function make_bytes(bytes data) -> QrSegment
- Function make_numeric(str digits) -> QrSegment
- Function make_alphanumeric(str text) -> QrSegment
- Function make_segments(str text) -> list<QrSegment>
- Function make_eci(int assignval) -> QrSegment
- Constructor QrSegment(QrSegment.Mode mode, int numch, list<int> bitdata)
- Method get_mode() -> QrSegment.Mode
- Method get_num_chars() -> int
- Method get_data() -> list<int>
- Constants regex NUMERIC_REGEX, ALPHANUMERIC_REGEX
- Enum Mode:
- Constants NUMERIC, ALPHANUMERIC, BYTE, KANJI, ECI
"""
from collections.abc import Sequence
from typing import Callable, Dict, List, Optional, Tuple, Union
# ---- QR Code symbol class ----
@ -87,25 +54,23 @@ class QrCode:
Unicode code points (not UTF-16 code units) 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."""
segs = QrSegment.make_segments(text)
segs: List[QrSegment] = QrSegment.make_segments(text)
return QrCode.encode_segments(segs, ecl)
@staticmethod
def encode_binary(data: bytes, ecl: QrCode.Ecc) -> QrCode:
def encode_binary(data: Union[bytes,Sequence[int]], ecl: QrCode.Ecc) -> QrCode:
"""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."""
if not isinstance(data, (bytes, bytearray)):
raise TypeError("Byte string/list expected")
return QrCode.encode_segments([QrSegment.make_bytes(data)], ecl)
# ---- Static factory functions (mid level) ----
@staticmethod
def encode_segments(segs: List[QrSegment], ecl: QrCode.Ecc, minversion: int = 1, maxversion: int = 40, mask: int = -1, boostecl: bool = True) -> QrCode:
def encode_segments(segs: Sequence[QrSegment], ecl: QrCode.Ecc, minversion: int = 1, maxversion: int = 40, mask: int = -1, boostecl: bool = True) -> QrCode:
"""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
@ -121,12 +86,12 @@ class QrCode:
# Find the minimal version number to use
for version in range(minversion, maxversion + 1):
datacapacitybits = QrCode._get_num_data_codewords(version, ecl) * 8 # Number of data bits available
datausedbits = QrSegment.get_total_bits(segs, version)
if datausedbits is not None and datausedbits <= datacapacitybits:
datacapacitybits: int = QrCode._get_num_data_codewords(version, ecl) * 8 # Number of data bits available
datausedbits: Optional[int] = QrSegment.get_total_bits(segs, version)
if (datausedbits is not None) and (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
msg = "Segment too long"
msg: str = "Segment too long"
if datausedbits is not None:
msg = "Data length = {} bits, Max capacity = {} bits".format(datausedbits, datacapacitybits)
raise DataTooLongError(msg)
@ -135,7 +100,7 @@ class QrCode:
# Increase the error correction level while the data still fits in the current version number
for newecl in (QrCode.Ecc.MEDIUM, QrCode.Ecc.QUARTILE, QrCode.Ecc.HIGH): # From low to high
if boostecl and datausedbits <= QrCode._get_num_data_codewords(version, newecl) * 8:
if boostecl and (datausedbits <= QrCode._get_num_data_codewords(version, newecl) * 8):
ecl = newecl
# Concatenate all segments to create the data bit string
@ -160,7 +125,7 @@ class QrCode:
bb.append_bits(padbyte, 8)
# Pack bits into bytes in big endian
datacodewords = [0] * (len(bb) // 8)
datacodewords = bytearray([0] * (len(bb) // 8))
for (i, bit) in enumerate(bb):
datacodewords[i >> 3] |= bit << (7 - (i & 7))
@ -168,9 +133,35 @@ class QrCode:
return QrCode(version, ecl, datacodewords, mask)
# ---- Private fields ----
# The version number of this QR Code, which is between 1 and 40 (inclusive).
# This determines the size of this barcode.
_version: int
# The width and height of this QR Code, measured in modules, between
# 21 and 177 (inclusive). This is equal to version * 4 + 17.
_size: int
# The error correction level used in this QR Code.
_errcorlvl: QrCode.Ecc
# 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.
_mask: int
# The modules of this QR Code (False = white, True = black).
# Immutable after constructor finishes. Accessed through get_module().
_modules: List[List[bool]]
# Indicates function modules that are not subjected to masking. Discarded when constructor finishes.
_isfunction: List[List[bool]]
# ---- Constructor (low level) ----
def __init__(self, version: int, errcorlvl: QrCode.Ecc, datacodewords: List[int], mask: int) -> None:
def __init__(self, version: int, errcorlvl: QrCode.Ecc, datacodewords: Union[bytes,Sequence[int]], mask: int) -> None:
"""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.
@ -184,32 +175,22 @@ class QrCode:
if not isinstance(errcorlvl, QrCode.Ecc):
raise TypeError("QrCode.Ecc expected")
# The version number of this QR Code, which is between 1 and 40 (inclusive).
# This determines the size of this barcode.
self._version = version
# The width and height of this QR Code, measured in modules, between
# 21 and 177 (inclusive). This is equal to version * 4 + 17.
self._size = version * 4 + 17
# The error correction level used in this QR Code.
self._errcorlvl = errcorlvl
# Initialize both grids to be size*size arrays of Boolean false
# The modules of this QR Code (False = white, True = black).
# Immutable after constructor finishes. Accessed through get_module().
self._modules = [[False] * self._size for _ in range(self._size)] # Initially all white
# Indicates function modules that are not subjected to masking. Discarded when constructor finishes
self._isfunction = [[False] * self._size for _ in range(self._size)]
# Compute ECC, draw modules
self._draw_function_patterns()
allcodewords = self._add_ecc_and_interleave(datacodewords)
allcodewords: bytes = self._add_ecc_and_interleave(bytearray(datacodewords))
self._draw_codewords(allcodewords)
# Do masking
if mask == -1: # Automatically choose best mask
minpenalty = 1 << 32
minpenalty: int = 1 << 32
for i in range(8):
self._apply_mask(i)
self._draw_format_bits(i)
@ -221,10 +202,6 @@ class QrCode:
assert 0 <= mask <= 7
self._apply_mask(mask) # Apply the final choice of mask
self._draw_format_bits(mask) # Overwrite old format bits
# 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.
self._mask = mask
del self._isfunction
@ -248,7 +225,7 @@ class QrCode:
"""Returns this QR Code's mask, in the range [0, 7]."""
return self._mask
def get_module(self, x, y) -> bool:
def get_module(self, x: int, y: int) -> bool:
"""Returns the color of the module (pixel) at the given coordinates, which is False
for white or True for black. The top left corner has the coordinates (x=0, y=0).
If the given coordinates are out of bounds, then False (white) is returned."""
@ -262,7 +239,7 @@ class QrCode:
of border modules. The string always uses Unix newlines (\n), regardless of the platform."""
if border < 0:
raise ValueError("Border must be non-negative")
parts = []
parts: List[str] = []
for y in range(self._size):
for x in range(self._size):
if self.get_module(x, y):
@ -291,9 +268,9 @@ class QrCode:
self._draw_finder_pattern(3, self._size - 4)
# Draw numerous alignment patterns
alignpatpos = self._get_alignment_pattern_positions()
numalign = len(alignpatpos)
skips = ((0, 0), (0, numalign - 1), (numalign - 1, 0))
alignpatpos: List[int] = self._get_alignment_pattern_positions()
numalign: int = len(alignpatpos)
skips: Sequence[Tuple[int,int]] = ((0, 0), (0, numalign - 1), (numalign - 1, 0))
for i in range(numalign):
for j in range(numalign):
if (i, j) not in skips: # Don't draw on the three finder corners
@ -304,15 +281,15 @@ class QrCode:
self._draw_version()
def _draw_format_bits(self, mask) -> None:
def _draw_format_bits(self, mask: int) -> None:
"""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."""
# Calculate error correction code and pack bits
data = self._errcorlvl.formatbits << 3 | mask # errCorrLvl is uint2, mask is uint3
rem = data
data: int = self._errcorlvl.formatbits << 3 | mask # errCorrLvl is uint2, mask is uint3
rem: int = data
for _ in range(10):
rem = (rem << 1) ^ ((rem >> 9) * 0x537)
bits = (data << 10 | rem) ^ 0x5412 # uint15
bits: int = (data << 10 | rem) ^ 0x5412 # uint15
assert bits >> 15 == 0
# Draw first copy
@ -339,22 +316,22 @@ class QrCode:
return
# Calculate error correction code and pack bits
rem = self._version # version is uint6, in the range [7, 40]
rem: int = self._version # version is uint6, in the range [7, 40]
for _ in range(12):
rem = (rem << 1) ^ ((rem >> 11) * 0x1F25)
bits = self._version << 12 | rem # uint18
bits: int = self._version << 12 | rem # uint18
assert bits >> 18 == 0
# Draw two copies
for i in range(18):
bit = _get_bit(bits, i)
a = self._size - 11 + i % 3
b = i // 3
bit: bool = _get_bit(bits, i)
a: int = self._size - 11 + i % 3
b: int = i // 3
self._set_function_module(a, b, bit)
self._set_function_module(b, a, bit)
def _draw_finder_pattern(self, x, y) -> None:
def _draw_finder_pattern(self, x: int, y: int) -> None:
"""Draws a 9*9 finder pattern including the border separator,
with the center module at (x, y). Modules can be out of bounds."""
for dy in range(-4, 5):
@ -365,7 +342,7 @@ class QrCode:
self._set_function_module(xx, yy, max(abs(dx), abs(dy)) not in (2, 4))
def _draw_alignment_pattern(self, x, y) -> None:
def _draw_alignment_pattern(self, x: int, y: int) -> None:
"""Draws a 5*5 alignment pattern, with the center module
at (x, y). All modules must be in bounds."""
for dy in range(-2, 3):
@ -383,59 +360,59 @@ class QrCode:
# ---- Private helper methods for constructor: Codewords and masking ----
def _add_ecc_and_interleave(self, data: List[int]) -> List[int]:
def _add_ecc_and_interleave(self, data: bytearray) -> bytes:
"""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."""
version = self._version
version: int = self._version
assert len(data) == QrCode._get_num_data_codewords(version, self._errcorlvl)
# Calculate parameter numbers
numblocks = QrCode._NUM_ERROR_CORRECTION_BLOCKS[self._errcorlvl.ordinal][version]
blockecclen = QrCode._ECC_CODEWORDS_PER_BLOCK [self._errcorlvl.ordinal][version]
rawcodewords = QrCode._get_num_raw_data_modules(version) // 8
numshortblocks = numblocks - rawcodewords % numblocks
shortblocklen = rawcodewords // numblocks
numblocks: int = QrCode._NUM_ERROR_CORRECTION_BLOCKS[self._errcorlvl.ordinal][version]
blockecclen: int = QrCode._ECC_CODEWORDS_PER_BLOCK [self._errcorlvl.ordinal][version]
rawcodewords: int = QrCode._get_num_raw_data_modules(version) // 8
numshortblocks: int = numblocks - rawcodewords % numblocks
shortblocklen: int = rawcodewords // numblocks
# Split data into blocks and append ECC to each block
blocks = []
rsdiv = QrCode._reed_solomon_compute_divisor(blockecclen)
k = 0
blocks: List[bytes] = []
rsdiv: bytes = QrCode._reed_solomon_compute_divisor(blockecclen)
k: int = 0
for i in range(numblocks):
dat = data[k : k + shortblocklen - blockecclen + (0 if i < numshortblocks else 1)]
dat: bytearray = data[k : k + shortblocklen - blockecclen + (0 if i < numshortblocks else 1)]
k += len(dat)
ecc = QrCode._reed_solomon_compute_remainder(dat, rsdiv)
ecc: bytes = QrCode._reed_solomon_compute_remainder(dat, rsdiv)
if i < numshortblocks:
dat.append(0)
blocks.append(dat + ecc)
assert k == len(data)
# Interleave (not concatenate) the bytes from every block into a single sequence
result = []
result = bytearray()
for i in range(len(blocks[0])):
for (j, blk) in enumerate(blocks):
# Skip the padding byte in short blocks
if i != shortblocklen - blockecclen or j >= numshortblocks:
if (i != shortblocklen - blockecclen) or (j >= numshortblocks):
result.append(blk[i])
assert len(result) == rawcodewords
return result
def _draw_codewords(self, data: List[int]) -> None:
def _draw_codewords(self, data: bytes) -> None:
"""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."""
assert len(data) == QrCode._get_num_raw_data_modules(self._version) // 8
i = 0 # Bit index into the data
i: int = 0 # Bit index into the data
# Do the funny zigzag scan
for right in range(self._size - 1, 0, -2): # Index of right column in each column pair
if right <= 6:
right -= 1
for vert in range(self._size): # Vertical counter
for j in range(2):
x = right - j # Actual x coordinate
upward = (right + 1) & 2 == 0
y = (self._size - 1 - vert) if upward else vert # Actual y coordinate
if not self._isfunction[y][x] and i < len(data) * 8:
x: int = right - j # Actual x coordinate
upward: bool = (right + 1) & 2 == 0
y: int = (self._size - 1 - vert) if upward else vert # Actual y coordinate
if (not self._isfunction[y][x]) and (i < len(data) * 8):
self._modules[y][x] = _get_bit(data[i >> 3], 7 - (i & 7))
i += 1
# If this QR Code has any remainder bits (0 to 7), they were assigned as
@ -446,12 +423,12 @@ class QrCode:
def _apply_mask(self, mask: int) -> None:
"""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
before masking. Due to the arithmetic of XOR, calling _apply_mask() 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."""
if not (0 <= mask <= 7):
raise ValueError("Mask value out of range")
masker = QrCode._MASK_PATTERNS[mask]
masker: Callable[[int,int],int] = QrCode._MASK_PATTERNS[mask]
for y in range(self._size):
for x in range(self._size):
self._modules[y][x] ^= (masker(x, y) == 0) and (not self._isfunction[y][x])
@ -460,14 +437,14 @@ class QrCode:
def _get_penalty_score(self) -> int:
"""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."""
result = 0
size = self._size
modules = self._modules
result: int = 0
size: int = self._size
modules: List[List[bool]] = self._modules
# Adjacent modules in row having same color, and finder-like patterns
for y in range(size):
runcolor = False
runx = 0
runcolor: bool = False
runx: int = 0
runhistory = collections.deque([0] * 7, 7)
for x in range(size):
if modules[y][x] == runcolor:
@ -510,10 +487,10 @@ class QrCode:
result += QrCode._PENALTY_N2
# Balance of black and white modules
black = sum((1 if cell else 0) for row in modules for cell in row)
total = size**2 # Note that size is odd, so black/total != 1/2
black: int = sum((1 if cell else 0) for row in modules for cell in row)
total: int = size**2 # Note that size is odd, so black/total != 1/2
# Compute the smallest integer k >= 0 such that (45-5k)% <= black/total <= (55+5k)%
k = (abs(black * 20 - total * 10) + total - 1) // total - 1
k: int = (abs(black * 20 - total * 10) + total - 1) // total - 1
result += k * QrCode._PENALTY_N4
return result
@ -524,27 +501,27 @@ class QrCode:
"""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 integers."""
ver = self._version
ver: int = self._version
if ver == 1:
return []
else:
numalign = ver // 7 + 2
step = 26 if (ver == 32) else \
numalign: int = ver // 7 + 2
step: int = 26 if (ver == 32) else \
(ver*4 + numalign*2 + 1) // (numalign*2 - 2) * 2
result = [(self._size - 7 - i * step) for i in range(numalign - 1)] + [6]
result: List[int] = [(self._size - 7 - i * step) for i in range(numalign - 1)] + [6]
return list(reversed(result))
@staticmethod
def _get_num_raw_data_modules(ver) -> int:
def _get_num_raw_data_modules(ver: int) -> int:
"""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."""
if not (QrCode.MIN_VERSION <= ver <= QrCode.MAX_VERSION):
raise ValueError("Version number out of range")
result = (16 * ver + 128) * ver + 64
result: int = (16 * ver + 128) * ver + 64
if ver >= 2:
numalign = ver // 7 + 2
numalign: int = ver // 7 + 2
result -= (25 * numalign - 10) * numalign - 55
if ver >= 7:
result -= 36
@ -553,7 +530,7 @@ class QrCode:
@staticmethod
def _get_num_data_codewords(ver, ecl: QrCode.Ecc) -> int:
def _get_num_data_codewords(ver: int, ecl: QrCode.Ecc) -> int:
"""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."""
@ -563,19 +540,19 @@ class QrCode:
@staticmethod
def _reed_solomon_compute_divisor(degree: int) -> List[int]:
def _reed_solomon_compute_divisor(degree: int) -> bytes:
"""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."""
if not (1 <= degree <= 255):
raise ValueError("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].
result = [0] * (degree - 1) + [1] # Start off with the monomial x^0
result = bytearray([0] * (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}),
# 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).
root = 1
root: int = 1
for _ in range(degree): # Unused variable i
# Multiply the current product by (x - r^i)
for j in range(degree):
@ -587,11 +564,11 @@ class QrCode:
@staticmethod
def _reed_solomon_compute_remainder(data: List[int], divisor: List[int]) -> List[int]:
def _reed_solomon_compute_remainder(data: bytes, divisor: bytes) -> bytes:
"""Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials."""
result = [0] * len(divisor)
result = bytearray([0] * len(divisor))
for b in data: # Polynomial division
factor = b ^ result.pop(0)
factor: int = b ^ result.pop(0)
result.append(0)
for (i, coef) in enumerate(divisor):
result[i] ^= QrCode._reed_solomon_multiply(coef, factor)
@ -602,10 +579,10 @@ class QrCode:
def _reed_solomon_multiply(x: int, y: int) -> int:
"""Returns the product of the two given field elements modulo GF(2^8/0x11D). The arguments and result
are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8."""
if x >> 8 != 0 or y >> 8 != 0:
if (x >> 8 != 0) or (y >> 8 != 0):
raise ValueError("Byte out of range")
# Russian peasant multiplication
z = 0
z: int = 0
for i in reversed(range(8)):
z = (z << 1) ^ ((z >> 7) * 0x11D)
z ^= ((y >> i) & 1) * x
@ -616,9 +593,9 @@ class QrCode:
def _finder_penalty_count_patterns(self, runhistory: collections.deque) -> int:
"""Can only be called immediately after a white run is added, and
returns either 0, 1, or 2. A helper function for _get_penalty_score()."""
n = runhistory[1]
n: int = runhistory[1]
assert n <= self._size * 3
core = n > 0 and (runhistory[2] == runhistory[4] == runhistory[5] == n) and runhistory[3] == n * 3
core: bool = n > 0 and (runhistory[2] == runhistory[4] == runhistory[5] == n) and runhistory[3] == n * 3
return (1 if (core and runhistory[0] >= n * 4 and runhistory[6] >= n) else 0) \
+ (1 if (core and runhistory[6] >= n * 4 and runhistory[0] >= n) else 0)
@ -641,16 +618,16 @@ class QrCode:
# ---- Constants and tables ----
MIN_VERSION = 1 # The minimum version number supported in the QR Code Model 2 standard
MAX_VERSION = 40 # The maximum version number supported in the QR Code Model 2 standard
MIN_VERSION: int = 1 # The minimum version number supported in the QR Code Model 2 standard
MAX_VERSION: int = 40 # The maximum version number supported in the QR Code Model 2 standard
# For use in getPenaltyScore(), when evaluating which mask is best.
_PENALTY_N1 = 3
_PENALTY_N2 = 3
_PENALTY_N3 = 40
_PENALTY_N4 = 10
# For use in _get_penalty_score(), when evaluating which mask is best.
_PENALTY_N1: int = 3
_PENALTY_N2: int = 3
_PENALTY_N3: int = 40
_PENALTY_N4: int = 10
_ECC_CODEWORDS_PER_BLOCK = (
_ECC_CODEWORDS_PER_BLOCK: Sequence[Sequence[int]] = (
# 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
@ -658,7 +635,7 @@ class QrCode:
(-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
_NUM_ERROR_CORRECTION_BLOCKS = (
_NUM_ERROR_CORRECTION_BLOCKS: Sequence[Sequence[int]] = (
# 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
@ -666,7 +643,7 @@ class QrCode:
(-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
_MASK_PATTERNS = (
_MASK_PATTERNS: Sequence[Callable[[int,int],int]] = (
(lambda x, y: (x + y) % 2 ),
(lambda x, y: y % 2 ),
(lambda x, y: x % 3 ),
@ -681,11 +658,14 @@ class QrCode:
# ---- Public helper enumeration ----
class Ecc:
ordinal: int # (Public) In the range 0 to 3 (unsigned 2-bit integer)
formatbits: int # (Package-private) In the range 0 to 3 (unsigned 2-bit integer)
"""The error correction level in a QR Code symbol. Immutable."""
# Private constructor
def __init__(self, i: int, fb: int) -> None:
self.ordinal = i # (Public) In the range 0 to 3 (unsigned 2-bit integer)
self.formatbits = fb # (Package-private) In the range 0 to 3 (unsigned 2-bit integer)
self.ordinal = i
self.formatbits = fb
# Placeholders
LOW : QrCode.Ecc
@ -717,12 +697,10 @@ class QrSegment:
# ---- Static factory functions (mid level) ----
@staticmethod
def make_bytes(data) -> QrSegment:
def make_bytes(data: Union[bytes,Sequence[int]]) -> QrSegment:
"""Returns a segment representing the given binary data encoded in byte mode.
All input byte lists are acceptable. Any text string can be converted to
UTF-8 bytes (s.encode("UTF-8")) and encoded as a byte mode segment."""
if isinstance(data, str):
raise TypeError("Byte string/list expected")
bb = _BitBuffer()
for b in data:
bb.append_bits(b, 8)
@ -735,9 +713,9 @@ class QrSegment:
if QrSegment.NUMERIC_REGEX.fullmatch(digits) is None:
raise ValueError("String contains non-numeric characters")
bb = _BitBuffer()
i = 0
i: int = 0
while i < len(digits): # Consume up to 3 digits per iteration
n = min(len(digits) - i, 3)
n: int = min(len(digits) - i, 3)
bb.append_bits(int(digits[i : i + n]), n * 3 + 1)
i += n
return QrSegment(QrSegment.Mode.NUMERIC, len(digits), bb)
@ -752,7 +730,7 @@ class QrSegment:
raise ValueError("String contains unencodable characters in alphanumeric mode")
bb = _BitBuffer()
for i in range(0, len(text) - 1, 2): # Process groups of 2
temp = QrSegment._ALPHANUMERIC_ENCODING_TABLE[text[i]] * 45
temp: int = QrSegment._ALPHANUMERIC_ENCODING_TABLE[text[i]] * 45
temp += QrSegment._ALPHANUMERIC_ENCODING_TABLE[text[i + 1]]
bb.append_bits(temp, 11)
if len(text) % 2 > 0: # 1 character remaining
@ -798,9 +776,24 @@ class QrSegment:
return QrSegment(QrSegment.Mode.ECI, 0, bb)
# ---- Private fields ----
# The mode indicator of this segment. Accessed through get_mode().
_mode: QrSegment.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 get_num_chars().
_numchars: int
# The data bits of this segment. Accessed through get_data().
_bitdata: List[int]
# ---- Constructor (low level) ----
def __init__(self, mode: QrSegment.Mode, numch: int, bitdata: List[int]) -> None:
def __init__(self, mode: QrSegment.Mode, numch: int, bitdata: Sequence[int]) -> None:
"""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 cloned and stored."""
@ -808,17 +801,8 @@ class QrSegment:
raise TypeError("QrSegment.Mode expected")
if numch < 0:
raise ValueError()
# The mode indicator of this segment. Accessed through get_mode().
self._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 get_num_chars().
self._numchars = numch
# The data bits of this segment. Accessed through get_data().
self._bitdata = list(bitdata) # Make defensive copy
@ -845,7 +829,7 @@ class QrSegment:
returns None if a segment has too many characters to fit its length field."""
result = 0
for seg in segs:
ccbits = seg.get_mode().num_char_count_bits(version)
ccbits: int = seg.get_mode().num_char_count_bits(version)
if seg.get_num_chars() >= (1 << ccbits):
return None # The segment's length doesn't fit the field's bit width
result += 4 + ccbits + len(seg._bitdata)
@ -857,17 +841,16 @@ class QrSegment:
# (Public) Describes precisely all strings that are encodable in numeric mode.
# To test whether a string s is encodable: ok = NUMERIC_REGEX.fullmatch(s) is not None
# A string is encodable iff each character is in the range 0 to 9.
NUMERIC_REGEX = re.compile(r"[0-9]*")
NUMERIC_REGEX: re.Pattern = re.compile(r"[0-9]*")
# (Public) Describes precisely all strings that are encodable in alphanumeric mode.
# To test whether a string s is encodable: ok = ALPHANUMERIC_REGEX.fullmatch(s) is not None
# 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.
ALPHANUMERIC_REGEX = re.compile(r"[A-Z0-9 $%*+./:-]*")
ALPHANUMERIC_REGEX: re.Pattern = re.compile(r"[A-Z0-9 $%*+./:-]*")
# (Private) Dictionary of "0"->0, "A"->10, "$"->37, etc.
_ALPHANUMERIC_ENCODING_TABLE = {ch: i for (i, ch) in enumerate("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:")}
_ALPHANUMERIC_ENCODING_TABLE: Dict[str,int] = {ch: i for (i, ch) in enumerate("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:")}
# ---- Public helper enumeration ----
@ -875,10 +858,13 @@ class QrSegment:
class Mode:
"""Describes how a segment's data bits are interpreted. Immutable."""
_modebits: int # The mode indicator bits, which is a uint4 value (range 0 to 15)
_charcounts: Tuple[int,int,int] # Number of character count bits for three different version ranges
# Private constructor
def __init__(self, modebits: int, charcounts: Tuple[int,int,int]):
self._modebits = modebits # The mode indicator bits, which is a uint4 value (range 0 to 15)
self._charcounts = charcounts # Number of character count bits for three different version ranges
self._modebits = modebits
self._charcounts = charcounts
# Package-private method
def get_mode_bits(self) -> int:
@ -915,7 +901,7 @@ class _BitBuffer(list):
def append_bits(self, val: int, n: int) -> None:
"""Appends the given number of low-order bits of the given
value to this buffer. Requires n >= 0 and 0 <= val < 2^n."""
if n < 0 or val >> n != 0:
if (n < 0) or (val >> n != 0):
raise ValueError("Value out of range")
self.extend(((val >> i) & 1) for i in reversed(range(n)))

@ -29,8 +29,7 @@ use qrcodegen::Mask;
use qrcodegen::QrCode;
use qrcodegen::QrCodeEcc;
use qrcodegen::QrSegment;
use qrcodegen::QrCode_MAX_VERSION;
use qrcodegen::QrCode_MIN_VERSION;
use qrcodegen::Version;
// The main application program.
@ -128,8 +127,8 @@ fn do_segment_demo() {
0x0000, 0x0208, 0x01FF, 0x0008,
];
let mut bb = qrcodegen::BitBuffer(Vec::new());
for c in &kanjichars {
bb.append_bits(*c, 13);
for &c in &kanjichars {
bb.append_bits(c, 13);
}
let segs = vec![
QrSegment::new(qrcodegen::QrSegmentMode::Kanji, kanjichars.len(), bb.0),
@ -143,20 +142,20 @@ fn do_segment_demo() {
fn do_mask_demo() {
// Project Nayuki URL
let segs = QrSegment::make_segments(&to_chars("https://www.nayuki.io/"));
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::High, QrCode_MIN_VERSION, QrCode_MAX_VERSION, None, true).unwrap(); // Automatic mask
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::High, Version::MIN, Version::MAX, None, true).unwrap(); // Automatic mask
print_qr(&qr);
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::High, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(Mask::new(3)), true).unwrap(); // Force mask 3
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::High, Version::MIN, Version::MAX, Some(Mask::new(3)), true).unwrap(); // Force mask 3
print_qr(&qr);
// Chinese text as UTF-8
let segs = QrSegment::make_segments(&to_chars("維基百科Wikipedia聆聽i/ˌwɪkᵻˈpiːdi.ə/)是一個自由內容、公開編輯且多語言的網路百科全書協作計畫"));
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(Mask::new(0)), true).unwrap(); // Force mask 0
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, Version::MIN, Version::MAX, Some(Mask::new(0)), true).unwrap(); // Force mask 0
print_qr(&qr);
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(Mask::new(1)), true).unwrap(); // Force mask 1
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, Version::MIN, Version::MAX, Some(Mask::new(1)), true).unwrap(); // Force mask 1
print_qr(&qr);
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(Mask::new(5)), true).unwrap(); // Force mask 5
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, Version::MIN, Version::MAX, Some(Mask::new(5)), true).unwrap(); // Force mask 5
print_qr(&qr);
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(Mask::new(7)), true).unwrap(); // Force mask 7
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, Version::MIN, Version::MAX, Some(Mask::new(7)), true).unwrap(); // Force mask 7
print_qr(&qr);
}

@ -59,9 +59,9 @@ fn main() {
let mask = read_int();
let boostecl = read_int();
assert!(0 <= errcorlvl && errcorlvl <= 3);
assert!(i16::from(qrcodegen::QrCode_MIN_VERSION.value()) <= minversion
assert!(i16::from(Version::MIN.value()) <= minversion
&& minversion <= maxversion
&& maxversion <= i16::from(qrcodegen::QrCode_MAX_VERSION.value()));
&& maxversion <= i16::from(Version::MAX.value()));
assert!(-1 <= mask && mask <= 7);
assert!(boostecl >> 1 == 0);

@ -184,7 +184,7 @@ impl QrCode {
/// Returns a wrapped `QrCode` if successful, or `Err` if the
/// data is too long to fit in any version at the given ECC level.
pub fn encode_segments(segs: &[QrSegment], ecl: QrCodeEcc) -> Result<Self,DataTooLong> {
QrCode::encode_segments_advanced(segs, ecl, QrCode_MIN_VERSION, QrCode_MAX_VERSION, None, true)
QrCode::encode_segments_advanced(segs, ecl, Version::MIN, Version::MAX, None, true)
}
@ -207,7 +207,7 @@ impl QrCode {
assert!(minversion.value() <= maxversion.value(), "Invalid value");
// Find the minimal version number to use
let mut version = minversion;
let mut version: Version = minversion;
let datausedbits: usize = loop {
// Number of data bits available
let datacapacitybits: usize = QrCode::get_num_data_codewords(version, ecl) * 8;
@ -245,9 +245,9 @@ impl QrCode {
// Add terminator and pad up to a byte if applicable
let datacapacitybits: usize = QrCode::get_num_data_codewords(version, ecl) * 8;
assert!(bb.0.len() <= datacapacitybits);
let numzerobits = std::cmp::min(4, datacapacitybits - bb.0.len());
let numzerobits: usize = std::cmp::min(4, datacapacitybits - bb.0.len());
bb.append_bits(0, numzerobits as u8);
let numzerobits = bb.0.len().wrapping_neg() & 7;
let numzerobits: usize = bb.0.len().wrapping_neg() & 7;
bb.append_bits(0, numzerobits as u8);
assert_eq!(bb.0.len() % 8, 0, "Assertion error");
@ -296,7 +296,7 @@ impl QrCode {
// Do masking
if mask.is_none() { // Automatically choose best mask
let mut minpenalty: i32 = std::i32::MAX;
let mut minpenalty = std::i32::MAX;
for i in 0u8 .. 8 {
let newmask = Mask::new(i);
result.apply_mask(newmask);
@ -438,7 +438,7 @@ impl QrCode {
// Calculate error correction code and pack bits
let bits: u32 = {
// errcorrlvl is uint2, mask is uint3
let data: u32 = self.errorcorrectionlevel.format_bits() << 3 | u32::from(mask.value());
let data: u32 = u32::from(self.errorcorrectionlevel.format_bits() << 3 | mask.value());
let mut rem: u32 = data;
for _ in 0 .. 10 {
rem = (rem << 1) ^ ((rem >> 9) * 0x537);
@ -539,8 +539,8 @@ impl QrCode {
// 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.
fn add_ecc_and_interleave(&self, data: &[u8]) -> Vec<u8> {
let ver = self.version;
let ecl = self.errorcorrectionlevel;
let ver: Version = self.version;
let ecl: QrCodeEcc = self.errorcorrectionlevel;
assert_eq!(data.len(), QrCode::get_num_data_codewords(ver, ecl), "Illegal argument");
// Calculate parameter numbers
@ -613,14 +613,13 @@ impl QrCode {
// 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
// before masking. Due to the arithmetic of XOR, calling apply_mask() 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.
fn apply_mask(&mut self, mask: Mask) {
let mask: u8 = mask.value();
for y in 0 .. self.size {
for x in 0 .. self.size {
let invert: bool = match mask {
let invert: bool = match mask.value() {
0 => (x + y) % 2 == 0,
1 => y % 2 == 0,
2 => x % 3 == 0,
@ -720,7 +719,7 @@ impl QrCode {
// 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.
fn get_alignment_pattern_positions(&self) -> Vec<i32> {
let ver = self.version.value();
let ver: u8 = self.version.value();
if ver == 1 {
vec![]
} else {
@ -884,13 +883,6 @@ impl FinderPenalty {
/*---- Constants and tables ----*/
/// The minimum version number supported in the QR Code Model 2 standard.
pub const QrCode_MIN_VERSION: Version = Version( 1);
/// The maximum version number supported in the QR Code Model 2 standard.
pub const QrCode_MAX_VERSION: Version = Version(40);
// For use in get_penalty_score(), when evaluating which mask is best.
const PENALTY_N1: i32 = 3;
const PENALTY_N2: i32 = 3;
@ -949,7 +941,7 @@ impl QrCodeEcc {
// Returns an unsigned 2-bit integer (in the range 0 to 3).
fn format_bits(self) -> u32 {
fn format_bits(self) -> u8 {
use QrCodeEcc::*;
match self {
Low => 1,
@ -1047,7 +1039,7 @@ impl QrSegment {
let mut accumdata: u32 = 0;
let mut accumcount: u32 = 0;
for &c in text {
let i = ALPHANUMERIC_CHARSET.iter().position(|&x| x == c)
let i: usize = ALPHANUMERIC_CHARSET.iter().position(|&x| x == c)
.expect("String contains unencodable characters in alphanumeric mode");
accumdata = accumdata * 45 + (i as u32);
accumcount += 1;
@ -1140,11 +1132,15 @@ impl QrSegment {
fn get_total_bits(segs: &[Self], version: Version) -> Option<usize> {
let mut result: usize = 0;
for seg in segs {
let ccbits = seg.mode.num_char_count_bits(version);
if seg.numchars >= 1 << ccbits {
return None; // The segment's length doesn't fit the field's bit width
let ccbits: u8 = seg.mode.num_char_count_bits(version);
// ccbits can be as large as 16, but usize can be as small as 16
if let Some(limit) = 1usize.checked_shl(u32::from(ccbits)) {
if seg.numchars >= limit {
return None; // The segment's length doesn't fit the field's bit width
}
}
result = result.checked_add(4 + usize::from(ccbits) + seg.data.len())?;
result = result.checked_add(4 + usize::from(ccbits))?;
result = result.checked_add(seg.data.len())?;
}
Some(result)
}
@ -1249,8 +1245,8 @@ impl BitBuffer {
///
/// - Decrease the error correction level if it was greater than `QrCodeEcc::Low`.
/// - If the `encode_segments_advanced()` function was called, then increase the maxversion
/// argument 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`.)
/// argument if it was less than `Version::MAX`. (This advice does not apply to the
/// other factory functions because they search all versions up to `Version::MAX`.)
/// - 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).
@ -1276,11 +1272,17 @@ impl std::fmt::Display for DataTooLong {
pub struct Version(u8);
impl Version {
/// The minimum version number supported in the QR Code Model 2 standard.
pub const MIN: Version = Version( 1);
/// The maximum version number supported in the QR Code Model 2 standard.
pub const MAX: Version = Version(40);
/// Creates a version object from the given number.
///
/// Panics if the number is outside the range [1, 40].
pub fn new(ver: u8) -> Self {
assert!(QrCode_MIN_VERSION.value() <= ver && ver <= QrCode_MAX_VERSION.value(), "Version number out of range");
assert!(Version::MIN.value() <= ver && ver <= Version::MAX.value(), "Version number out of range");
Self(ver)
}

Loading…
Cancel
Save