OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
181 ilm 1
/*
2
 * Copyright 2014 Robin Stuart
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5
 * in compliance with the License. You may obtain a copy of the License at
6
 *
7
 * http://www.apache.org/licenses/LICENSE-2.0
8
 *
9
 * Unless required by applicable law or agreed to in writing, software distributed under the License
10
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11
 * or implied. See the License for the specific language governing permissions and limitations under
12
 * the License.
13
 */
14
package uk.org.okapibarcode.backend;
15
 
16
import static uk.org.okapibarcode.util.Arrays.positionOf;
17
 
18
import java.nio.CharBuffer;
19
import java.nio.charset.Charset;
20
 
21
/**
22
 * <p>
23
 * Implements QR Code bar code symbology According to ISO/IEC 18004:2015.
24
 *
25
 * <p>
26
 * The maximum capacity of a (version 40) QR Code symbol is 7089 numeric digits, 4296 alphanumeric
27
 * characters or 2953 bytes of data. QR Code symbols can also be used to encode GS1 data. QR Code
28
 * symbols can encode characters in the Latin-1 set and Kanji characters which are members of the
29
 * Shift-JIS encoding scheme.
30
 *
31
 * @author <a href="mailto:rstuart114@gmail.com">Robin Stuart</a>
32
 */
33
public class QrCode extends Symbol {
34
 
35
    public enum EccLevel {
36
        L, M, Q, H
37
    }
38
 
39
    private enum QrMode {
40
        NULL, KANJI, BINARY, ALPHANUM, NUMERIC
41
    }
42
 
43
    /* Table 5 - Encoding/Decoding table for Alphanumeric mode */
44
    private static final char[] RHODIUM = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
45
            'V', 'W', 'X', 'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':' };
46
 
47
    private static final int[] QR_DATA_CODEWORDS_L = { 19, 34, 55, 80, 108, 136, 156, 194, 232, 274, 324, 370, 428, 461, 523, 589, 647, 721, 795, 861, 932, 1006, 1094, 1174, 1276, 1370, 1468, 1531,
48
            1631, 1735, 1843, 1955, 2071, 2191, 2306, 2434, 2566, 2702, 2812, 2956 };
49
 
50
    private static final int[] QR_DATA_CODEWORDS_M = { 16, 28, 44, 64, 86, 108, 124, 154, 182, 216, 254, 290, 334, 365, 415, 453, 507, 563, 627, 669, 714, 782, 860, 914, 1000, 1062, 1128, 1193, 1267,
51
            1373, 1455, 1541, 1631, 1725, 1812, 1914, 1992, 2102, 2216, 2334 };
52
 
53
    private static final int[] QR_DATA_CODEWORDS_Q = { 13, 22, 34, 48, 62, 76, 88, 110, 132, 154, 180, 206, 244, 261, 295, 325, 367, 397, 445, 485, 512, 568, 614, 664, 718, 754, 808, 871, 911, 985,
54
            1033, 1115, 1171, 1231, 1286, 1354, 1426, 1502, 1582, 1666 };
55
 
56
    private static final int[] QR_DATA_CODEWORDS_H = { 9, 16, 26, 36, 46, 60, 66, 86, 100, 122, 140, 158, 180, 197, 223, 253, 283, 313, 341, 385, 406, 442, 464, 514, 538, 596, 628, 661, 701, 745, 793,
57
            845, 901, 961, 986, 1054, 1096, 1142, 1222, 1276 };
58
 
59
    private static final int[] QR_BLOCKS_L = { 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 };
60
 
61
    private static final int[] QR_BLOCKS_M = { 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 };
62
 
63
    private static final int[] QR_BLOCKS_Q = { 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 };
64
 
65
    private static final int[] QR_BLOCKS_H = { 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 };
66
 
67
    private static final int[] QR_TOTAL_CODEWORDS = { 26, 44, 70, 100, 134, 172, 196, 242, 292, 346, 404, 466, 532, 581, 655, 733, 815, 901, 991, 1085, 1156, 1258, 1364, 1474, 1588, 1706, 1828, 1921,
68
            2051, 2185, 2323, 2465, 2611, 2761, 2876, 3034, 3196, 3362, 3532, 3706 };
69
 
70
    private static final int[] QR_SIZES = { 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 129, 133, 137, 141, 145, 149, 153, 157,
71
            161, 165, 169, 173, 177 };
72
 
73
    private static final int[] QR_ALIGN_LOOPSIZE = { 0, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7 };
74
 
75
    private static final int[] QR_TABLE_E1 = { 6, 18, 0, 0, 0, 0, 0, 6, 22, 0, 0, 0, 0, 0, 6, 26, 0, 0, 0, 0, 0, 6, 30, 0, 0, 0, 0, 0, 6, 34, 0, 0, 0, 0, 0, 6, 22, 38, 0, 0, 0, 0, 6, 24, 42, 0, 0, 0,
76
            0, 6, 26, 46, 0, 0, 0, 0, 6, 28, 50, 0, 0, 0, 0, 6, 30, 54, 0, 0, 0, 0, 6, 32, 58, 0, 0, 0, 0, 6, 34, 62, 0, 0, 0, 0, 6, 26, 46, 66, 0, 0, 0, 6, 26, 48, 70, 0, 0, 0, 6, 26, 50, 74, 0, 0,
77
            0, 6, 30, 54, 78, 0, 0, 0, 6, 30, 56, 82, 0, 0, 0, 6, 30, 58, 86, 0, 0, 0, 6, 34, 62, 90, 0, 0, 0, 6, 28, 50, 72, 94, 0, 0, 6, 26, 50, 74, 98, 0, 0, 6, 30, 54, 78, 102, 0, 0, 6, 28, 54,
78
            80, 106, 0, 0, 6, 32, 58, 84, 110, 0, 0, 6, 30, 58, 86, 114, 0, 0, 6, 34, 62, 90, 118, 0, 0, 6, 26, 50, 74, 98, 122, 0, 6, 30, 54, 78, 102, 126, 0, 6, 26, 52, 78, 104, 130, 0, 6, 30, 56,
79
            82, 108, 134, 0, 6, 34, 60, 86, 112, 138, 0, 6, 30, 58, 86, 114, 142, 0, 6, 34, 62, 90, 118, 146, 0, 6, 30, 54, 78, 102, 126, 150, 6, 24, 50, 76, 102, 128, 154, 6, 28, 54, 80, 106, 132,
80
            158, 6, 32, 58, 84, 110, 136, 162, 6, 26, 54, 82, 110, 138, 166, 6, 30, 58, 86, 114, 142, 170 };
81
 
82
    private static final int[] QR_ANNEX_C = {
83
            /* Format information bit sequences */
84
            0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, 0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976, 0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c,
85
            0x083b, 0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed };
86
 
87
    private static final int[] QR_ANNEX_D = {
88
            /* Version information bit sequences */
89
            0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e,
90
            0x1cc1a, 0x1d33f, 0x1ed75, 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, 0x27541, 0x28c69 };
91
 
92
    private int preferredVersion;
93
    private EccLevel preferredEccLevel = EccLevel.L;
94
 
95
    /**
96
     * Sets the preferred symbol size / version. This value may be ignored if the data string is too
97
     * large to fit into the specified symbol. Input values correspond to symbol sizes as shown in
98
     * the following table:
99
     *
100
     * <table summary="Available QR Code sizes">
101
     * <tbody>
102
     * <tr>
103
     * <th>Input</th>
104
     * <th>Symbol Size</th>
105
     * <th>Input</th>
106
     * <th>Symbol Size</th>
107
     * </tr>
108
     * <tr>
109
     * <td>1</td>
110
     * <td>21 x 21</td>
111
     * <td>21</td>
112
     * <td>101 x 101</td>
113
     * </tr>
114
     * <tr>
115
     * <td>2</td>
116
     * <td>25 x 25</td>
117
     * <td>22</td>
118
     * <td>105 x 105</td>
119
     * </tr>
120
     * <tr>
121
     * <td>3</td>
122
     * <td>29 x 29</td>
123
     * <td>23</td>
124
     * <td>109 x 109</td>
125
     * </tr>
126
     * <tr>
127
     * <td>4</td>
128
     * <td>33 x 33</td>
129
     * <td>24</td>
130
     * <td>113 x 113</td>
131
     * </tr>
132
     * <tr>
133
     * <td>5</td>
134
     * <td>37 x 37</td>
135
     * <td>25</td>
136
     * <td>117 x 117</td>
137
     * </tr>
138
     * <tr>
139
     * <td>6</td>
140
     * <td>41 x 41</td>
141
     * <td>26</td>
142
     * <td>121 x 121</td>
143
     * </tr>
144
     * <tr>
145
     * <td>7</td>
146
     * <td>45 x 45</td>
147
     * <td>27</td>
148
     * <td>125 x 125</td>
149
     * </tr>
150
     * <tr>
151
     * <td>8</td>
152
     * <td>49 x 49</td>
153
     * <td>28</td>
154
     * <td>129 x 129</td>
155
     * </tr>
156
     * <tr>
157
     * <td>9</td>
158
     * <td>53 x 53</td>
159
     * <td>29</td>
160
     * <td>133 x 133</td>
161
     * </tr>
162
     * <tr>
163
     * <td>10</td>
164
     * <td>57 x 57</td>
165
     * <td>30</td>
166
     * <td>137 x 137</td>
167
     * </tr>
168
     * <tr>
169
     * <td>11</td>
170
     * <td>61 x 61</td>
171
     * <td>31</td>
172
     * <td>141 x 141</td>
173
     * </tr>
174
     * <tr>
175
     * <td>12</td>
176
     * <td>65 x 65</td>
177
     * <td>32</td>
178
     * <td>145 x 145</td>
179
     * </tr>
180
     * <tr>
181
     * <td>13</td>
182
     * <td>69 x 69</td>
183
     * <td>33</td>
184
     * <td>149 x 149</td>
185
     * </tr>
186
     * <tr>
187
     * <td>14</td>
188
     * <td>73 x 73</td>
189
     * <td>34</td>
190
     * <td>153 x 153</td>
191
     * </tr>
192
     * <tr>
193
     * <td>15</td>
194
     * <td>77 x 77</td>
195
     * <td>35</td>
196
     * <td>157 x 157</td>
197
     * </tr>
198
     * <tr>
199
     * <td>16</td>
200
     * <td>81 x 81</td>
201
     * <td>36</td>
202
     * <td>161 x 161</td>
203
     * </tr>
204
     * <tr>
205
     * <td>17</td>
206
     * <td>85 x 85</td>
207
     * <td>37</td>
208
     * <td>165 x 165</td>
209
     * </tr>
210
     * <tr>
211
     * <td>18</td>
212
     * <td>89 x 89</td>
213
     * <td>38</td>
214
     * <td>169 x 169</td>
215
     * </tr>
216
     * <tr>
217
     * <td>19</td>
218
     * <td>93 x 93</td>
219
     * <td>39</td>
220
     * <td>173 x 173</td>
221
     * </tr>
222
     * <tr>
223
     * <td>20</td>
224
     * <td>97 x 97</td>
225
     * <td>40</td>
226
     * <td>177 x 177</td>
227
     * </tr>
228
     * </tbody>
229
     * </table>
230
     *
231
     * @param version the preferred symbol version
232
     */
233
    public void setPreferredVersion(final int version) {
234
        this.preferredVersion = version;
235
    }
236
 
237
    /**
238
     * Returns the preferred symbol version.
239
     *
240
     * @return the preferred symbol version
241
     */
242
    public int getPreferredVersion() {
243
        return this.preferredVersion;
244
    }
245
 
246
    /**
247
     * Sets the preferred amount of symbol space allocated to error correction. This value may be
248
     * ignored if there is room for a higher error correction level. Levels are predefined according
249
     * to the following table:
250
     *
251
     * <table summary="QR Code error correction levels">
252
     * <tbody>
253
     * <tr>
254
     * <th>ECC Level</th>
255
     * <th>Error Correction Capacity</th>
256
     * <th>Recovery Capacity</th>
257
     * </tr>
258
     * <tr>
259
     * <td>L (default)</td>
260
     * <td>Approx 20% of symbol</td>
261
     * <td>Approx 7%</td>
262
     * </tr>
263
     * <tr>
264
     * <td>M</td>
265
     * <td>Approx 37% of symbol</td>
266
     * <td>Approx 15%</td>
267
     * </tr>
268
     * <tr>
269
     * <td>Q</td>
270
     * <td>Approx 55% of symbol</td>
271
     * <td>Approx 25%</td>
272
     * </tr>
273
     * <tr>
274
     * <td>H</td>
275
     * <td>Approx 65% of symbol</td>
276
     * <td>Approx 30%</td>
277
     * </tr>
278
     * </tbody>
279
     * </table>
280
     *
281
     * @param preferredEccLevel the preferred error correction level
282
     */
283
    public void setPreferredEccLevel(final EccLevel preferredEccLevel) {
284
        this.preferredEccLevel = preferredEccLevel;
285
    }
286
 
287
    /**
288
     * Returns the preferred amount of symbol space allocated to error correction.
289
     *
290
     * @return the preferred amount of symbol space allocated to error correction
291
     */
292
    public EccLevel getPreferredEccLevel() {
293
        return this.preferredEccLevel;
294
    }
295
 
296
    @Override
297
    protected boolean gs1Supported() {
298
        return true;
299
    }
300
 
301
    @Override
302
    protected void encode() {
303
 
304
        int i, j;
305
        int est_binlen;
306
        EccLevel ecc_level;
307
        int max_cw;
308
        int targetCwCount, version, blocks;
309
        int size;
310
        int bitmask;
311
        final boolean gs1 = this.inputDataType == DataType.GS1;
312
 
313
        eciProcess(); // Get ECI mode
314
 
315
        if (this.eciMode == 20) {
316
            /* Shift-JIS encoding, use Kanji mode */
317
            final Charset c = Charset.forName("Shift_JIS");
318
            this.inputData = new int[this.content.length()];
319
            for (i = 0; i < this.inputData.length; i++) {
320
                final CharBuffer buffer = CharBuffer.wrap(this.content, i, i + 1);
321
                final byte[] bytes = c.encode(buffer).array();
322
                final int value = bytes.length == 2 ? (bytes[0] & 0xff) << 8 | bytes[1] & 0xff : bytes[0];
323
                this.inputData[i] = value;
324
            }
325
        } else {
326
            /* inputData already initialized in eciProcess() */
327
        }
328
 
329
        QrMode[] inputMode = new QrMode[this.inputData.length];
330
        defineMode(inputMode, this.inputData);
331
        est_binlen = getBinaryLength(40, inputMode, this.inputData, gs1, this.eciMode);
332
 
333
        ecc_level = this.preferredEccLevel;
334
        switch (this.preferredEccLevel) {
335
        case L:
336
        default:
337
            max_cw = 2956;
338
            break;
339
        case M:
340
            max_cw = 2334;
341
            break;
342
        case Q:
343
            max_cw = 1666;
344
            break;
345
        case H:
346
            max_cw = 1276;
347
            break;
348
        }
349
 
350
        if (est_binlen > 8 * max_cw) {
351
            throw new OkapiException("Input too long for selected error correction level");
352
        }
353
 
354
        // ZINT NOTE: this block is different from the corresponding block of code in Zint;
355
        // it is simplified, but the simplification required that the applyOptimisation method
356
        // be changed to be free of side effects (by putting the optimized mode array into a
357
        // new array instead of modifying the existing array)
358
 
359
        version = 40;
360
        for (i = 39; i >= 0; i--) {
361
            int[] dataCodewords;
362
            switch (ecc_level) {
363
            case L:
364
            default:
365
                dataCodewords = QR_DATA_CODEWORDS_L;
366
                break;
367
            case M:
368
                dataCodewords = QR_DATA_CODEWORDS_M;
369
                break;
370
            case Q:
371
                dataCodewords = QR_DATA_CODEWORDS_Q;
372
                break;
373
            case H:
374
                dataCodewords = QR_DATA_CODEWORDS_H;
375
                break;
376
            }
377
            final int proposedVersion = i + 1;
378
            final int proposedBinLen = getBinaryLength(proposedVersion, inputMode, this.inputData, gs1, this.eciMode);
379
            if (8 * dataCodewords[i] >= proposedBinLen) {
380
                version = proposedVersion;
381
                est_binlen = proposedBinLen;
382
            }
383
        }
384
 
385
        inputMode = applyOptimisation(version, inputMode);
386
 
387
        // ZINT NOTE: end of block of code that is different
388
 
389
        // TODO: delete this
390
        //
391
        // autosize = 40;
392
        // for (i = 39; i >= 0; i--) {
393
        // switch (ecc_level) {
394
        // case L:
395
        // if ((8 * QR_DATA_CODEWORDS_L[i]) >= est_binlen) {
396
        // autosize = i + 1;
397
        // }
398
        // break;
399
        // case M:
400
        // if ((8 * QR_DATA_CODEWORDS_M[i]) >= est_binlen) {
401
        // autosize = i + 1;
402
        // }
403
        // break;
404
        // case Q:
405
        // if ((8 * QR_DATA_CODEWORDS_Q[i]) >= est_binlen) {
406
        // autosize = i + 1;
407
        // }
408
        // break;
409
        // case H:
410
        // if ((8 * QR_DATA_CODEWORDS_H[i]) >= est_binlen) {
411
        // autosize = i + 1;
412
        // }
413
        // break;
414
        // }
415
        // }
416
        //
417
        // // Now see if the optimized binary will fit in a smaller symbol.
418
        // canShrink = true;
419
        //
420
        // do {
421
        // if (autosize == 1) {
422
        // est_binlen = getBinaryLength(autosize, inputMode, inputData, gs1, eciMode); // TODO:
423
        // added
424
        // canShrink = false;
425
        // } else {
426
        // est_binlen = getBinaryLength(autosize - 1, inputMode, inputData, gs1, eciMode);
427
        //
428
        // switch (ecc_level) {
429
        // case L:
430
        // if ((8 * QR_DATA_CODEWORDS_L[autosize - 2]) < est_binlen) {
431
        // canShrink = false;
432
        // }
433
        // break;
434
        // case M:
435
        // if ((8 * QR_DATA_CODEWORDS_M[autosize - 2]) < est_binlen) {
436
        // canShrink = false;
437
        // }
438
        // break;
439
        // case Q:
440
        // if ((8 * QR_DATA_CODEWORDS_Q[autosize - 2]) < est_binlen) {
441
        // canShrink = false;
442
        // }
443
        // break;
444
        // case H:
445
        // if ((8 * QR_DATA_CODEWORDS_H[autosize - 2]) < est_binlen) {
446
        // canShrink = false;
447
        // }
448
        // break;
449
        // }
450
        //
451
        // if (canShrink) {
452
        // // Optimization worked - data will fit in a smaller symbol
453
        // autosize--;
454
        // } else {
455
        // // Data did not fit in the smaller symbol, revert to original size
456
        // est_binlen = getBinaryLength(autosize, inputMode, inputData, gs1, eciMode);
457
        // }
458
        // }
459
        // } while (canShrink);
460
        //
461
        // version = autosize;
462
 
463
        if (this.preferredVersion >= 1 && this.preferredVersion <= 40) {
464
            /*
465
             * If the user has selected a larger symbol than the smallest available, then use the
466
             * size the user has selected, and re-optimize for this symbol size.
467
             */
468
            if (this.preferredVersion > version) {
469
                version = this.preferredVersion;
470
                est_binlen = getBinaryLength(this.preferredVersion, inputMode, this.inputData, gs1, this.eciMode);
471
                inputMode = applyOptimisation(version, inputMode);
472
            }
473
            if (this.preferredVersion < version) {
474
                throw new OkapiException("Input too long for selected symbol size");
475
            }
476
        }
477
 
478
        /* Ensure maximum error correction capacity */
479
        if (est_binlen <= QR_DATA_CODEWORDS_M[version - 1] * 8) {
480
            ecc_level = EccLevel.M;
481
        }
482
        if (est_binlen <= QR_DATA_CODEWORDS_Q[version - 1] * 8) {
483
            ecc_level = EccLevel.Q;
484
        }
485
        if (est_binlen <= QR_DATA_CODEWORDS_H[version - 1] * 8) {
486
            ecc_level = EccLevel.H;
487
        }
488
 
489
        targetCwCount = QR_DATA_CODEWORDS_L[version - 1];
490
        blocks = QR_BLOCKS_L[version - 1];
491
        switch (ecc_level) {
492
        case M:
493
            targetCwCount = QR_DATA_CODEWORDS_M[version - 1];
494
            blocks = QR_BLOCKS_M[version - 1];
495
            break;
496
        case Q:
497
            targetCwCount = QR_DATA_CODEWORDS_Q[version - 1];
498
            blocks = QR_BLOCKS_Q[version - 1];
499
            break;
500
        case H:
501
            targetCwCount = QR_DATA_CODEWORDS_H[version - 1];
502
            blocks = QR_BLOCKS_H[version - 1];
503
            break;
504
        }
505
 
506
        final int[] datastream = new int[targetCwCount + 1];
507
        final int[] fullstream = new int[QR_TOTAL_CODEWORDS[version - 1] + 1];
508
 
509
        qrBinary(datastream, version, targetCwCount, inputMode, this.inputData, gs1, this.eciMode, est_binlen);
510
        addEcc(fullstream, datastream, version, targetCwCount, blocks);
511
 
512
        size = QR_SIZES[version - 1];
513
 
514
        final int[] grid = new int[size * size];
515
 
516
        infoLine("Version: " + version);
517
        infoLine("ECC Level: " + ecc_level.name());
518
 
519
        setupGrid(grid, size, version);
520
        populateGrid(grid, size, fullstream, QR_TOTAL_CODEWORDS[version - 1]);
521
 
522
        if (version >= 7) {
523
            addVersionInfo(grid, size, version);
524
        }
525
 
526
        bitmask = applyBitmask(grid, size, ecc_level);
527
        infoLine("Mask Pattern: " + Integer.toBinaryString(bitmask));
528
        addFormatInfo(grid, size, ecc_level, bitmask);
529
 
530
        this.readable = "";
531
        this.pattern = new String[size];
532
        this.row_count = size;
533
        this.row_height = new int[size];
534
        for (i = 0; i < size; i++) {
535
            final StringBuilder bin = new StringBuilder(size);
536
            for (j = 0; j < size; j++) {
537
                if ((grid[i * size + j] & 0x01) != 0) {
538
                    bin.append('1');
539
                } else {
540
                    bin.append('0');
541
                }
542
            }
543
            this.pattern[i] = bin2pat(bin);
544
            this.row_height[i] = 1;
545
        }
546
    }
547
 
548
    /** Place Kanji / Binary / Alphanumeric / Numeric values in inputMode. */
549
    private static void defineMode(final QrMode[] inputMode, final int[] inputData) {
550
 
551
        for (int i = 0; i < inputData.length; i++) {
552
            if (inputData[i] > 0xff) {
553
                inputMode[i] = QrMode.KANJI;
554
            } else {
555
                inputMode[i] = QrMode.BINARY;
556
                if (isAlpha(inputData[i])) {
557
                    inputMode[i] = QrMode.ALPHANUM;
558
                }
559
                if (inputData[i] == FNC1) {
560
                    inputMode[i] = QrMode.ALPHANUM;
561
                }
562
                if (isNumeric(inputData[i])) {
563
                    inputMode[i] = QrMode.NUMERIC;
564
                }
565
            }
566
        }
567
 
568
        // TODO: uncomment
569
        // /* If less than 6 numeric digits together then don't use numeric mode */
570
        // for (int i = 0; i < inputMode.length; i++) {
571
        // if (inputMode[i] == QrMode.NUMERIC) {
572
        // if (((i != 0) && (inputMode[i - 1] != QrMode.NUMERIC)) || (i == 0)) {
573
        // mlen = 0;
574
        // while (((mlen + i) < inputMode.length) && (inputMode[mlen + i] == QrMode.NUMERIC)) {
575
        // mlen++;
576
        // };
577
        // if (mlen < 6) {
578
        // for (int j = 0; j < mlen; j++) {
579
        // inputMode[i + j] = QrMode.ALPHANUM;
580
        // }
581
        // }
582
        // }
583
        // }
584
        // }
585
        //
586
        // /* If less than 4 alphanumeric characters together then don't use alphanumeric mode */
587
        // for (int i = 0; i < inputMode.length; i++) {
588
        // if (inputMode[i] == QrMode.ALPHANUM) {
589
        // if (((i != 0) && (inputMode[i - 1] != QrMode.ALPHANUM)) || (i == 0)) {
590
        // mlen = 0;
591
        // while (((mlen + i) < inputMode.length) && (inputMode[mlen + i] == QrMode.ALPHANUM)) {
592
        // mlen++;
593
        // };
594
        // if (mlen < 4) {
595
        // for (int j = 0; j < mlen; j++) {
596
        // inputMode[i + j] = QrMode.BINARY;
597
        // }
598
        // }
599
        // }
600
        // }
601
        // }
602
    }
603
 
604
    /** Calculate the actual bit length of the proposed binary string. */
605
    private static int getBinaryLength(final int version, final QrMode[] inputModeUnoptimized, final int[] inputData, final boolean gs1, final int eciMode) {
606
 
607
        int i, j;
608
        QrMode currentMode;
609
        final int inputLength = inputModeUnoptimized.length;
610
        int count = 0;
611
        int alphaLength;
612
        int percent = 0;
613
 
614
        // ZINT NOTE: in Zint, this call modifies the input mode array directly; here, we leave
615
        // the original array alone so that subsequent binary length checks don't irrevocably
616
        // optimize the mode array for the wrong QR Code version
617
        final QrMode[] inputMode = applyOptimisation(version, inputModeUnoptimized);
618
 
619
        currentMode = QrMode.NULL;
620
 
621
        if (gs1) {
622
            count += 4;
623
        }
624
 
625
        if (eciMode != 3) {
626
            count += 12;
627
        }
628
 
629
        for (i = 0; i < inputLength; i++) {
630
            if (inputMode[i] != currentMode) {
631
                count += 4;
632
                switch (inputMode[i]) {
633
                case KANJI:
634
                    count += tribus(version, 8, 10, 12);
635
                    count += blockLength(i, inputMode) * 13;
636
                    break;
637
                case BINARY:
638
                    count += tribus(version, 8, 16, 16);
639
                    for (j = i; j < i + blockLength(i, inputMode); j++) {
640
                        if (inputData[j] > 0xff) {
641
                            count += 16;
642
                        } else {
643
                            count += 8;
644
                        }
645
                    }
646
                    break;
647
                case ALPHANUM:
648
                    count += tribus(version, 9, 11, 13);
649
                    alphaLength = blockLength(i, inputMode);
650
                    // In alphanumeric mode % becomes %%
651
                    if (gs1) {
652
                        for (j = i; j < i + alphaLength; j++) { // TODO: need to do this only if
653
                                                                // in GS1 mode? or is the other
654
                                                                // code wrong?
655
                                                                // https://sourceforge.net/p/zint/tickets/104/#227b
656
                            if (inputData[j] == '%') {
657
                                percent++;
658
                            }
659
                        }
660
                    }
661
                    alphaLength += percent;
662
                    switch (alphaLength % 2) {
663
                    case 0:
664
                        count += alphaLength / 2 * 11;
665
                        break;
666
                    case 1:
667
                        count += (alphaLength - 1) / 2 * 11;
668
                        count += 6;
669
                        break;
670
                    }
671
                    break;
672
                case NUMERIC:
673
                    count += tribus(version, 10, 12, 14);
674
                    switch (blockLength(i, inputMode) % 3) {
675
                    case 0:
676
                        count += blockLength(i, inputMode) / 3 * 10;
677
                        break;
678
                    case 1:
679
                        count += (blockLength(i, inputMode) - 1) / 3 * 10;
680
                        count += 4;
681
                        break;
682
                    case 2:
683
                        count += (blockLength(i, inputMode) - 2) / 3 * 10;
684
                        count += 7;
685
                        break;
686
                    }
687
                    break;
688
                }
689
                currentMode = inputMode[i];
690
            }
691
        }
692
 
693
        return count;
694
    }
695
 
696
    /**
697
     * Implements a custom optimization algorithm, because implementation of the algorithm shown in
698
     * Annex J.2 created LONGER binary sequences.
699
     */
700
    private static QrMode[] applyOptimisation(final int version, final QrMode[] inputMode) {
701
 
702
        final int inputLength = inputMode.length;
703
        int blockCount = 0;
704
        int i, j;
705
        QrMode currentMode = QrMode.NULL;
706
 
707
        for (i = 0; i < inputLength; i++) {
708
            if (inputMode[i] != currentMode) {
709
                currentMode = inputMode[i];
710
                blockCount++;
711
            }
712
        }
713
 
714
        final int[] blockLength = new int[blockCount];
715
        final QrMode[] blockMode = new QrMode[blockCount];
716
 
717
        j = -1;
718
        currentMode = QrMode.NULL;
719
        for (i = 0; i < inputLength; i++) {
720
            if (inputMode[i] != currentMode) {
721
                j++;
722
                blockLength[j] = 1;
723
                blockMode[j] = inputMode[i];
724
                currentMode = inputMode[i];
725
            } else {
726
                blockLength[j]++;
727
            }
728
        }
729
 
730
        if (blockCount > 1) {
731
            // Search forward
732
            for (i = 0; i <= blockCount - 2; i++) {
733
                if (blockMode[i] == QrMode.BINARY) {
734
                    switch (blockMode[i + 1]) {
735
                    case KANJI:
736
                        if (blockLength[i + 1] < tribus(version, 4, 5, 6)) {
737
                            blockMode[i + 1] = QrMode.BINARY;
738
                        }
739
                        break;
740
                    case ALPHANUM:
741
                        if (blockLength[i + 1] < tribus(version, 7, 8, 9)) {
742
                            blockMode[i + 1] = QrMode.BINARY;
743
                        }
744
                        break;
745
                    case NUMERIC:
746
                        if (blockLength[i + 1] < tribus(version, 3, 4, 5)) {
747
                            blockMode[i + 1] = QrMode.BINARY;
748
                        }
749
                        break;
750
                    }
751
                }
752
 
753
                if (blockMode[i] == QrMode.ALPHANUM && blockMode[i + 1] == QrMode.NUMERIC) {
754
                    if (blockLength[i + 1] < tribus(version, 6, 8, 10)) {
755
                        blockMode[i + 1] = QrMode.ALPHANUM;
756
                    }
757
                }
758
            }
759
 
760
            // Search backward
761
            for (i = blockCount - 1; i > 0; i--) {
762
                if (blockMode[i] == QrMode.BINARY) {
763
                    switch (blockMode[i - 1]) {
764
                    case KANJI:
765
                        if (blockLength[i - 1] < tribus(version, 4, 5, 6)) {
766
                            blockMode[i - 1] = QrMode.BINARY;
767
                        }
768
                        break;
769
                    case ALPHANUM:
770
                        if (blockLength[i - 1] < tribus(version, 7, 8, 9)) {
771
                            blockMode[i - 1] = QrMode.BINARY;
772
                        }
773
                        break;
774
                    case NUMERIC:
775
                        if (blockLength[i - 1] < tribus(version, 3, 4, 5)) {
776
                            blockMode[i - 1] = QrMode.BINARY;
777
                        }
778
                        break;
779
                    }
780
                }
781
 
782
                if (blockMode[i] == QrMode.ALPHANUM && blockMode[i - 1] == QrMode.NUMERIC) {
783
                    if (blockLength[i - 1] < tribus(version, 6, 8, 10)) {
784
                        blockMode[i - 1] = QrMode.ALPHANUM;
785
                    }
786
                }
787
            }
788
        }
789
 
790
        // ZINT NOTE: this method is different from the original Zint code in that it creates a
791
        // new array to hold the optimized values and returns it, rather than modifying the
792
        // original array; this allows this method to be called as many times as we want without
793
        // worrying about side effects
794
 
795
        final QrMode[] optimized = new QrMode[inputMode.length];
796
 
797
        j = 0;
798
        for (int block = 0; block < blockCount; block++) {
799
            currentMode = blockMode[block];
800
            for (i = 0; i < blockLength[block]; i++) {
801
                optimized[j] = currentMode;
802
                j++;
803
            }
804
        }
805
 
806
        return optimized;
807
    }
808
 
809
    /** Find the length of the block starting from 'start'. */
810
    private static int blockLength(final int start, final QrMode[] inputMode) {
811
 
812
        final QrMode mode = inputMode[start];
813
        int count = 0;
814
        final int i = start;
815
 
816
        do {
817
            count++;
818
        } while (i + count < inputMode.length && inputMode[i + count] == mode);
819
 
820
        return count;
821
    }
822
 
823
    /** Choose from three numbers based on version. */
824
    private static int tribus(final int version, final int a, final int b, final int c) {
825
        if (version < 10) {
826
            return a;
827
        } else if (version >= 10 && version <= 26) {
828
            return b;
829
        } else {
830
            return c;
831
        }
832
    }
833
 
834
    /** Returns true if input is in the Alphanumeric set (see Table J.1) */
835
    private static boolean isAlpha(final int c) {
836
        return c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == ' ' || c == '$' || c == '%' || c == '*' || c == '+' || c == '-' || c == '.' || c == '/' || c == ':';
837
    }
838
 
839
    /** Returns true if input is in the Numeric set (see Table J.1) */
840
    private static boolean isNumeric(final int c) {
841
        return c >= '0' && c <= '9';
842
    }
843
 
844
    /** Converts input data to a binary stream and adds padding. */
845
    private void qrBinary(final int[] datastream, final int version, final int target_binlen, final QrMode[] inputMode, final int[] inputData, final boolean gs1, final int eciMode,
846
            final int est_binlen) {
847
 
848
        // TODO: make encodeInfo a StringBuilder, make this method static?
849
 
850
        int position = 0;
851
        int short_data_block_length, i;
852
        int padbits;
853
        int current_binlen, current_bytes;
854
        int toggle;
855
        QrMode data_block;
856
 
857
        final StringBuilder binary = new StringBuilder(est_binlen + 12);
858
 
859
        if (gs1) {
860
            binary.append("0101"); /* FNC1 */
861
        }
862
 
863
        if (eciMode != 3) {
864
            binary.append("0111"); /* ECI (Table 4) */
865
            if (eciMode <= 127) {
866
                binaryAppend(eciMode, 8, binary); /* 000000 to 000127 */
867
            } else if (eciMode <= 16383) {
868
                binaryAppend(0x8000 + eciMode, 16, binary); /* 000000 to 016383 */
869
            } else {
870
                binaryAppend(0xC00000 + eciMode, 24, binary); /* 000000 to 999999 */
871
            }
872
        }
873
 
874
        info("Encoding: ");
875
 
876
        do {
877
            data_block = inputMode[position];
878
            short_data_block_length = 0;
879
            do {
880
                short_data_block_length++;
881
            } while (short_data_block_length + position < inputMode.length && inputMode[position + short_data_block_length] == data_block);
882
 
883
            switch (data_block) {
884
 
885
            case KANJI:
886
                /* Kanji mode */
887
                /* Mode indicator */
888
                binary.append("1000");
889
 
890
                /* Character count indicator */
891
                binaryAppend(short_data_block_length, tribus(version, 8, 10, 12), binary);
892
 
893
                info("KNJI ");
894
 
895
                /* Character representation */
896
                for (i = 0; i < short_data_block_length; i++) {
897
                    int jis = inputData[position + i];
898
                    if (jis >= 0x8140 && jis <= 0x9ffc) {
899
                        jis -= 0x8140;
900
                    } else if (jis >= 0xe040 && jis <= 0xebbf) {
901
                        jis -= 0xc140;
902
                    }
903
                    final int prod = (jis >> 8) * 0xc0 + (jis & 0xff);
904
                    binaryAppend(prod, 13, binary);
905
                    infoSpace(prod);
906
                }
907
 
908
                break;
909
 
910
            case BINARY:
911
                /* Byte mode */
912
                /* Mode indicator */
913
                binary.append("0100");
914
 
915
                /* Character count indicator */
916
                binaryAppend(short_data_block_length, tribus(version, 8, 16, 16), binary);
917
 
918
                info("BYTE ");
919
 
920
                /* Character representation */
921
                for (i = 0; i < short_data_block_length; i++) {
922
                    int b = inputData[position + i];
923
                    if (b == FNC1) {
924
                        b = 0x1d; /* FNC1 */
925
                    }
926
                    binaryAppend(b, 8, binary);
927
                    infoSpace(b);
928
                }
929
 
930
                break;
931
 
932
            case ALPHANUM:
933
                /* Alphanumeric mode */
934
                /* Mode indicator */
935
                binary.append("0010");
936
 
937
                /* If in GS1 mode, expand FNC1 -> '%' and expand '%' -> '%%' in a new array */
938
                int percentCount = 0;
939
                if (gs1) {
940
                    for (i = 0; i < short_data_block_length; i++) {
941
                        if (inputData[position + i] == '%') {
942
                            percentCount++;
943
                        }
944
                    }
945
                }
946
                final int[] inputExpanded = new int[short_data_block_length + percentCount];
947
                percentCount = 0;
948
                for (i = 0; i < short_data_block_length; i++) {
949
                    final int c = inputData[position + i];
950
                    if (c == FNC1) {
951
                        inputExpanded[i + percentCount] = '%'; /* FNC1 */
952
                    } else {
953
                        inputExpanded[i + percentCount] = c;
954
                        if (gs1 && c == '%') {
955
                            percentCount++;
956
                            inputExpanded[i + percentCount] = c;
957
                        }
958
                    }
959
                }
960
 
961
                /* Character count indicator */
962
                binaryAppend(inputExpanded.length, tribus(version, 9, 11, 13), binary);
963
 
964
                info("ALPH ");
965
 
966
                /* Character representation */
967
                for (i = 0; i + 1 < inputExpanded.length; i += 2) {
968
                    final int first = positionOf((char) inputExpanded[i], RHODIUM);
969
                    final int second = positionOf((char) inputExpanded[i + 1], RHODIUM);
970
                    final int prod = first * 45 + second;
971
                    final int count = 2;
972
                    binaryAppend(prod, 1 + 5 * count, binary);
973
                    infoSpace(prod);
974
                }
975
                if (inputExpanded.length % 2 != 0) {
976
                    final int first = positionOf((char) inputExpanded[inputExpanded.length - 1], RHODIUM);
977
                    final int prod = first;
978
                    final int count = 1;
979
                    binaryAppend(prod, 1 + 5 * count, binary);
980
                    infoSpace(prod);
981
                }
982
 
983
                break;
984
 
985
            case NUMERIC:
986
                /* Numeric mode */
987
                /* Mode indicator */
988
                binary.append("0001");
989
 
990
                /* Character count indicator */
991
                binaryAppend(short_data_block_length, tribus(version, 10, 12, 14), binary);
992
 
993
                info("NUMB ");
994
 
995
                /* Character representation */
996
                i = 0;
997
                while (i < short_data_block_length) {
998
 
999
                    final int first = Character.getNumericValue(inputData[position + i]);
1000
                    int count = 1;
1001
                    int prod = first;
1002
 
1003
                    if (i + 1 < short_data_block_length) {
1004
                        final int second = Character.getNumericValue(inputData[position + i + 1]);
1005
                        count = 2;
1006
                        prod = prod * 10 + second;
1007
 
1008
                        if (i + 2 < short_data_block_length) {
1009
                            final int third = Character.getNumericValue(inputData[position + i + 2]);
1010
                            count = 3;
1011
                            prod = prod * 10 + third;
1012
                        }
1013
                    }
1014
 
1015
                    binaryAppend(prod, 1 + 3 * count, binary);
1016
 
1017
                    infoSpace(prod);
1018
 
1019
                    i += count;
1020
                }
1021
 
1022
                break;
1023
            }
1024
 
1025
            position += short_data_block_length;
1026
 
1027
        } while (position < inputMode.length);
1028
 
1029
        infoLine();
1030
 
1031
        /* Terminator */
1032
        binary.append("0000");
1033
 
1034
        current_binlen = binary.length();
1035
        padbits = 8 - current_binlen % 8;
1036
        if (padbits == 8) {
1037
            padbits = 0;
1038
        }
1039
        current_bytes = (current_binlen + padbits) / 8;
1040
 
1041
        /* Padding bits */
1042
        for (i = 0; i < padbits; i++) {
1043
            binary.append('0');
1044
        }
1045
 
1046
        /* Put data into 8-bit codewords */
1047
        for (i = 0; i < current_bytes; i++) {
1048
            datastream[i] = 0x00;
1049
            for (int p = 0; p < 8; p++) {
1050
                if (binary.charAt(i * 8 + p) == '1') {
1051
                    datastream[i] += 0x80 >> p;
1052
                }
1053
            }
1054
        }
1055
 
1056
        /* Add pad codewords */
1057
        toggle = 0;
1058
        for (i = current_bytes; i < target_binlen; i++) {
1059
            if (toggle == 0) {
1060
                datastream[i] = 0xec;
1061
                toggle = 1;
1062
            } else {
1063
                datastream[i] = 0x11;
1064
                toggle = 0;
1065
            }
1066
        }
1067
 
1068
        info("Codewords: ");
1069
        for (i = 0; i < target_binlen; i++) {
1070
            infoSpace(datastream[i]);
1071
        }
1072
        infoLine();
1073
    }
1074
 
1075
    private static void binaryAppend(final int value, final int length, final StringBuilder binary) {
1076
        final int start = 0x01 << length - 1;
1077
        for (int i = 0; i < length; i++) {
1078
            if ((value & start >> i) != 0) {
1079
                binary.append('1');
1080
            } else {
1081
                binary.append('0');
1082
            }
1083
        }
1084
    }
1085
 
1086
    /**
1087
     * Splits data into blocks, adds error correction and then interleaves the blocks and error
1088
     * correction data.
1089
     */
1090
    private static void addEcc(final int[] fullstream, final int[] datastream, final int version, final int data_cw, final int blocks) {
1091
 
1092
        final int ecc_cw = QR_TOTAL_CODEWORDS[version - 1] - data_cw;
1093
        final int short_data_block_length = data_cw / blocks;
1094
        final int qty_long_blocks = data_cw % blocks;
1095
        final int qty_short_blocks = blocks - qty_long_blocks;
1096
        final int ecc_block_length = ecc_cw / blocks;
1097
        int i, j, length_this_block, posn;
1098
 
1099
        final int[] data_block = new int[short_data_block_length + 2];
1100
        final int[] ecc_block = new int[ecc_block_length + 2];
1101
        final int[] interleaved_data = new int[data_cw + 2];
1102
        final int[] interleaved_ecc = new int[ecc_cw + 2];
1103
 
1104
        posn = 0;
1105
 
1106
        for (i = 0; i < blocks; i++) {
1107
            if (i < qty_short_blocks) {
1108
                length_this_block = short_data_block_length;
1109
            } else {
1110
                length_this_block = short_data_block_length + 1;
1111
            }
1112
 
1113
            for (j = 0; j < ecc_block_length; j++) {
1114
                ecc_block[j] = 0;
1115
            }
1116
 
1117
            for (j = 0; j < length_this_block; j++) {
1118
                data_block[j] = datastream[posn + j];
1119
            }
1120
 
1121
            final ReedSolomon rs = new ReedSolomon();
1122
            rs.init_gf(0x11d);
1123
            rs.init_code(ecc_block_length, 0);
1124
            rs.encode(length_this_block, data_block);
1125
 
1126
            for (j = 0; j < ecc_block_length; j++) {
1127
                ecc_block[j] = rs.getResult(j);
1128
            }
1129
 
1130
            for (j = 0; j < short_data_block_length; j++) {
1131
                interleaved_data[j * blocks + i] = data_block[j];
1132
            }
1133
 
1134
            if (i >= qty_short_blocks) {
1135
                interleaved_data[short_data_block_length * blocks + i - qty_short_blocks] = data_block[short_data_block_length];
1136
            }
1137
 
1138
            for (j = 0; j < ecc_block_length; j++) {
1139
                interleaved_ecc[j * blocks + i] = ecc_block[ecc_block_length - j - 1];
1140
            }
1141
 
1142
            posn += length_this_block;
1143
        }
1144
 
1145
        for (j = 0; j < data_cw; j++) {
1146
            fullstream[j] = interleaved_data[j];
1147
        }
1148
        for (j = 0; j < ecc_cw; j++) {
1149
            fullstream[j + data_cw] = interleaved_ecc[j];
1150
        }
1151
    }
1152
 
1153
    private static void setupGrid(final int[] grid, final int size, final int version) {
1154
 
1155
        int i;
1156
        boolean toggle = true;
1157
 
1158
        /* Add timing patterns */
1159
        for (i = 0; i < size; i++) {
1160
            if (toggle) {
1161
                grid[6 * size + i] = 0x21;
1162
                grid[i * size + 6] = 0x21;
1163
                toggle = false;
1164
            } else {
1165
                grid[6 * size + i] = 0x20;
1166
                grid[i * size + 6] = 0x20;
1167
                toggle = true;
1168
            }
1169
        }
1170
 
1171
        /* Add finder patterns */
1172
        placeFinder(grid, size, 0, 0);
1173
        placeFinder(grid, size, 0, size - 7);
1174
        placeFinder(grid, size, size - 7, 0);
1175
 
1176
        /* Add separators */
1177
        for (i = 0; i < 7; i++) {
1178
            grid[7 * size + i] = 0x10;
1179
            grid[i * size + 7] = 0x10;
1180
            grid[7 * size + size - 1 - i] = 0x10;
1181
            grid[i * size + size - 8] = 0x10;
1182
            grid[(size - 8) * size + i] = 0x10;
1183
            grid[(size - 1 - i) * size + 7] = 0x10;
1184
        }
1185
        grid[7 * size + 7] = 0x10;
1186
        grid[7 * size + size - 8] = 0x10;
1187
        grid[(size - 8) * size + 7] = 0x10;
1188
 
1189
        /* Add alignment patterns */
1190
        if (version != 1) {
1191
            /* Version 1 does not have alignment patterns */
1192
            final int loopsize = QR_ALIGN_LOOPSIZE[version - 1];
1193
            for (int x = 0; x < loopsize; x++) {
1194
                for (int y = 0; y < loopsize; y++) {
1195
                    final int xcoord = QR_TABLE_E1[(version - 2) * 7 + x];
1196
                    final int ycoord = QR_TABLE_E1[(version - 2) * 7 + y];
1197
                    if ((grid[ycoord * size + xcoord] & 0x10) == 0) {
1198
                        placeAlign(grid, size, xcoord, ycoord);
1199
                    }
1200
                }
1201
            }
1202
        }
1203
 
1204
        /* Reserve space for format information */
1205
        for (i = 0; i < 8; i++) {
1206
            grid[8 * size + i] += 0x20;
1207
            grid[i * size + 8] += 0x20;
1208
            grid[8 * size + size - 1 - i] = 0x20;
1209
            grid[(size - 1 - i) * size + 8] = 0x20;
1210
        }
1211
        grid[8 * size + 8] += 0x20;
1212
        grid[(size - 1 - 7) * size + 8] = 0x21; /* Dark Module from Figure 25 */
1213
 
1214
        /* Reserve space for version information */
1215
        if (version >= 7) {
1216
            for (i = 0; i < 6; i++) {
1217
                grid[(size - 9) * size + i] = 0x20;
1218
                grid[(size - 10) * size + i] = 0x20;
1219
                grid[(size - 11) * size + i] = 0x20;
1220
                grid[i * size + size - 9] = 0x20;
1221
                grid[i * size + size - 10] = 0x20;
1222
                grid[i * size + size - 11] = 0x20;
1223
            }
1224
        }
1225
    }
1226
 
1227
    private static void placeFinder(final int[] grid, final int size, final int x, final int y) {
1228
 
1229
        final int[] finder = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 };
1230
 
1231
        for (int xp = 0; xp < 7; xp++) {
1232
            for (int yp = 0; yp < 7; yp++) {
1233
                if (finder[xp + 7 * yp] == 1) {
1234
                    grid[(yp + y) * size + xp + x] = 0x11;
1235
                } else {
1236
                    grid[(yp + y) * size + xp + x] = 0x10;
1237
                }
1238
            }
1239
        }
1240
    }
1241
 
1242
    private static void placeAlign(final int[] grid, final int size, int x, int y) {
1243
 
1244
        final int[] alignment = { 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1 };
1245
 
1246
        x -= 2;
1247
        y -= 2; /* Input values represent centre of pattern */
1248
 
1249
        for (int xp = 0; xp < 5; xp++) {
1250
            for (int yp = 0; yp < 5; yp++) {
1251
                if (alignment[xp + 5 * yp] == 1) {
1252
                    grid[(yp + y) * size + xp + x] = 0x11;
1253
                } else {
1254
                    grid[(yp + y) * size + xp + x] = 0x10;
1255
                }
1256
            }
1257
        }
1258
    }
1259
 
1260
    private static void populateGrid(final int[] grid, final int size, final int[] fullstream, final int cw) {
1261
 
1262
        boolean goingUp = true;
1263
        int row = 0; /* right hand side */
1264
 
1265
        int i, n, y;
1266
 
1267
        n = cw * 8;
1268
        y = size - 1;
1269
        i = 0;
1270
        do {
1271
            int x = size - 2 - row * 2;
1272
            if (x < 6) {
1273
                x--; /* skip over vertical timing pattern */
1274
            }
1275
 
1276
            if ((grid[y * size + x + 1] & 0xf0) == 0) {
1277
                if (cwbit(fullstream, i)) {
1278
                    grid[y * size + x + 1] = 0x01;
1279
                } else {
1280
                    grid[y * size + x + 1] = 0x00;
1281
                }
1282
                i++;
1283
            }
1284
 
1285
            if (i < n) {
1286
                if ((grid[y * size + x] & 0xf0) == 0) {
1287
                    if (cwbit(fullstream, i)) {
1288
                        grid[y * size + x] = 0x01;
1289
                    } else {
1290
                        grid[y * size + x] = 0x00;
1291
                    }
1292
                    i++;
1293
                }
1294
            }
1295
 
1296
            if (goingUp) {
1297
                y--;
1298
            } else {
1299
                y++;
1300
            }
1301
            if (y == -1) {
1302
                /* reached the top */
1303
                row++;
1304
                y = 0;
1305
                goingUp = false;
1306
            }
1307
            if (y == size) {
1308
                /* reached the bottom */
1309
                row++;
1310
                y = size - 1;
1311
                goingUp = true;
1312
            }
1313
        } while (i < n);
1314
    }
1315
 
1316
    private static boolean cwbit(final int[] fullstream, final int i) {
1317
        return (fullstream[i / 8] & 0x80 >> i % 8) != 0;
1318
    }
1319
 
1320
    private static int applyBitmask(final int[] grid, final int size, final EccLevel ecc_level) {
1321
 
1322
        int x, y;
1323
        char p;
1324
        int pattern;
1325
        int best_val, best_pattern;
1326
        final int[] penalty = new int[8];
1327
        final byte[] mask = new byte[size * size];
1328
        final byte[] eval = new byte[size * size];
1329
 
1330
        /* Perform data masking */
1331
        for (x = 0; x < size; x++) {
1332
            for (y = 0; y < size; y++) {
1333
                mask[y * size + x] = 0x00;
1334
                // all eight bit mask variants are encoded in the 8 bits of the bytes that make up
1335
                // the mask array
1336
                if ((grid[y * size + x] & 0xf0) == 0) { // exclude areas not to be masked
1337
                    if ((y + x & 1) == 0) {
1338
                        mask[y * size + x] += (byte) 0x01;
1339
                    }
1340
                    if ((y & 1) == 0) {
1341
                        mask[y * size + x] += (byte) 0x02;
1342
                    }
1343
                    if (x % 3 == 0) {
1344
                        mask[y * size + x] += (byte) 0x04;
1345
                    }
1346
                    if ((y + x) % 3 == 0) {
1347
                        mask[y * size + x] += (byte) 0x08;
1348
                    }
1349
                    if ((y / 2 + x / 3 & 1) == 0) {
1350
                        mask[y * size + x] += (byte) 0x10;
1351
                    }
1352
                    if ((y * x & 1) + y * x % 3 == 0) {
1353
                        mask[y * size + x] += (byte) 0x20;
1354
                    }
1355
                    if (((y * x & 1) + y * x % 3 & 1) == 0) {
1356
                        mask[y * size + x] += (byte) 0x40;
1357
                    }
1358
                    if (((y + x & 1) + y * x % 3 & 1) == 0) {
1359
                        mask[y * size + x] += (byte) 0x80;
1360
                    }
1361
                }
1362
            }
1363
        }
1364
 
1365
        /* Apply data masks to grid, result in eval */
1366
        for (x = 0; x < size; x++) {
1367
            for (y = 0; y < size; y++) {
1368
                if ((grid[y * size + x] & 0x01) != 0) {
1369
                    p = 0xff;
1370
                } else {
1371
                    p = 0x00;
1372
                }
1373
                eval[y * size + x] = (byte) (mask[y * size + x] ^ p);
1374
            }
1375
        }
1376
 
1377
        /* Evaluate result */
1378
        for (pattern = 0; pattern < 8; pattern++) {
1379
            addFormatInfoEval(eval, size, ecc_level, pattern);
1380
            penalty[pattern] = evaluate(eval, size, pattern);
1381
        }
1382
 
1383
        best_pattern = 0;
1384
        best_val = penalty[0];
1385
        for (pattern = 1; pattern < 8; pattern++) {
1386
            if (penalty[pattern] < best_val) {
1387
                best_pattern = pattern;
1388
                best_val = penalty[pattern];
1389
            }
1390
        }
1391
 
1392
        /* Apply mask */
1393
        for (x = 0; x < size; x++) {
1394
            for (y = 0; y < size; y++) {
1395
                if ((mask[y * size + x] & 0x01 << best_pattern) != 0) {
1396
                    if ((grid[y * size + x] & 0x01) != 0) {
1397
                        grid[y * size + x] = 0x00;
1398
                    } else {
1399
                        grid[y * size + x] = 0x01;
1400
                    }
1401
                }
1402
            }
1403
        }
1404
 
1405
        return best_pattern;
1406
    }
1407
 
1408
    /** Adds format information to eval. */
1409
    private static void addFormatInfoEval(final byte[] eval, final int size, final EccLevel ecc_level, final int pattern) {
1410
 
1411
        int format = pattern;
1412
        int seq;
1413
        int i;
1414
 
1415
        switch (ecc_level) {
1416
        case L:
1417
            format += 0x08;
1418
            break;
1419
        case Q:
1420
            format += 0x18;
1421
            break;
1422
        case H:
1423
            format += 0x10;
1424
            break;
1425
        }
1426
 
1427
        seq = QR_ANNEX_C[format];
1428
 
1429
        for (i = 0; i < 6; i++) {
1430
            eval[i * size + 8] = (byte) ((seq >> i & 0x01) != 0 ? 0x01 >> pattern : 0x00);
1431
        }
1432
 
1433
        for (i = 0; i < 8; i++) {
1434
            eval[8 * size + size - i - 1] = (byte) ((seq >> i & 0x01) != 0 ? 0x01 >> pattern : 0x00);
1435
        }
1436
 
1437
        for (i = 0; i < 6; i++) {
1438
            eval[8 * size + 5 - i] = (byte) ((seq >> i + 9 & 0x01) != 0 ? 0x01 >> pattern : 0x00);
1439
        }
1440
 
1441
        for (i = 0; i < 7; i++) {
1442
            eval[(size - 7 + i) * size + 8] = (byte) ((seq >> i + 8 & 0x01) != 0 ? 0x01 >> pattern : 0x00);
1443
        }
1444
 
1445
        eval[7 * size + 8] = (byte) ((seq >> 6 & 0x01) != 0 ? 0x01 >> pattern : 0x00);
1446
        eval[8 * size + 8] = (byte) ((seq >> 7 & 0x01) != 0 ? 0x01 >> pattern : 0x00);
1447
        eval[8 * size + 7] = (byte) ((seq >> 8 & 0x01) != 0 ? 0x01 >> pattern : 0x00);
1448
    }
1449
 
1450
    private static int evaluate(final byte[] eval, final int size, final int pattern) {
1451
 
1452
        int x, y, block, weight;
1453
        int result = 0;
1454
        int state;
1455
        int p;
1456
        int dark_mods;
1457
        int percentage, k;
1458
        int a, b, afterCount, beforeCount;
1459
        final byte[] local = new byte[size * size];
1460
 
1461
        // all eight bit mask variants have been encoded in the 8 bits of the bytes
1462
        // that make up the grid array; select them for evaluation according to the
1463
        // desired pattern
1464
        for (x = 0; x < size; x++) {
1465
            for (y = 0; y < size; y++) {
1466
                if ((eval[y * size + x] & 0x01 << pattern) != 0) {
1467
                    local[y * size + x] = '1';
1468
                } else {
1469
                    local[y * size + x] = '0';
1470
                }
1471
            }
1472
        }
1473
 
1474
        /* Test 1: Adjacent modules in row/column in same colour */
1475
        /* Vertical */
1476
        for (x = 0; x < size; x++) {
1477
            state = local[x];
1478
            block = 0;
1479
            for (y = 0; y < size; y++) {
1480
                if (local[y * size + x] == state) {
1481
                    block++;
1482
                } else {
1483
                    if (block > 5) {
1484
                        result += 3 + block - 5;
1485
                    }
1486
                    block = 0;
1487
                    state = local[y * size + x];
1488
                }
1489
            }
1490
            if (block > 5) {
1491
                result += 3 + block - 5;
1492
            }
1493
        }
1494
 
1495
        /* Horizontal */
1496
        for (y = 0; y < size; y++) {
1497
            state = local[y * size];
1498
            block = 0;
1499
            for (x = 0; x < size; x++) {
1500
                if (local[y * size + x] == state) {
1501
                    block++;
1502
                } else {
1503
                    if (block > 5) {
1504
                        result += 3 + block - 5;
1505
                    }
1506
                    block = 0;
1507
                    state = local[y * size + x];
1508
                }
1509
            }
1510
            if (block > 5) {
1511
                result += 3 + block - 5;
1512
            }
1513
        }
1514
 
1515
        /* Test 2: Block of modules in same color */
1516
        for (x = 0; x < size - 1; x++) {
1517
            for (y = 0; y < size - 1; y++) {
1518
                if (local[y * size + x] == local[(y + 1) * size + x] && local[y * size + x] == local[y * size + x + 1] && local[y * size + x] == local[(y + 1) * size + x + 1]) {
1519
                    result += 3;
1520
                }
1521
            }
1522
        }
1523
 
1524
        /* Test 3: 1:1:3:1:1 ratio pattern in row/column */
1525
        /* Vertical */
1526
        for (x = 0; x < size; x++) {
1527
            for (y = 0; y < size - 7; y++) {
1528
                p = 0;
1529
                for (weight = 0; weight < 7; weight++) {
1530
                    if (local[(y + weight) * size + x] == '1') {
1531
                        p += 0x40 >> weight;
1532
                    }
1533
                }
1534
                if (p == 0x5d) {
1535
                    /* Pattern found, check before and after */
1536
                    beforeCount = 0;
1537
                    for (b = y - 4; b < y; b++) {
1538
                        if (b < 0) {
1539
                            beforeCount++;
1540
                        } else {
1541
                            if (local[b * size + x] == '0') {
1542
                                beforeCount++;
1543
                            } else {
1544
                                beforeCount = 0;
1545
                            }
1546
                        }
1547
                    }
1548
 
1549
                    afterCount = 0;
1550
                    for (a = y + 7; a <= y + 10; a++) {
1551
                        if (a >= size) {
1552
                            afterCount++;
1553
                        } else {
1554
                            if (local[a * size + x] == '0') {
1555
                                afterCount++;
1556
                            } else {
1557
                                afterCount = 0;
1558
                            }
1559
                        }
1560
                    }
1561
 
1562
                    if (beforeCount == 4 || afterCount == 4) {
1563
                        // Pattern is preceded or followed by light area 4 modules wide
1564
                        result += 40;
1565
                    }
1566
                }
1567
            }
1568
        }
1569
 
1570
        /* Horizontal */
1571
        for (y = 0; y < size; y++) {
1572
            for (x = 0; x < size - 7; x++) {
1573
                p = 0;
1574
                for (weight = 0; weight < 7; weight++) {
1575
                    if (local[y * size + x + weight] == '1') {
1576
                        p += 0x40 >> weight;
1577
                    }
1578
                }
1579
                if (p == 0x5d) {
1580
                    /* Pattern found, check before and after */
1581
                    beforeCount = 0;
1582
                    for (b = x - 4; b < x; b++) {
1583
                        if (b < 0) {
1584
                            beforeCount++;
1585
                        } else {
1586
                            if (local[y * size + b] == '0') {
1587
                                beforeCount++;
1588
                            } else {
1589
                                beforeCount = 0;
1590
                            }
1591
                        }
1592
                    }
1593
 
1594
                    afterCount = 0;
1595
                    for (a = x + 7; a <= x + 10; a++) {
1596
                        if (a >= size) {
1597
                            afterCount++;
1598
                        } else {
1599
                            if (local[y * size + a] == '0') {
1600
                                afterCount++;
1601
                            } else {
1602
                                afterCount = 0;
1603
                            }
1604
                        }
1605
                    }
1606
 
1607
                    if (beforeCount == 4 || afterCount == 4) {
1608
                        // Pattern is preceded or followed by light area 4 modules wide
1609
                        result += 40;
1610
                    }
1611
                }
1612
            }
1613
        }
1614
 
1615
        /* Test 4: Proportion of dark modules in entire symbol */
1616
        dark_mods = 0;
1617
        for (x = 0; x < size; x++) {
1618
            for (y = 0; y < size; y++) {
1619
                if (local[y * size + x] == '1') {
1620
                    dark_mods++;
1621
                }
1622
            }
1623
        }
1624
        percentage = 100 * (dark_mods / (size * size));
1625
        if (percentage <= 50) {
1626
            k = (100 - percentage - 50) / 5;
1627
        } else {
1628
            k = (percentage - 50) / 5;
1629
        }
1630
 
1631
        result += 10 * k;
1632
 
1633
        return result;
1634
    }
1635
 
1636
    /* Adds format information to grid. */
1637
    private static void addFormatInfo(final int[] grid, final int size, final EccLevel ecc_level, final int pattern) {
1638
 
1639
        int format = pattern;
1640
        int seq;
1641
        int i;
1642
 
1643
        switch (ecc_level) {
1644
        case L:
1645
            format += 0x08;
1646
            break;
1647
        case Q:
1648
            format += 0x18;
1649
            break;
1650
        case H:
1651
            format += 0x10;
1652
            break;
1653
        }
1654
 
1655
        seq = QR_ANNEX_C[format];
1656
 
1657
        for (i = 0; i < 6; i++) {
1658
            grid[i * size + 8] += seq >> i & 0x01;
1659
        }
1660
 
1661
        for (i = 0; i < 8; i++) {
1662
            grid[8 * size + size - i - 1] += seq >> i & 0x01;
1663
        }
1664
 
1665
        for (i = 0; i < 6; i++) {
1666
            grid[8 * size + 5 - i] += seq >> i + 9 & 0x01;
1667
        }
1668
 
1669
        for (i = 0; i < 7; i++) {
1670
            grid[(size - 7 + i) * size + 8] += seq >> i + 8 & 0x01;
1671
        }
1672
 
1673
        grid[7 * size + 8] += seq >> 6 & 0x01;
1674
        grid[8 * size + 8] += seq >> 7 & 0x01;
1675
        grid[8 * size + 7] += seq >> 8 & 0x01;
1676
    }
1677
 
1678
    /** Adds version information. */
1679
    private static void addVersionInfo(final int[] grid, final int size, final int version) {
1680
        // TODO: Zint masks with 0x41 instead of 0x01; which is correct?
1681
        // https://sourceforge.net/p/zint/tickets/110/
1682
        final int version_data = QR_ANNEX_D[version - 7];
1683
        for (int i = 0; i < 6; i++) {
1684
            grid[(size - 11) * size + i] += version_data >> i * 3 & 0x01;
1685
            grid[(size - 10) * size + i] += version_data >> i * 3 + 1 & 0x01;
1686
            grid[(size - 9) * size + i] += version_data >> i * 3 + 2 & 0x01;
1687
            grid[i * size + size - 11] += version_data >> i * 3 & 0x01;
1688
            grid[i * size + size - 10] += version_data >> i * 3 + 1 & 0x01;
1689
            grid[i * size + size - 9] += version_data >> i * 3 + 2 & 0x01;
1690
        }
1691
    }
1692
}