module

CrImage::Util::QRCode

QR Code generator for CrImage.

Generates QR codes following ISO/IEC 18004 specification. Supports versions 1-40, all error correction levels, and automatic mode/version selection.

Example

# Generate QR code image
img = CrImage::Util::QRCode.generate("https://example.com", size: 300)

# With options
img = CrImage::Util::QRCode.generate("Hello",
  error_correction: :high,
  size: 400,
  margin: 4
)

# Low-level API
qr = CrImage::Util::QRCode.encode("Hello World")
img = qr.to_image(module_size: 10)

Constants

ALIGNMENT_POSITIONS = [[] of Int32, [6, 18], [6, 22], [6, 26], [6, 30], [6, 34], [6, 22, 38], [6, 24, 42], [6, 26, 46], [6, 28, 50], [6, 30, 54], [6, 32, 58], [6, 34, 62], [6, 26, 46, 66], [6, 26, 48, 70], [6, 26, 50, 74], [6, 30, 54, 78], [6, 30, 56, 82], [6, 30, 58, 86], [6, 34, 62, 90], [6, 28, 50, 72, 94], [6, 26, 50, 74, 98], [6, 30, 54, 78, 102], [6, 28, 54, 80, 106], [6, 32, 58, 84, 110], [6, 30, 58, 86, 114], [6, 34, 62, 90, 118], [6, 26, 50, 74, 98, 122], [6, 30, 54, 78, 102, 126], [6, 26, 52, 78, 104, 130], [6, 30, 56, 82, 108, 134], [6, 34, 60, 86, 112, 138], [6, 30, 58, 86, 114, 142], [6, 34, 62, 90, 118, 146], [6, 30, 54, 78, 102, 126, 150], [6, 24, 50, 76, 102, 128, 154], [6, 28, 54, 80, 106, 132, 158], [6, 32, 58, 84, 110, 136, 162], [6, 26, 54, 82, 110, 138, 166], [6, 30, 58, 86, 114, 142, 170]]

Alignment pattern positions for each version

ALPHANUMERIC_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"

Alphanumeric character set

EC_BLOCKS = {ErrorCorrection::Low => [[26, 7, 1, 19, 0, 0], [44, 10, 1, 34, 0, 0], [70, 15, 1, 55, 0, 0], [100, 20, 1, 80, 0, 0], [134, 26, 1, 108, 0, 0], [172, 18, 2, 68, 0, 0], [196, 20, 2, 78, 0, 0], [242, 24, 2, 97, 0, 0], [292, 30, 2, 116, 0, 0], [346, 18, 2, 68, 2, 69], [404, 20, 4, 81, 0, 0], [466, 24, 2, 92, 2, 93], [532, 26, 4, 107, 0, 0], [581, 30, 3, 115, 1, 116], [655, 22, 5, 87, 1, 88], [733, 24, 5, 98, 1, 99], [815, 28, 1, 107, 5, 108], [901, 30, 5, 120, 1, 121], [991, 28, 3, 113, 4, 114], [1085, 28, 3, 107, 5, 108], [1156, 28, 4, 116, 4, 117], [1258, 28, 2, 111, 7, 112], [1364, 30, 4, 121, 5, 122], [1474, 30, 6, 117, 4, 118], [1588, 26, 8, 106, 4, 107], [1706, 28, 10, 114, 2, 115], [1828, 30, 8, 122, 4, 123], [1921, 30, 3, 117, 10, 118], [2051, 30, 7, 116, 7, 117], [2185, 30, 5, 115, 10, 116], [2323, 30, 13, 115, 3, 116], [2465, 30, 17, 115, 0, 0], [2611, 30, 17, 115, 1, 116], [2761, 30, 13, 115, 6, 116], [2876, 30, 12, 121, 7, 122], [3034, 30, 6, 121, 14, 122], [3196, 30, 17, 122, 4, 123], [3362, 30, 4, 122, 18, 123], [3532, 30, 20, 117, 4, 118], [3706, 30, 19, 118, 6, 119]], ErrorCorrection::Medium => [[26, 10, 1, 16, 0, 0], [44, 16, 1, 28, 0, 0], [70, 26, 1, 44, 0, 0], [100, 18, 2, 32, 0, 0], [134, 24, 2, 43, 0, 0], [172, 16, 4, 27, 0, 0], [196, 18, 4, 31, 0, 0], [242, 22, 2, 38, 2, 39], [292, 22, 3, 36, 2, 37], [346, 26, 4, 43, 1, 44], [404, 30, 1, 50, 4, 51], [466, 22, 6, 36, 2, 37], [532, 22, 8, 37, 1, 38], [581, 24, 4, 40, 5, 41], [655, 24, 5, 41, 5, 42], [733, 28, 7, 45, 3, 46], [815, 28, 10, 46, 1, 47], [901, 26, 9, 43, 4, 44], [991, 26, 3, 44, 11, 45], [1085, 26, 3, 41, 13, 42], [1156, 26, 17, 42, 0, 0], [1258, 28, 17, 46, 0, 0], [1364, 28, 4, 47, 14, 48], [1474, 28, 6, 45, 14, 46], [1588, 28, 8, 47, 13, 48], [1706, 28, 19, 46, 4, 47], [1828, 28, 22, 45, 3, 46], [1921, 28, 3, 45, 23, 46], [2051, 28, 21, 45, 7, 46], [2185, 28, 19, 47, 10, 48], [2323, 28, 2, 46, 29, 47], [2465, 28, 10, 46, 23, 47], [2611, 28, 14, 46, 21, 47], [2761, 28, 14, 46, 23, 47], [2876, 28, 12, 47, 26, 48], [3034, 28, 6, 47, 34, 48], [3196, 28, 29, 46, 14, 47], [3362, 28, 13, 46, 32, 47], [3532, 28, 40, 47, 7, 48], [3706, 28, 18, 47, 31, 48]], ErrorCorrection::Quartile => [[26, 13, 1, 13, 0, 0], [44, 22, 1, 22, 0, 0], [70, 18, 2, 17, 0, 0], [100, 26, 2, 24, 0, 0], [134, 18, 2, 15, 2, 16], [172, 24, 4, 19, 0, 0], [196, 18, 2, 14, 4, 15], [242, 22, 4, 18, 2, 19], [292, 20, 4, 16, 4, 17], [346, 24, 6, 19, 2, 20], [404, 28, 4, 22, 4, 23], [466, 26, 4, 20, 6, 21], [532, 24, 8, 20, 4, 21], [581, 20, 11, 16, 5, 17], [655, 30, 5, 24, 7, 25], [733, 24, 15, 19, 2, 20], [815, 28, 1, 22, 15, 23], [901, 28, 17, 22, 1, 23], [991, 26, 17, 21, 4, 22], [1085, 30, 15, 24, 5, 25], [1156, 28, 17, 22, 6, 23], [1258, 30, 7, 24, 16, 25], [1364, 30, 11, 24, 14, 25], [1474, 30, 11, 24, 16, 25], [1588, 30, 7, 24, 22, 25], [1706, 28, 28, 22, 6, 23], [1828, 30, 8, 23, 26, 24], [1921, 30, 4, 24, 31, 25], [2051, 30, 1, 23, 37, 24], [2185, 30, 15, 24, 25, 25], [2323, 30, 42, 24, 1, 25], [2465, 30, 10, 24, 35, 25], [2611, 30, 29, 24, 19, 25], [2761, 30, 44, 24, 7, 25], [2876, 30, 39, 24, 14, 25], [3034, 30, 46, 24, 10, 25], [3196, 30, 49, 24, 10, 25], [3362, 30, 48, 24, 14, 25], [3532, 30, 43, 24, 22, 25], [3706, 30, 34, 24, 34, 25]], ErrorCorrection::High => [[26, 17, 1, 9, 0, 0], [44, 28, 1, 16, 0, 0], [70, 22, 2, 13, 0, 0], [100, 16, 4, 9, 0, 0], [134, 22, 2, 11, 2, 12], [172, 28, 4, 15, 0, 0], [196, 26, 4, 13, 1, 14], [242, 26, 4, 14, 2, 15], [292, 24, 4, 12, 4, 13], [346, 28, 6, 15, 2, 16], [404, 24, 3, 12, 8, 13], [466, 28, 7, 14, 4, 15], [532, 22, 12, 11, 4, 12], [581, 24, 11, 12, 5, 13], [655, 24, 11, 12, 7, 13], [733, 30, 3, 15, 13, 16], [815, 28, 2, 14, 17, 15], [901, 28, 2, 14, 19, 15], [991, 26, 9, 13, 16, 14], [1085, 28, 15, 15, 10, 16], [1156, 30, 19, 16, 6, 17], [1258, 24, 34, 13, 0, 0], [1364, 30, 16, 15, 14, 16], [1474, 30, 30, 16, 2, 17], [1588, 30, 22, 15, 13, 16], [1706, 30, 33, 16, 4, 17], [1828, 30, 12, 15, 28, 16], [1921, 30, 11, 15, 31, 16], [1828, 30, 19, 15, 26, 16], [2185, 30, 23, 15, 25, 16], [2323, 30, 23, 15, 28, 16], [2465, 30, 19, 15, 35, 16], [2611, 30, 11, 15, 46, 16], [2761, 30, 59, 16, 1, 17], [2876, 30, 22, 15, 41, 16], [3034, 30, 2, 15, 64, 16], [3196, 30, 24, 15, 46, 16], [3362, 30, 42, 15, 32, 16], [3532, 30, 10, 15, 67, 16], [3706, 30, 20, 15, 61, 16]]}

Number of error correction codewords per block for each version and EC level Format: [total_codewords, ec_codewords_per_block, num_blocks_group1, data_cw_group1, num_blocks_group2, data_cw_group2]

FORMAT_INFO = {ErrorCorrection::Low => [30660, 29427, 32170, 30877, 26159, 25368, 27713, 26998], ErrorCorrection::Medium => [21522, 20773, 24188, 23371, 17913, 16590, 20375, 19104], ErrorCorrection::Quartile => [13663, 12392, 16177, 14854, 9396, 8579, 11994, 11245], ErrorCorrection::High => [5769, 5054, 7399, 6608, 1890, 597, 3340, 2107]}

Format info for each EC level and mask (pre-calculated with BCH)

VERSION_INFO = [31892, 34236, 39577, 42195, 48118, 51042, 55367, 58893, 63784, 68472, 70749, 76311, 79154, 84390, 87683, 92361, 96236, 102084, 102881, 110507, 110734, 117786, 119615, 126325, 127568, 133589, 136944, 141498, 145311, 150283, 152622, 158308, 161089, 167017]

Version info (versions 7-40, pre-calculated with BCH)

Class methods

encode(data : String, error_correction : ErrorCorrection = ErrorCorrection::Medium, version : Int32 | Nil = nil) : Code

Encode data to QR code

Source
generate(data : String, size : Int32 = 300, error_correction : ErrorCorrection = ErrorCorrection::Medium, margin : Int32 = 4, foreground : Color::Color = Color::BLACK, background : Color::Color = Color::WHITE) : RGBA

Generate QR code image from text

Source
generate_with_logo(data : String, logo : Image, size : Int32 = 300, error_correction : ErrorCorrection = ErrorCorrection::High, margin : Int32 = 4, foreground : Color::Color = Color::BLACK, background : Color::Color = Color::WHITE, logo_scale : Float64 = 0.2, logo_border : Int32 = 4) : RGBA

Generate QR code with a logo/image overlay in the center

The logo is placed in the center of the QR code. QR codes have built-in error correction that allows up to 30% of the code to be obscured (with High error correction level). For best results:

  • Use High error correction level
  • Keep logo_scale at 0.2-0.25 (20-25% of QR size)
  • Use a logo with good contrast against the QR background

Example

logo = CrImage::PNG.read("logo.png")
qr = CrImage::Util::QRCode.generate_with_logo(
  "https://example.com",
  logo,
  size: 400,
  error_correction: CrImage::Util::QRCode::ErrorCorrection::High
)
Source

Nested types