1package qr
2
3import "math"
4
5// ErrorCorrectionLevel indicates the amount of "backup data" stored in the QR code
6type ErrorCorrectionLevel byte
7
8const (
9	// L recovers 7% of data
10	L ErrorCorrectionLevel = iota
11	// M recovers 15% of data
12	M
13	// Q recovers 25% of data
14	Q
15	// H recovers 30% of data
16	H
17)
18
19func (ecl ErrorCorrectionLevel) String() string {
20	switch ecl {
21	case L:
22		return "L"
23	case M:
24		return "M"
25	case Q:
26		return "Q"
27	case H:
28		return "H"
29	}
30	return "unknown"
31}
32
33type encodingMode byte
34
35const (
36	numericMode      encodingMode = 1
37	alphaNumericMode encodingMode = 2
38	byteMode         encodingMode = 4
39	kanjiMode        encodingMode = 8
40)
41
42type versionInfo struct {
43	Version                          byte
44	Level                            ErrorCorrectionLevel
45	ErrorCorrectionCodewordsPerBlock byte
46	NumberOfBlocksInGroup1           byte
47	DataCodeWordsPerBlockInGroup1    byte
48	NumberOfBlocksInGroup2           byte
49	DataCodeWordsPerBlockInGroup2    byte
50}
51
52var versionInfos = []*versionInfo{
53	&versionInfo{1, L, 7, 1, 19, 0, 0},
54	&versionInfo{1, M, 10, 1, 16, 0, 0},
55	&versionInfo{1, Q, 13, 1, 13, 0, 0},
56	&versionInfo{1, H, 17, 1, 9, 0, 0},
57	&versionInfo{2, L, 10, 1, 34, 0, 0},
58	&versionInfo{2, M, 16, 1, 28, 0, 0},
59	&versionInfo{2, Q, 22, 1, 22, 0, 0},
60	&versionInfo{2, H, 28, 1, 16, 0, 0},
61	&versionInfo{3, L, 15, 1, 55, 0, 0},
62	&versionInfo{3, M, 26, 1, 44, 0, 0},
63	&versionInfo{3, Q, 18, 2, 17, 0, 0},
64	&versionInfo{3, H, 22, 2, 13, 0, 0},
65	&versionInfo{4, L, 20, 1, 80, 0, 0},
66	&versionInfo{4, M, 18, 2, 32, 0, 0},
67	&versionInfo{4, Q, 26, 2, 24, 0, 0},
68	&versionInfo{4, H, 16, 4, 9, 0, 0},
69	&versionInfo{5, L, 26, 1, 108, 0, 0},
70	&versionInfo{5, M, 24, 2, 43, 0, 0},
71	&versionInfo{5, Q, 18, 2, 15, 2, 16},
72	&versionInfo{5, H, 22, 2, 11, 2, 12},
73	&versionInfo{6, L, 18, 2, 68, 0, 0},
74	&versionInfo{6, M, 16, 4, 27, 0, 0},
75	&versionInfo{6, Q, 24, 4, 19, 0, 0},
76	&versionInfo{6, H, 28, 4, 15, 0, 0},
77	&versionInfo{7, L, 20, 2, 78, 0, 0},
78	&versionInfo{7, M, 18, 4, 31, 0, 0},
79	&versionInfo{7, Q, 18, 2, 14, 4, 15},
80	&versionInfo{7, H, 26, 4, 13, 1, 14},
81	&versionInfo{8, L, 24, 2, 97, 0, 0},
82	&versionInfo{8, M, 22, 2, 38, 2, 39},
83	&versionInfo{8, Q, 22, 4, 18, 2, 19},
84	&versionInfo{8, H, 26, 4, 14, 2, 15},
85	&versionInfo{9, L, 30, 2, 116, 0, 0},
86	&versionInfo{9, M, 22, 3, 36, 2, 37},
87	&versionInfo{9, Q, 20, 4, 16, 4, 17},
88	&versionInfo{9, H, 24, 4, 12, 4, 13},
89	&versionInfo{10, L, 18, 2, 68, 2, 69},
90	&versionInfo{10, M, 26, 4, 43, 1, 44},
91	&versionInfo{10, Q, 24, 6, 19, 2, 20},
92	&versionInfo{10, H, 28, 6, 15, 2, 16},
93	&versionInfo{11, L, 20, 4, 81, 0, 0},
94	&versionInfo{11, M, 30, 1, 50, 4, 51},
95	&versionInfo{11, Q, 28, 4, 22, 4, 23},
96	&versionInfo{11, H, 24, 3, 12, 8, 13},
97	&versionInfo{12, L, 24, 2, 92, 2, 93},
98	&versionInfo{12, M, 22, 6, 36, 2, 37},
99	&versionInfo{12, Q, 26, 4, 20, 6, 21},
100	&versionInfo{12, H, 28, 7, 14, 4, 15},
101	&versionInfo{13, L, 26, 4, 107, 0, 0},
102	&versionInfo{13, M, 22, 8, 37, 1, 38},
103	&versionInfo{13, Q, 24, 8, 20, 4, 21},
104	&versionInfo{13, H, 22, 12, 11, 4, 12},
105	&versionInfo{14, L, 30, 3, 115, 1, 116},
106	&versionInfo{14, M, 24, 4, 40, 5, 41},
107	&versionInfo{14, Q, 20, 11, 16, 5, 17},
108	&versionInfo{14, H, 24, 11, 12, 5, 13},
109	&versionInfo{15, L, 22, 5, 87, 1, 88},
110	&versionInfo{15, M, 24, 5, 41, 5, 42},
111	&versionInfo{15, Q, 30, 5, 24, 7, 25},
112	&versionInfo{15, H, 24, 11, 12, 7, 13},
113	&versionInfo{16, L, 24, 5, 98, 1, 99},
114	&versionInfo{16, M, 28, 7, 45, 3, 46},
115	&versionInfo{16, Q, 24, 15, 19, 2, 20},
116	&versionInfo{16, H, 30, 3, 15, 13, 16},
117	&versionInfo{17, L, 28, 1, 107, 5, 108},
118	&versionInfo{17, M, 28, 10, 46, 1, 47},
119	&versionInfo{17, Q, 28, 1, 22, 15, 23},
120	&versionInfo{17, H, 28, 2, 14, 17, 15},
121	&versionInfo{18, L, 30, 5, 120, 1, 121},
122	&versionInfo{18, M, 26, 9, 43, 4, 44},
123	&versionInfo{18, Q, 28, 17, 22, 1, 23},
124	&versionInfo{18, H, 28, 2, 14, 19, 15},
125	&versionInfo{19, L, 28, 3, 113, 4, 114},
126	&versionInfo{19, M, 26, 3, 44, 11, 45},
127	&versionInfo{19, Q, 26, 17, 21, 4, 22},
128	&versionInfo{19, H, 26, 9, 13, 16, 14},
129	&versionInfo{20, L, 28, 3, 107, 5, 108},
130	&versionInfo{20, M, 26, 3, 41, 13, 42},
131	&versionInfo{20, Q, 30, 15, 24, 5, 25},
132	&versionInfo{20, H, 28, 15, 15, 10, 16},
133	&versionInfo{21, L, 28, 4, 116, 4, 117},
134	&versionInfo{21, M, 26, 17, 42, 0, 0},
135	&versionInfo{21, Q, 28, 17, 22, 6, 23},
136	&versionInfo{21, H, 30, 19, 16, 6, 17},
137	&versionInfo{22, L, 28, 2, 111, 7, 112},
138	&versionInfo{22, M, 28, 17, 46, 0, 0},
139	&versionInfo{22, Q, 30, 7, 24, 16, 25},
140	&versionInfo{22, H, 24, 34, 13, 0, 0},
141	&versionInfo{23, L, 30, 4, 121, 5, 122},
142	&versionInfo{23, M, 28, 4, 47, 14, 48},
143	&versionInfo{23, Q, 30, 11, 24, 14, 25},
144	&versionInfo{23, H, 30, 16, 15, 14, 16},
145	&versionInfo{24, L, 30, 6, 117, 4, 118},
146	&versionInfo{24, M, 28, 6, 45, 14, 46},
147	&versionInfo{24, Q, 30, 11, 24, 16, 25},
148	&versionInfo{24, H, 30, 30, 16, 2, 17},
149	&versionInfo{25, L, 26, 8, 106, 4, 107},
150	&versionInfo{25, M, 28, 8, 47, 13, 48},
151	&versionInfo{25, Q, 30, 7, 24, 22, 25},
152	&versionInfo{25, H, 30, 22, 15, 13, 16},
153	&versionInfo{26, L, 28, 10, 114, 2, 115},
154	&versionInfo{26, M, 28, 19, 46, 4, 47},
155	&versionInfo{26, Q, 28, 28, 22, 6, 23},
156	&versionInfo{26, H, 30, 33, 16, 4, 17},
157	&versionInfo{27, L, 30, 8, 122, 4, 123},
158	&versionInfo{27, M, 28, 22, 45, 3, 46},
159	&versionInfo{27, Q, 30, 8, 23, 26, 24},
160	&versionInfo{27, H, 30, 12, 15, 28, 16},
161	&versionInfo{28, L, 30, 3, 117, 10, 118},
162	&versionInfo{28, M, 28, 3, 45, 23, 46},
163	&versionInfo{28, Q, 30, 4, 24, 31, 25},
164	&versionInfo{28, H, 30, 11, 15, 31, 16},
165	&versionInfo{29, L, 30, 7, 116, 7, 117},
166	&versionInfo{29, M, 28, 21, 45, 7, 46},
167	&versionInfo{29, Q, 30, 1, 23, 37, 24},
168	&versionInfo{29, H, 30, 19, 15, 26, 16},
169	&versionInfo{30, L, 30, 5, 115, 10, 116},
170	&versionInfo{30, M, 28, 19, 47, 10, 48},
171	&versionInfo{30, Q, 30, 15, 24, 25, 25},
172	&versionInfo{30, H, 30, 23, 15, 25, 16},
173	&versionInfo{31, L, 30, 13, 115, 3, 116},
174	&versionInfo{31, M, 28, 2, 46, 29, 47},
175	&versionInfo{31, Q, 30, 42, 24, 1, 25},
176	&versionInfo{31, H, 30, 23, 15, 28, 16},
177	&versionInfo{32, L, 30, 17, 115, 0, 0},
178	&versionInfo{32, M, 28, 10, 46, 23, 47},
179	&versionInfo{32, Q, 30, 10, 24, 35, 25},
180	&versionInfo{32, H, 30, 19, 15, 35, 16},
181	&versionInfo{33, L, 30, 17, 115, 1, 116},
182	&versionInfo{33, M, 28, 14, 46, 21, 47},
183	&versionInfo{33, Q, 30, 29, 24, 19, 25},
184	&versionInfo{33, H, 30, 11, 15, 46, 16},
185	&versionInfo{34, L, 30, 13, 115, 6, 116},
186	&versionInfo{34, M, 28, 14, 46, 23, 47},
187	&versionInfo{34, Q, 30, 44, 24, 7, 25},
188	&versionInfo{34, H, 30, 59, 16, 1, 17},
189	&versionInfo{35, L, 30, 12, 121, 7, 122},
190	&versionInfo{35, M, 28, 12, 47, 26, 48},
191	&versionInfo{35, Q, 30, 39, 24, 14, 25},
192	&versionInfo{35, H, 30, 22, 15, 41, 16},
193	&versionInfo{36, L, 30, 6, 121, 14, 122},
194	&versionInfo{36, M, 28, 6, 47, 34, 48},
195	&versionInfo{36, Q, 30, 46, 24, 10, 25},
196	&versionInfo{36, H, 30, 2, 15, 64, 16},
197	&versionInfo{37, L, 30, 17, 122, 4, 123},
198	&versionInfo{37, M, 28, 29, 46, 14, 47},
199	&versionInfo{37, Q, 30, 49, 24, 10, 25},
200	&versionInfo{37, H, 30, 24, 15, 46, 16},
201	&versionInfo{38, L, 30, 4, 122, 18, 123},
202	&versionInfo{38, M, 28, 13, 46, 32, 47},
203	&versionInfo{38, Q, 30, 48, 24, 14, 25},
204	&versionInfo{38, H, 30, 42, 15, 32, 16},
205	&versionInfo{39, L, 30, 20, 117, 4, 118},
206	&versionInfo{39, M, 28, 40, 47, 7, 48},
207	&versionInfo{39, Q, 30, 43, 24, 22, 25},
208	&versionInfo{39, H, 30, 10, 15, 67, 16},
209	&versionInfo{40, L, 30, 19, 118, 6, 119},
210	&versionInfo{40, M, 28, 18, 47, 31, 48},
211	&versionInfo{40, Q, 30, 34, 24, 34, 25},
212	&versionInfo{40, H, 30, 20, 15, 61, 16},
213}
214
215func (vi *versionInfo) totalDataBytes() int {
216	g1Data := int(vi.NumberOfBlocksInGroup1) * int(vi.DataCodeWordsPerBlockInGroup1)
217	g2Data := int(vi.NumberOfBlocksInGroup2) * int(vi.DataCodeWordsPerBlockInGroup2)
218	return (g1Data + g2Data)
219}
220
221func (vi *versionInfo) charCountBits(m encodingMode) byte {
222	switch m {
223	case numericMode:
224		if vi.Version < 10 {
225			return 10
226		} else if vi.Version < 27 {
227			return 12
228		}
229		return 14
230
231	case alphaNumericMode:
232		if vi.Version < 10 {
233			return 9
234		} else if vi.Version < 27 {
235			return 11
236		}
237		return 13
238
239	case byteMode:
240		if vi.Version < 10 {
241			return 8
242		}
243		return 16
244
245	case kanjiMode:
246		if vi.Version < 10 {
247			return 8
248		} else if vi.Version < 27 {
249			return 10
250		}
251		return 12
252	default:
253		return 0
254	}
255}
256
257func (vi *versionInfo) modulWidth() int {
258	return ((int(vi.Version) - 1) * 4) + 21
259}
260
261func (vi *versionInfo) alignmentPatternPlacements() []int {
262	if vi.Version == 1 {
263		return make([]int, 0)
264	}
265
266	first := 6
267	last := vi.modulWidth() - 7
268	space := float64(last - first)
269	count := int(math.Ceil(space/28)) + 1
270
271	result := make([]int, count)
272	result[0] = first
273	result[len(result)-1] = last
274	if count > 2 {
275		step := int(math.Ceil(float64(last-first) / float64(count-1)))
276		if step%2 == 1 {
277			frac := float64(last-first) / float64(count-1)
278			_, x := math.Modf(frac)
279			if x >= 0.5 {
280				frac = math.Ceil(frac)
281			} else {
282				frac = math.Floor(frac)
283			}
284
285			if int(frac)%2 == 0 {
286				step--
287			} else {
288				step++
289			}
290		}
291
292		for i := 1; i <= count-2; i++ {
293			result[i] = last - (step * (count - 1 - i))
294		}
295	}
296
297	return result
298}
299
300func findSmallestVersionInfo(ecl ErrorCorrectionLevel, mode encodingMode, dataBits int) *versionInfo {
301	dataBits = dataBits + 4 // mode indicator
302	for _, vi := range versionInfos {
303		if vi.Level == ecl {
304			if (vi.totalDataBytes() * 8) >= (dataBits + int(vi.charCountBits(mode))) {
305				return vi
306			}
307		}
308	}
309	return nil
310}
311