*ALWAYS UNDER CONSTRUCTION*

Making qr code generator - part 1

created:

i’m trying to make a qr code generator while reading these:

  • ISO IEC 18004 2015 Standard.pdf
  • https:www.thonky.com/qr-code-tutorial

*

modes

modeindicatornote
eci0111extended channel interpretation (e.g. utf-8)
numeric0001alphanumeric table
alphanumeric0010
byte0100
kanji1000shift JIS
structured append0011encode data into multiple qr codes (max 16)
fnc10101(1st)
/1001(2nd)
turn qr code into gs1 barcode

mixing modes

multiple modes can be used in single qr code.

this can be done because we specify the length of each data segment.

example:

ECI(utf-8) - BYTE(data1) - ALPHANUMERIC(data2) - KANJI(data3)

extended channel interpretation (ECI) mode

we can encode data into various encodings like utf-8, ISO/IEC 8859-1(latin-1), ISO/IEC 8859-2(latin-2), and even raw bytes.

i had hard time understanding the ECI mode. the ECI mode only contains encoding format data like utf-8 and this instructs how to decode following data (usually byte mode data).

example 1:

ECI(utf-8) - BYTE(data1)

we treat data1 as utf-8 string.

example 2:

ECI(utf-8) - BYTE(data1) - NUMERIC(data2) - ECI(shift_jis) - BYTE(data3)

we treat

  • data1 as utf-8 string.
  • data2 as numeric data.
  • data3 as shift_jis data.

kanji mode

kanjis can be encoded with utf-8 but, kanji mode is more efficient.

about utf-8

there are several ways to use utf-8 in qrcode

  • just use utf-8 bytes some qrcode reader can just detect if utf-8 is used but others doesn’t.
  • ECI mode we can define to use utf-8 encoding using ECI mode. but similarly, some qrcode reader doesn’t support ECI mode.
  • byte order mark (BOM) we can use byte order mark (BOM) 0xEF 0xBB 0xBF at the front of the bytes.

error correction

qrcode uses Reed–Solomon error correction

error correction levels:

levelcapability
L(low)7%
M(medium)15%
Q(quartile)25%
H(high)30%

versions

the different sizes of qr codes are called versions.

version N is (17+4N)x(17+4N) pixels (1 <= N <= 40) so, version 1 is 21x21, version 2 is 25x25, … , version 39 is 173x173, version 40 is 177x177.

since each version has a maximum capacity, we should choose version that fits out data.

we can determine version to use for data with character capacities table

character counting

for each version and mode, data character count reserves a specific bits.

vernumalphanumbytekanji
1-910 bits9 bits8 bits8 bits
10-2612 bits11 bits16 bits10 bits
27-4014 bits14 bits16 bits12 bits

data encoding

numeric mode [0001]

split digits into group of three digits (ltr). last group can be one or two digits long.

for non last group with number N:

  • convert to 10 bits binary

for last group with number N:

  •   0 <= N <= 9   : 4  bits binary
  •  10 <= N <= 99  : 7  bits binary
  • 100 <= N <= 999 : 10 bits binary

and yes, article that i read[↗] was wrong. look at [7.4.3 Numeric mode] in the ISO/IEC 18004:2015 QR code standard specification.

example
=== example start ===

let's assume err corr level as L(low).

[42805902]
    → numeric mode <0001>
    → 8 chars → ver 1 → <00 00001000>

[42805902]
 ↓
[428] [059] [02]
 ↓
[428] [59]  [2]
 ↓
<01 10101100> <00 00111011> <0010>
 ↓
<01101011 00000011 10110010>

 ↓

final bits:
 <0001 0000001000 01101011 00000011 
  10110010>

=== example end ===

alphanumeric mode [0010]

split characters into group of two characters (ltr). last group can be a single character.

for each pair, treat two character as a base 45 number and convert to 11 bits binary (left pad with zeros).

if the pair is [RA], R and A each converts to 27 and 10 so in base 45, it’s (27 × 45) + 10 = 1225 = 100 1100 1001(2)

if last group is a single character, convert it to 6 bits binary.

example
=== example start ===

let's assume err corr level as L(low).

[RAWPLUG2026 10 15]
    → alphanumeric mode <0010>
    → 18 chars → ver 1 → <00 00010010>

[RAWPLUG2026 10 15]
 ↓
[RA] [WP] [LU] [G2] [02] [6 ] [10] [ 1] [5]
 ↓
[WP] → (32 * 45) + 25 = 1465 = <101 10111001>
[RA] → (27 * 45) + 10 = 1225 = <100 11001001>
[LU] → (21 * 45) + 30 =  975 = <011 11001111>
[G2] → (16 * 45) +  2 =  722 = <010 11010010>
[02] → ( 0 * 45) +  2 =    2 = <000 00000010>
[6 ] → ( 6 * 45) + 36 = 0306 = <001 00110010>
[10] → ( 1 * 45) +  0 =   45 = <000 00101101>
[ 1] → (36 * 45) +  1 = 1621 = <110 01010101>
[5]  → 5                     =       <000101>
 ↓
 <10110111 00110011 00100101 11100111
  10101101 00100000 00000100 01001100
  10000001 01101110 01010101 000101>

 ↓

final bits:
 <0010 0000010010 10110111 00110011 
  00100101 11100111 10101101 00100000 
  00000100 01001100 10000001 01101110 
  01010101 000101>

=== example end ===

kanji mode [1000]

…

i don’t know whether should i learn about this mode, honestly.

byte mode [0100]

when it comes to bytes, there’s nothing to encode. bytes are just raw binary data.

example
=== example start ===

let's assume err corr level as L(low).

[6D AC D3 B4 25 12]
    → byte mode <0100>
    → 6 chars(bytes) → ver 1 → <00 00000110>

[6D AC D3 B4 25 12]
 ↓
<01101101 10101100 11010011 10110100 00100101 00010010>

 ↓

final bits:
 <0100 0000000110 01101101 10101100 
  11010011 10110100 00100101 00010010>

=== example end ===

ECI mode [0111]

byte mode alone doesn’t contains data about encoding by default (some qrcode readers do detect utf-8). using ECI mode, we can define encoding for byte mode.

ECI Designator:

assignment valueno.bits
000000-00012710bbbbbbb(2) (8-bit)
000128-016383210bbbbbb bbbbbbbb(2) (16-bit)
016384-9999993110bbbbb bbbbbbbb bbbbbbbb(2) (24-bit)
(where b…b is value bits)

list of supported ECI encodings[↗]

example
=== example start ===

let's assume err corr level as L(low).

[bong]
    → eci mode <0111>
    → utf-8 format \000026 → <00011010>

    → byte mode <0100>
    → 4 chars(bytes) → ver 1 → <00 00000100>

[bong]
 ↓
[62 6F 6E 67]
 ↓
<01100010 01101111 01101110 01100111>

final bits:
 <0111 00011010 0100 00 00000100 
  01100010 01101111 01101110 01100111>

=== example end ===

appendix

a. alphanumeric table

uppercase only for alphabets.

alphanumeric table
charindexnote
00
11
22
33
44
55
66
77
88
99
A10
B11
C12
D13
E14
F15
G16
H17
I18
J19
K20
L21
M22
N23
O24
P25
Q26
R27
S28
T29
U30
V31
W32
X33
Y34
Z35
36(space)
$37
%38
*39
+40
-41
.42
/43
:44

b. character capacities

character capacities
vererr corrnumalphanumbytekanji.vererr corrnumalphanumbytekanji
1L41251710.21L22321352929572
M3420148.M17081035711438
Q2716117.Q1224742509314
H171074.H969587403248
------.------
2L77473220.22L240914601003618
M63382616.M18721134779480
Q48292012.Q1358823565348
H3420148.H1056640439270
------.------
3L127775332.23L262015881091672
M101614226.M20591248857528
Q77473220.Q1468890611376
H58352415.H1108672461284
------.------
4L1871147848.24L281217041171721
M149906238.M21881326911561
Q111674628.Q1588963661407
H82503421.H1228744511315
------.------
5L25515410665.25L305718531273784
M2021228452.M23951451997614
Q144876037.Q17181041715440
H106644427.H1286779535330
------.------
6L32219513482.26L328319901367842
M25515410665.M254415421059652
Q1781087445.Q18041094751462
H139845836.H1425864593365
------.------
7L37022415495.27L351721321465902
M29317812275.M270116371125692
Q2071258653.Q19331172805496
H154936439.H1501910625385
------.------
8L461279192118.28L366922231528940
M36522115293.M285717321190732
Q25915710866.Q20851263868534
H2021228452.H1581958658405
------.------
9L552335230141.29L3909236916281002
M432262180111.M303518391264778
Q31218913080.Q21811322908559
H2351439860.H16771016698430
------.------
10L652395271167.30L4158252017321066
M513311213131.M328919941370843
Q36422115193.Q23581429982604
H28817411974.H17821080742457
------.------
11L772468321198.31L4417267718401132
M604366251155.M348621131452894
Q427259177109.Q247314991030634
H33120013785.H18971150790486
------.------
12L883535367226.32L4686284019521201
M691419287177.M369322381538947
Q489296203125.Q267016181112684
H37422715596.H20221226842518
------.------
13L1022619425262.33L4965300920681273
M796483331204.M3909236916281002
Q580352241149.Q280517001168719
H427259177109.H21571307898553
------.------
14L1101667458282.34L5253318321881347
M871528362223.M4134250617221060
Q621376258159.Q294917871228756
H468283194120.H23011394958590
------.------
15L1250758520320.35L5529335123031417
M991600412254.M4343263218091113
Q703426292180.Q308118671283790
H530321220136.H23611431983605
------.------
16L1408854586361.36L5836353724311496
M1082656450277.M4588278019111176
Q775470322198.Q324419661351832
H602365250154.H252415301051647
------.------
17L1548938644397.37L6153372925631577
M1212734504310.M4775289419891224
Q876531364224.Q341720711423876
H674408280173.H262515911093673
------.------
18L17251046718442.38L6479392726991661
M1346816560345.M5039305420991292
Q948574394243.Q359921811499923
H746452310191.H273516581139701
------.------
19L19031153792488.39L6743408728091729
M1500909624384.M5313322022131362
Q1063644442272.Q379122981579972
H813493338208.H292717741219750
------.------
20L20611249858528.40L7089429629531817
M1600970666410.M5596339123311435
Q1159702482297.Q3993242016631024
H919557382235.H305718521273784

Webmentions[0]

    Q. Why isn't my webmention not appearing?

    A. I deploy this site not so often and this site is static site. So don't expect your webmention to appear instantly. Thanks for the webmention and sorry for the inconvenience.
    last deployed: see footer