Codebase list hibiscus / 07dc8de
Temporarily add fastqrcodegen library Jochen Sprickerhof 2 years ago
3 changed file(s) with 1680 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
3737 On Debian systems, the complete text of the GNU General
3838 Public License version 3 can be found in "/usr/share/common-licenses/GPL-2".
3939
40 Files: src/io/nayuki/fastqrcodegen/
41 Copyright: 2017-2022 Project Nayuki <me@nayuki.io>
42 License: Expat
43 Permission is hereby granted, free of charge, to any person obtaining a
44 copy of this software and associated documentation files (the "Software"),
45 to deal in the Software without restriction, including without limitation
46 the rights to use, copy, modify, merge, publish, distribute, sublicense,
47 and/or sell copies of the Software, and to permit persons to whom the
48 Software is furnished to do so, subject to the following conditions:
49 .
50 The above copyright notice and this permission notice shall be included
51 in all copies or substantial portions of the Software.
52 .
53 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
54 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
55 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
56 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
57 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
58 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
59 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
60
4061 Files: debian/*
4162 Copyright: 2018 Jochen Sprickerhof <jspricke@debian.org>
4263 License: ISC
0 From: Jochen Sprickerhof <git@jochen.sprickerhof.de>
1 Date: Thu, 5 May 2022 17:54:29 +0200
2 Subject: Add fastqrcodegen lib till #1010618 is resolved
3
4 ---
5 src/io/nayuki/fastqrcodegen/BitBuffer.java | 134 +++++
6 .../nayuki/fastqrcodegen/DataTooLongException.java | 57 ++
7 src/io/nayuki/fastqrcodegen/Memoizer.java | 95 ++++
8 src/io/nayuki/fastqrcodegen/QrCode.java | 595 +++++++++++++++++++++
9 src/io/nayuki/fastqrcodegen/QrSegment.java | 338 ++++++++++++
10 src/io/nayuki/fastqrcodegen/QrTemplate.java | 270 ++++++++++
11 .../nayuki/fastqrcodegen/ReedSolomonGenerator.java | 106 ++++
12 7 files changed, 1595 insertions(+)
13 create mode 100644 src/io/nayuki/fastqrcodegen/BitBuffer.java
14 create mode 100644 src/io/nayuki/fastqrcodegen/DataTooLongException.java
15 create mode 100644 src/io/nayuki/fastqrcodegen/Memoizer.java
16 create mode 100644 src/io/nayuki/fastqrcodegen/QrCode.java
17 create mode 100644 src/io/nayuki/fastqrcodegen/QrSegment.java
18 create mode 100644 src/io/nayuki/fastqrcodegen/QrTemplate.java
19 create mode 100644 src/io/nayuki/fastqrcodegen/ReedSolomonGenerator.java
20
21 diff --git a/src/io/nayuki/fastqrcodegen/BitBuffer.java b/src/io/nayuki/fastqrcodegen/BitBuffer.java
22 new file mode 100644
23 index 0000000..fafafd5
24 --- /dev/null
25 +++ b/src/io/nayuki/fastqrcodegen/BitBuffer.java
26 @@ -0,0 +1,134 @@
27 +/*
28 + * Fast QR Code generator library
29 + *
30 + * Copyright (c) Project Nayuki. (MIT License)
31 + * https://www.nayuki.io/page/fast-qr-code-generator-library
32 + *
33 + * Permission is hereby granted, free of charge, to any person obtaining a copy of
34 + * this software and associated documentation files (the "Software"), to deal in
35 + * the Software without restriction, including without limitation the rights to
36 + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
37 + * the Software, and to permit persons to whom the Software is furnished to do so,
38 + * subject to the following conditions:
39 + * - The above copyright notice and this permission notice shall be included in
40 + * all copies or substantial portions of the Software.
41 + * - The Software is provided "as is", without warranty of any kind, express or
42 + * implied, including but not limited to the warranties of merchantability,
43 + * fitness for a particular purpose and noninfringement. In no event shall the
44 + * authors or copyright holders be liable for any claim, damages or other
45 + * liability, whether in an action of contract, tort or otherwise, arising from,
46 + * out of or in connection with the Software or the use or other dealings in the
47 + * Software.
48 + */
49 +
50 +package io.nayuki.fastqrcodegen;
51 +
52 +import java.util.Arrays;
53 +import java.util.Objects;
54 +
55 +
56 +// An appendable sequence of bits (0s and 1s), mainly used by QrSegment.
57 +final class BitBuffer {
58 +
59 + /*---- Fields ----*/
60 +
61 + int[] data; // In each 32-bit word, bits are filled from top down.
62 +
63 + int bitLength; // Always non-negative.
64 +
65 +
66 +
67 + /*---- Constructor ----*/
68 +
69 + // Creates an empty bit buffer.
70 + public BitBuffer() {
71 + data = new int[64];
72 + bitLength = 0;
73 + }
74 +
75 +
76 +
77 + /*---- Methods ----*/
78 +
79 + // Returns the bit at the given index, yielding 0 or 1.
80 + public int getBit(int index) {
81 + if (index < 0 || index >= bitLength)
82 + throw new IndexOutOfBoundsException();
83 + return (data[index >>> 5] >>> ~index) & 1;
84 + }
85 +
86 +
87 + // Returns a new array representing this buffer's bits packed into
88 + // bytes in big endian. The current bit length must be a multiple of 8.
89 + public byte[] getBytes() {
90 + if (bitLength % 8 != 0)
91 + throw new IllegalStateException("Data is not a whole number of bytes");
92 + byte[] result = new byte[bitLength / 8];
93 + for (int i = 0; i < result.length; i++)
94 + result[i] = (byte)(data[i >>> 2] >>> (~i << 3));
95 + return result;
96 + }
97 +
98 +
99 + // Appends the given number of low-order bits of the given value
100 + // to this buffer. Requires 0 <= len <= 31 and 0 <= val < 2^len.
101 + public void appendBits(int val, int len) {
102 + if (len < 0 || len > 31 || val >>> len != 0)
103 + throw new IllegalArgumentException("Value out of range");
104 + if (len > Integer.MAX_VALUE - bitLength)
105 + throw new IllegalStateException("Maximum length reached");
106 +
107 + if (bitLength + len + 1 > data.length << 5)
108 + data = Arrays.copyOf(data, data.length * 2);
109 + assert bitLength + len <= data.length << 5;
110 +
111 + int remain = 32 - (bitLength & 0x1F);
112 + assert 1 <= remain && remain <= 32;
113 + if (remain < len) {
114 + data[bitLength >>> 5] |= val >>> (len - remain);
115 + bitLength += remain;
116 + assert (bitLength & 0x1F) == 0;
117 + len -= remain;
118 + val &= (1 << len) - 1;
119 + remain = 32;
120 + }
121 + data[bitLength >>> 5] |= val << (remain - len);
122 + bitLength += len;
123 + }
124 +
125 +
126 + // Appends to this buffer the sequence of bits represented by the given
127 + // word array and given bit length. Requires 0 <= len <= 32 * vals.length.
128 + public void appendBits(int[] vals, int len) {
129 + Objects.requireNonNull(vals);
130 + if (len == 0)
131 + return;
132 + if (len < 0 || len > vals.length * 32L)
133 + throw new IllegalArgumentException("Value out of range");
134 + int wholeWords = len / 32;
135 + int tailBits = len % 32;
136 + if (tailBits > 0 && vals[wholeWords] << tailBits != 0)
137 + throw new IllegalArgumentException("Last word must have low bits clear");
138 + if (len > Integer.MAX_VALUE - bitLength)
139 + throw new IllegalStateException("Maximum length reached");
140 +
141 + while (bitLength + len > data.length * 32)
142 + data = Arrays.copyOf(data, data.length * 2);
143 +
144 + int shift = bitLength % 32;
145 + if (shift == 0) {
146 + System.arraycopy(vals, 0, data, bitLength / 32, (len + 31) / 32);
147 + bitLength += len;
148 + } else {
149 + for (int i = 0; i < wholeWords; i++) {
150 + int word = vals[i];
151 + data[bitLength >>> 5] |= word >>> shift;
152 + bitLength += 32;
153 + data[bitLength >>> 5] = word << (32 - shift);
154 + }
155 + if (tailBits > 0)
156 + appendBits(vals[wholeWords] >>> (32 - tailBits), tailBits);
157 + }
158 + }
159 +
160 +}
161 diff --git a/src/io/nayuki/fastqrcodegen/DataTooLongException.java b/src/io/nayuki/fastqrcodegen/DataTooLongException.java
162 new file mode 100644
163 index 0000000..c6e4444
164 --- /dev/null
165 +++ b/src/io/nayuki/fastqrcodegen/DataTooLongException.java
166 @@ -0,0 +1,57 @@
167 +/*
168 + * Fast QR Code generator library
169 + *
170 + * Copyright (c) Project Nayuki. (MIT License)
171 + * https://www.nayuki.io/page/fast-qr-code-generator-library
172 + *
173 + * Permission is hereby granted, free of charge, to any person obtaining a copy of
174 + * this software and associated documentation files (the "Software"), to deal in
175 + * the Software without restriction, including without limitation the rights to
176 + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
177 + * the Software, and to permit persons to whom the Software is furnished to do so,
178 + * subject to the following conditions:
179 + * - The above copyright notice and this permission notice shall be included in
180 + * all copies or substantial portions of the Software.
181 + * - The Software is provided "as is", without warranty of any kind, express or
182 + * implied, including but not limited to the warranties of merchantability,
183 + * fitness for a particular purpose and noninfringement. In no event shall the
184 + * authors or copyright holders be liable for any claim, damages or other
185 + * liability, whether in an action of contract, tort or otherwise, arising from,
186 + * out of or in connection with the Software or the use or other dealings in the
187 + * Software.
188 + */
189 +
190 +package io.nayuki.fastqrcodegen;
191 +
192 +
193 +/**
194 + * Thrown when the supplied data does not fit any QR Code version. Ways to handle this exception include:
195 + * <ul>
196 + * <li><p>Decrease the error correction level if it was greater than {@code Ecc.LOW}.</p></li>
197 + * <li><p>If the advanced {@code encodeSegments()} function with 6 arguments or the
198 + * {@code makeSegmentsOptimally()} function was called, then increase the maxVersion argument
199 + * if it was less than {@link QrCode#MAX_VERSION}. (This advice does not apply to the other
200 + * factory functions because they search all versions up to {@code QrCode.MAX_VERSION}.)</p></li>
201 + * <li><p>Split the text data into better or optimal segments in order to reduce the number of
202 + * bits required. (See {@link QrSegmentAdvanced#makeSegmentsOptimally(String,QrCode.Ecc,int,int)
203 + * QrSegmentAdvanced.makeSegmentsOptimally()}.)</p></li>
204 + * <li><p>Change the text or binary data to be shorter.</p></li>
205 + * <li><p>Change the text to fit the character set of a particular segment mode (e.g. alphanumeric).</p></li>
206 + * <li><p>Propagate the error upward to the caller/user.</p></li>
207 + * </ul>
208 + * @see QrCode#encodeText(String, QrCode.Ecc)
209 + * @see QrCode#encodeBinary(byte[], QrCode.Ecc)
210 + * @see QrCode#encodeSegments(java.util.List, QrCode.Ecc)
211 + * @see QrCode#encodeSegments(java.util.List, QrCode.Ecc, int, int, int, boolean)
212 + * @see QrSegmentAdvanced#makeSegmentsOptimally(String, QrCode.Ecc, int, int)
213 + */
214 +public class DataTooLongException extends IllegalArgumentException {
215 +
216 + public DataTooLongException() {}
217 +
218 +
219 + public DataTooLongException(String msg) {
220 + super(msg);
221 + }
222 +
223 +}
224 diff --git a/src/io/nayuki/fastqrcodegen/Memoizer.java b/src/io/nayuki/fastqrcodegen/Memoizer.java
225 new file mode 100644
226 index 0000000..34a50b7
227 --- /dev/null
228 +++ b/src/io/nayuki/fastqrcodegen/Memoizer.java
229 @@ -0,0 +1,95 @@
230 +/*
231 + * Fast QR Code generator library
232 + *
233 + * Copyright (c) Project Nayuki. (MIT License)
234 + * https://www.nayuki.io/page/fast-qr-code-generator-library
235 + *
236 + * Permission is hereby granted, free of charge, to any person obtaining a copy of
237 + * this software and associated documentation files (the "Software"), to deal in
238 + * the Software without restriction, including without limitation the rights to
239 + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
240 + * the Software, and to permit persons to whom the Software is furnished to do so,
241 + * subject to the following conditions:
242 + * - The above copyright notice and this permission notice shall be included in
243 + * all copies or substantial portions of the Software.
244 + * - The Software is provided "as is", without warranty of any kind, express or
245 + * implied, including but not limited to the warranties of merchantability,
246 + * fitness for a particular purpose and noninfringement. In no event shall the
247 + * authors or copyright holders be liable for any claim, damages or other
248 + * liability, whether in an action of contract, tort or otherwise, arising from,
249 + * out of or in connection with the Software or the use or other dealings in the
250 + * Software.
251 + */
252 +
253 +package io.nayuki.fastqrcodegen;
254 +
255 +import java.lang.ref.SoftReference;
256 +import java.util.HashSet;
257 +import java.util.Map;
258 +import java.util.Set;
259 +import java.util.concurrent.ConcurrentHashMap;
260 +import java.util.function.Function;
261 +
262 +
263 +// A thread-safe cache based on soft references.
264 +final class Memoizer<T,R> {
265 +
266 + private final Function<T,R> function;
267 + Map<T,SoftReference<R>> cache = new ConcurrentHashMap<>();
268 + private Set<T> pending = new HashSet<>();
269 +
270 +
271 + // Creates a memoizer based on the given function that takes one input to compute an output.
272 + public Memoizer(Function<T,R> func) {
273 + function = func;
274 + }
275 +
276 +
277 + // Computes function.apply(arg) or returns a cached copy of a previous call.
278 + public R get(T arg) {
279 + // Non-blocking fast path
280 + {
281 + SoftReference<R> ref = cache.get(arg);
282 + if (ref != null) {
283 + R result = ref.get();
284 + if (result != null)
285 + return result;
286 + }
287 + }
288 +
289 + // Sequential slow path
290 + while (true) {
291 + synchronized(this) {
292 + SoftReference<R> ref = cache.get(arg);
293 + if (ref != null) {
294 + R result = ref.get();
295 + if (result != null)
296 + return result;
297 + cache.remove(arg);
298 + }
299 + assert !cache.containsKey(arg);
300 +
301 + if (pending.add(arg))
302 + break;
303 +
304 + try {
305 + this.wait();
306 + } catch (InterruptedException e) {
307 + throw new RuntimeException(e);
308 + }
309 + }
310 + }
311 +
312 + try {
313 + R result = function.apply(arg);
314 + cache.put(arg, new SoftReference<>(result));
315 + return result;
316 + } finally {
317 + synchronized(this) {
318 + pending.remove(arg);
319 + this.notifyAll();
320 + }
321 + }
322 + }
323 +
324 +}
325 diff --git a/src/io/nayuki/fastqrcodegen/QrCode.java b/src/io/nayuki/fastqrcodegen/QrCode.java
326 new file mode 100644
327 index 0000000..75e5e0f
328 --- /dev/null
329 +++ b/src/io/nayuki/fastqrcodegen/QrCode.java
330 @@ -0,0 +1,595 @@
331 +/*
332 + * Fast QR Code generator library
333 + *
334 + * Copyright (c) Project Nayuki. (MIT License)
335 + * https://www.nayuki.io/page/fast-qr-code-generator-library
336 + *
337 + * Permission is hereby granted, free of charge, to any person obtaining a copy of
338 + * this software and associated documentation files (the "Software"), to deal in
339 + * the Software without restriction, including without limitation the rights to
340 + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
341 + * the Software, and to permit persons to whom the Software is furnished to do so,
342 + * subject to the following conditions:
343 + * - The above copyright notice and this permission notice shall be included in
344 + * all copies or substantial portions of the Software.
345 + * - The Software is provided "as is", without warranty of any kind, express or
346 + * implied, including but not limited to the warranties of merchantability,
347 + * fitness for a particular purpose and noninfringement. In no event shall the
348 + * authors or copyright holders be liable for any claim, damages or other
349 + * liability, whether in an action of contract, tort or otherwise, arising from,
350 + * out of or in connection with the Software or the use or other dealings in the
351 + * Software.
352 + */
353 +
354 +package io.nayuki.fastqrcodegen;
355 +
356 +import java.util.Arrays;
357 +import java.util.List;
358 +import java.util.Objects;
359 +
360 +
361 +/**
362 + * A QR Code symbol, which is a type of two-dimension barcode.
363 + * Invented by Denso Wave and described in the ISO/IEC 18004 standard.
364 + * <p>Instances of this class represent an immutable square grid of dark and light cells.
365 + * The class provides static factory functions to create a QR Code from text or binary data.
366 + * The class covers the QR Code Model 2 specification, supporting all versions (sizes)
367 + * from 1 to 40, all 4 error correction levels, and 4 character encoding modes.</p>
368 + * <p>Ways to create a QR Code object:</p>
369 + * <ul>
370 + * <li><p>High level: Take the payload data and call {@link QrCode#encodeText(String,Ecc)}
371 + * or {@link QrCode#encodeBinary(byte[],Ecc)}.</p></li>
372 + * <li><p>Mid level: Custom-make the list of {@link QrSegment segments}
373 + * and call {@link QrCode#encodeSegments(List,Ecc)} or
374 + * {@link QrCode#encodeSegments(List,Ecc,int,int,int,boolean)}</p></li>
375 + * <li><p>Low level: Custom-make the array of data codeword bytes (including segment headers and
376 + * final padding, excluding error correction codewords), supply the appropriate version number,
377 + * and call the {@link QrCode#QrCode(int,Ecc,byte[],int) constructor}.</p></li>
378 + * </ul>
379 + * <p>(Note that all ways require supplying the desired error correction level.)</p>
380 + * @see QrSegment
381 + */
382 +public final class QrCode {
383 +
384 + /*---- Static factory functions (high level) ----*/
385 +
386 + /**
387 + * Returns a QR Code representing the specified Unicode text string at the specified error correction level.
388 + * As a conservative upper bound, this function is guaranteed to succeed for strings that have 738 or fewer
389 + * Unicode code points (not UTF-16 code units) if the low error correction level is used. The smallest possible
390 + * QR Code version is automatically chosen for the output. The ECC level of the result may be higher than the
391 + * ecl argument if it can be done without increasing the version.
392 + * @param text the text to be encoded (not {@code null}), which can be any Unicode string
393 + * @param ecl the error correction level to use (not {@code null}) (boostable)
394 + * @return a QR Code (not {@code null}) representing the text
395 + * @throws NullPointerException if the text or error correction level is {@code null}
396 + * @throws DataTooLongException if the text fails to fit in the
397 + * largest version QR Code at the ECL, which means it is too long
398 + */
399 + public static QrCode encodeText(String text, Ecc ecl) {
400 + Objects.requireNonNull(text);
401 + Objects.requireNonNull(ecl);
402 + List<QrSegment> segs = QrSegment.makeSegments(text);
403 + return encodeSegments(segs, ecl);
404 + }
405 +
406 +
407 + /**
408 + * Returns a QR Code representing the specified binary data at the specified error correction level.
409 + * This function always encodes using the binary segment mode, not any text mode. The maximum number of
410 + * bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
411 + * The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
412 + * @param data the binary data to encode (not {@code null})
413 + * @param ecl the error correction level to use (not {@code null}) (boostable)
414 + * @return a QR Code (not {@code null}) representing the data
415 + * @throws NullPointerException if the data or error correction level is {@code null}
416 + * @throws DataTooLongException if the data fails to fit in the
417 + * largest version QR Code at the ECL, which means it is too long
418 + */
419 + public static QrCode encodeBinary(byte[] data, Ecc ecl) {
420 + Objects.requireNonNull(data);
421 + Objects.requireNonNull(ecl);
422 + QrSegment seg = QrSegment.makeBytes(data);
423 + return encodeSegments(Arrays.asList(seg), ecl);
424 + }
425 +
426 +
427 + /*---- Static factory functions (mid level) ----*/
428 +
429 + /**
430 + * Returns a QR Code representing the specified segments at the specified error correction
431 + * level. The smallest possible QR Code version is automatically chosen for the output. The ECC level
432 + * of the result may be higher than the ecl argument if it can be done without increasing the version.
433 + * <p>This function allows the user to create a custom sequence of segments that switches
434 + * between modes (such as alphanumeric and byte) to encode text in less space.
435 + * This is a mid-level API; the high-level API is {@link #encodeText(String,Ecc)}
436 + * and {@link #encodeBinary(byte[],Ecc)}.</p>
437 + * @param segs the segments to encode
438 + * @param ecl the error correction level to use (not {@code null}) (boostable)
439 + * @return a QR Code (not {@code null}) representing the segments
440 + * @throws NullPointerException if the list of segments, any segment, or the error correction level is {@code null}
441 + * @throws DataTooLongException if the segments fail to fit in the
442 + * largest version QR Code at the ECL, which means they are too long
443 + */
444 + public static QrCode encodeSegments(List<QrSegment> segs, Ecc ecl) {
445 + return encodeSegments(segs, ecl, MIN_VERSION, MAX_VERSION, -1, true);
446 + }
447 +
448 +
449 + /**
450 + * Returns a QR Code representing the specified segments with the specified encoding parameters.
451 + * The smallest possible QR Code version within the specified range is automatically
452 + * chosen for the output. Iff boostEcl is {@code true}, then the ECC level of the
453 + * result may be higher than the ecl argument if it can be done without increasing
454 + * the version. The mask number is either between 0 to 7 (inclusive) to force that
455 + * mask, or &#x2212;1 to automatically choose an appropriate mask (which may be slow).
456 + * <p>This function allows the user to create a custom sequence of segments that switches
457 + * between modes (such as alphanumeric and byte) to encode text in less space.
458 + * This is a mid-level API; the high-level API is {@link #encodeText(String,Ecc)}
459 + * and {@link #encodeBinary(byte[],Ecc)}.</p>
460 + * @param segs the segments to encode
461 + * @param ecl the error correction level to use (not {@code null}) (boostable)
462 + * @param minVersion the minimum allowed version of the QR Code (at least 1)
463 + * @param maxVersion the maximum allowed version of the QR Code (at most 40)
464 + * @param mask the mask number to use (between 0 and 7 (inclusive)), or &#x2212;1 for automatic mask
465 + * @param boostEcl increases the ECC level as long as it doesn't increase the version number
466 + * @return a QR Code (not {@code null}) representing the segments
467 + * @throws NullPointerException if the list of segments, any segment, or the error correction level is {@code null}
468 + * @throws IllegalArgumentException if 1 &#x2264; minVersion &#x2264; maxVersion &#x2264; 40
469 + * or &#x2212;1 &#x2264; mask &#x2264; 7 is violated
470 + * @throws DataTooLongException if the segments fail to fit in
471 + * the maxVersion QR Code at the ECL, which means they are too long
472 + */
473 + public static QrCode encodeSegments(List<QrSegment> segs, Ecc ecl, int minVersion, int maxVersion, int mask, boolean boostEcl) {
474 + Objects.requireNonNull(segs);
475 + Objects.requireNonNull(ecl);
476 + if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
477 + throw new IllegalArgumentException("Invalid value");
478 +
479 + // Find the minimal version number to use
480 + int version, dataUsedBits;
481 + for (version = minVersion; ; version++) {
482 + int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
483 + dataUsedBits = QrSegment.getTotalBits(segs, version);
484 + if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
485 + break; // This version number is found to be suitable
486 + if (version >= maxVersion) { // All versions in the range could not fit the given data
487 + String msg = "Segment too long";
488 + if (dataUsedBits != -1)
489 + msg = String.format("Data length = %d bits, Max capacity = %d bits", dataUsedBits, dataCapacityBits);
490 + throw new DataTooLongException(msg);
491 + }
492 + }
493 + assert dataUsedBits != -1;
494 +
495 + // Increase the error correction level while the data still fits in the current version number
496 + for (Ecc newEcl : Ecc.values()) { // From low to high
497 + if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8)
498 + ecl = newEcl;
499 + }
500 +
501 + // Concatenate all segments to create the data bit string
502 + BitBuffer bb = new BitBuffer();
503 + for (QrSegment seg : segs) {
504 + bb.appendBits(seg.mode.modeBits, 4);
505 + bb.appendBits(seg.numChars, seg.mode.numCharCountBits(version));
506 + bb.appendBits(seg.data, seg.bitLength);
507 + }
508 + assert bb.bitLength == dataUsedBits;
509 +
510 + // Add terminator and pad up to a byte if applicable
511 + int dataCapacityBits = getNumDataCodewords(version, ecl) * 8;
512 + assert bb.bitLength <= dataCapacityBits;
513 + bb.appendBits(0, Math.min(4, dataCapacityBits - bb.bitLength));
514 + bb.appendBits(0, (8 - bb.bitLength % 8) % 8);
515 + assert bb.bitLength % 8 == 0;
516 +
517 + // Pad with alternating bytes until data capacity is reached
518 + for (int padByte = 0xEC; bb.bitLength < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
519 + bb.appendBits(padByte, 8);
520 +
521 + // Create the QR Code object
522 + return new QrCode(version, ecl, bb.getBytes(), mask);
523 + }
524 +
525 +
526 +
527 + /*---- Instance fields ----*/
528 +
529 + // Public immutable scalar parameters:
530 +
531 + /** The version number of this QR Code, which is between 1 and 40 (inclusive).
532 + * This determines the size of this barcode. */
533 + public final int version;
534 +
535 + /** The width and height of this QR Code, measured in modules, between
536 + * 21 and 177 (inclusive). This is equal to version &#xD7; 4 + 17. */
537 + public final int size;
538 +
539 + /** The error correction level used in this QR Code, which is not {@code null}. */
540 + public final Ecc errorCorrectionLevel;
541 +
542 + /** The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive).
543 + * <p>Even if a QR Code is created with automatic masking requested (mask =
544 + * &#x2212;1), the resulting object still has a mask value between 0 and 7. */
545 + public final int mask;
546 +
547 + // Private grid of modules of this QR Code, packed tightly into bits.
548 + // Immutable after constructor finishes. Accessed through getModule().
549 + private final int[] modules;
550 +
551 +
552 +
553 + /*---- Constructor (low level) ----*/
554 +
555 + /**
556 + * Constructs a QR Code with the specified version number,
557 + * error correction level, data codeword bytes, and mask number.
558 + * <p>This is a low-level API that most users should not use directly. A mid-level
559 + * API is the {@link #encodeSegments(List,Ecc,int,int,int,boolean)} function.</p>
560 + * @param ver the version number to use, which must be in the range 1 to 40 (inclusive)
561 + * @param ecl the error correction level to use
562 + * @param dataCodewords the bytes representing segments to encode (without ECC)
563 + * @param msk the mask pattern to use, which is either &#x2212;1 for automatic choice or from 0 to 7 for fixed choice
564 + * @throws NullPointerException if the byte array or error correction level is {@code null}
565 + * @throws IllegalArgumentException if the version or mask value is out of range,
566 + * or if the data is the wrong length for the specified version and error correction level
567 + */
568 + public QrCode(int ver, Ecc ecl, byte[] dataCodewords, int msk) {
569 + // Check arguments and initialize fields
570 + if (ver < MIN_VERSION || ver > MAX_VERSION)
571 + throw new IllegalArgumentException("Version value out of range");
572 + if (msk < -1 || msk > 7)
573 + throw new IllegalArgumentException("Mask value out of range");
574 + version = ver;
575 + size = ver * 4 + 17;
576 + errorCorrectionLevel = Objects.requireNonNull(ecl);
577 + Objects.requireNonNull(dataCodewords);
578 +
579 + QrTemplate tpl = QrTemplate.MEMOIZER.get(ver);
580 + modules = tpl.template.clone();
581 +
582 + // Compute ECC, draw modules, do masking
583 + byte[] allCodewords = addEccAndInterleave(dataCodewords);
584 + drawCodewords(tpl.dataOutputBitIndexes, allCodewords);
585 + mask = handleConstructorMasking(tpl.masks, msk);
586 + }
587 +
588 +
589 +
590 + /*---- Public instance methods ----*/
591 +
592 + /**
593 + * Returns the color of the module (pixel) at the specified coordinates, which is {@code false}
594 + * for light or {@code true} for dark. The top left corner has the coordinates (x=0, y=0).
595 + * If the specified coordinates are out of bounds, then {@code false} (light) is returned.
596 + * @param x the x coordinate, where 0 is the left edge and size&#x2212;1 is the right edge
597 + * @param y the y coordinate, where 0 is the top edge and size&#x2212;1 is the bottom edge
598 + * @return {@code true} if the coordinates are in bounds and the module
599 + * at that location is dark, or {@code false} (light) otherwise
600 + */
601 + public boolean getModule(int x, int y) {
602 + if (0 <= x && x < size && 0 <= y && y < size) {
603 + int i = y * size + x;
604 + return getBit(modules[i >>> 5], i) != 0;
605 + } else
606 + return false;
607 + }
608 +
609 +
610 +
611 + /*---- Private helper methods for constructor: Drawing function modules ----*/
612 +
613 + // Draws two copies of the format bits (with its own error correction code)
614 + // based on the given mask and this object's error correction level field.
615 + private void drawFormatBits(int msk) {
616 + // Calculate error correction code and pack bits
617 + int data = errorCorrectionLevel.formatBits << 3 | msk; // errCorrLvl is uint2, mask is uint3
618 + int rem = data;
619 + for (int i = 0; i < 10; i++)
620 + rem = (rem << 1) ^ ((rem >>> 9) * 0x537);
621 + int bits = (data << 10 | rem) ^ 0x5412; // uint15
622 + assert bits >>> 15 == 0;
623 +
624 + // Draw first copy
625 + for (int i = 0; i <= 5; i++)
626 + setModule(8, i, getBit(bits, i));
627 + setModule(8, 7, getBit(bits, 6));
628 + setModule(8, 8, getBit(bits, 7));
629 + setModule(7, 8, getBit(bits, 8));
630 + for (int i = 9; i < 15; i++)
631 + setModule(14 - i, 8, getBit(bits, i));
632 +
633 + // Draw second copy
634 + for (int i = 0; i < 8; i++)
635 + setModule(size - 1 - i, 8, getBit(bits, i));
636 + for (int i = 8; i < 15; i++)
637 + setModule(8, size - 15 + i, getBit(bits, i));
638 + setModule(8, size - 8, 1); // Always dark
639 + }
640 +
641 +
642 + // Sets the module at the given coordinates to the given color.
643 + // Only used by the constructor. Coordinates must be in bounds.
644 + private void setModule(int x, int y, int dark) {
645 + assert 0 <= x && x < size;
646 + assert 0 <= y && y < size;
647 + assert dark == 0 || dark == 1;
648 + int i = y * size + x;
649 + modules[i >>> 5] &= ~(1 << i);
650 + modules[i >>> 5] |= dark << i;
651 + }
652 +
653 +
654 + /*---- Private helper methods for constructor: Codewords and masking ----*/
655 +
656 + // Returns a new byte string representing the given data with the appropriate error correction
657 + // codewords appended to it, based on this object's version and error correction level.
658 + private byte[] addEccAndInterleave(byte[] data) {
659 + Objects.requireNonNull(data);
660 + if (data.length != getNumDataCodewords(version, errorCorrectionLevel))
661 + throw new IllegalArgumentException();
662 +
663 + // Calculate parameter numbers
664 + int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[errorCorrectionLevel.ordinal()][version];
665 + int blockEccLen = ECC_CODEWORDS_PER_BLOCK [errorCorrectionLevel.ordinal()][version];
666 + int rawCodewords = QrTemplate.getNumRawDataModules(version) / 8;
667 + int numShortBlocks = numBlocks - rawCodewords % numBlocks;
668 + int shortBlockDataLen = rawCodewords / numBlocks - blockEccLen;
669 +
670 + // Split data into blocks, calculate ECC, and interleave
671 + // (not concatenate) the bytes into a single sequence
672 + byte[] result = new byte[rawCodewords];
673 + ReedSolomonGenerator rs = ReedSolomonGenerator.MEMOIZER.get(blockEccLen);
674 + byte[] ecc = new byte[blockEccLen]; // Temporary storage per iteration
675 + for (int i = 0, k = 0; i < numBlocks; i++) {
676 + int datLen = shortBlockDataLen + (i < numShortBlocks ? 0 : 1);
677 + rs.getRemainder(data, k, datLen, ecc);
678 + for (int j = 0, l = i; j < datLen; j++, k++, l += numBlocks) { // Copy data
679 + if (j == shortBlockDataLen)
680 + l -= numShortBlocks;
681 + result[l] = data[k];
682 + }
683 + for (int j = 0, l = data.length + i; j < blockEccLen; j++, l += numBlocks) // Copy ECC
684 + result[l] = ecc[j];
685 + }
686 + return result;
687 + }
688 +
689 +
690 + // Draws the given sequence of 8-bit codewords (data and error correction)
691 + // onto the entire data area of this QR Code, based on the given bit indexes.
692 + private void drawCodewords(int[] dataOutputBitIndexes, byte[] allCodewords) {
693 + Objects.requireNonNull(dataOutputBitIndexes);
694 + Objects.requireNonNull(allCodewords);
695 + if (allCodewords.length * 8 != dataOutputBitIndexes.length)
696 + throw new IllegalArgumentException();
697 + for (int i = 0; i < dataOutputBitIndexes.length; i++) {
698 + int j = dataOutputBitIndexes[i];
699 + int bit = getBit(allCodewords[i >>> 3], ~i & 7);
700 + modules[j >>> 5] |= bit << j;
701 + }
702 + }
703 +
704 +
705 + // XORs the codeword modules in this QR Code with the given mask pattern.
706 + // The function modules must be marked and the codeword bits must be drawn
707 + // before masking. Due to the arithmetic of XOR, calling applyMask() with
708 + // the same mask value a second time will undo the mask. A final well-formed
709 + // QR Code needs exactly one (not zero, two, etc.) mask applied.
710 + private void applyMask(int[] msk) {
711 + if (msk.length != modules.length)
712 + throw new IllegalArgumentException();
713 + for (int i = 0; i < msk.length; i++)
714 + modules[i] ^= msk[i];
715 + }
716 +
717 +
718 + // A messy helper function for the constructor. This QR Code must be in an unmasked state when this
719 + // method is called. The 'mask' argument is the requested mask, which is -1 for auto or 0 to 7 for fixed.
720 + // This method applies and returns the actual mask chosen, from 0 to 7.
721 + private int handleConstructorMasking(int[][] masks, int msk) {
722 + if (msk == -1) { // Automatically choose best mask
723 + int minPenalty = Integer.MAX_VALUE;
724 + for (int i = 0; i < 8; i++) {
725 + applyMask(masks[i]);
726 + drawFormatBits(i);
727 + int penalty = getPenaltyScore();
728 + if (penalty < minPenalty) {
729 + msk = i;
730 + minPenalty = penalty;
731 + }
732 + applyMask(masks[i]); // Undoes the mask due to XOR
733 + }
734 + }
735 + assert 0 <= msk && msk <= 7;
736 + applyMask(masks[msk]); // Apply the final choice of mask
737 + drawFormatBits(msk); // Overwrite old format bits
738 + return msk; // The caller shall assign this value to the final-declared field
739 + }
740 +
741 +
742 + // Calculates and returns the penalty score based on state of this QR Code's current modules.
743 + // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
744 + private int getPenaltyScore() {
745 + int result = 0;
746 + int dark = 0;
747 + int[] runHistory = new int[7];
748 +
749 + // Iterate over adjacent pairs of rows
750 + for (int index = 0, downIndex = size, end = size * size; index < end; ) {
751 + int runColor = 0;
752 + int runX = 0;
753 + Arrays.fill(runHistory, 0);
754 + int curRow = 0;
755 + int nextRow = 0;
756 + for (int x = 0; x < size; x++, index++, downIndex++) {
757 + int c = getBit(modules[index >>> 5], index);
758 + if (c == runColor) {
759 + runX++;
760 + if (runX == 5)
761 + result += PENALTY_N1;
762 + else if (runX > 5)
763 + result++;
764 + } else {
765 + finderPenaltyAddHistory(runX, runHistory);
766 + if (runColor == 0)
767 + result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
768 + runColor = c;
769 + runX = 1;
770 + }
771 + dark += c;
772 + if (downIndex < end) {
773 + curRow = ((curRow << 1) | c) & 3;
774 + nextRow = ((nextRow << 1) | getBit(modules[downIndex >>> 5], downIndex)) & 3;
775 + // 2*2 blocks of modules having same color
776 + if (x >= 1 && (curRow == 0 || curRow == 3) && curRow == nextRow)
777 + result += PENALTY_N2;
778 + }
779 + }
780 + result += finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3;
781 + }
782 +
783 + // Iterate over single columns
784 + for (int x = 0; x < size; x++) {
785 + int runColor = 0;
786 + int runY = 0;
787 + Arrays.fill(runHistory, 0);
788 + for (int y = 0, index = x; y < size; y++, index += size) {
789 + int c = getBit(modules[index >>> 5], index);
790 + if (c == runColor) {
791 + runY++;
792 + if (runY == 5)
793 + result += PENALTY_N1;
794 + else if (runY > 5)
795 + result++;
796 + } else {
797 + finderPenaltyAddHistory(runY, runHistory);
798 + if (runColor == 0)
799 + result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
800 + runColor = c;
801 + runY = 1;
802 + }
803 + }
804 + result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3;
805 + }
806 +
807 + // Balance of dark and light modules
808 + int total = size * size; // Note that size is odd, so dark/total != 1/2
809 + // Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)%
810 + int k = (Math.abs(dark * 20 - total * 10) + total - 1) / total - 1;
811 + result += k * PENALTY_N4;
812 + return result;
813 + }
814 +
815 +
816 +
817 + /*---- Private helper functions ----*/
818 +
819 + // Returns the number of 8-bit data (i.e. not error correction) codewords contained in any
820 + // QR Code of the given version number and error correction level, with remainder bits discarded.
821 + // This stateless pure function could be implemented as a (40*4)-cell lookup table.
822 + static int getNumDataCodewords(int ver, Ecc ecl) {
823 + return QrTemplate.getNumRawDataModules(ver) / 8
824 + - ECC_CODEWORDS_PER_BLOCK [ecl.ordinal()][ver]
825 + * NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal()][ver];
826 + }
827 +
828 +
829 + // Can only be called immediately after a light run is added, and
830 + // returns either 0, 1, or 2. A helper function for getPenaltyScore().
831 + private int finderPenaltyCountPatterns(int[] runHistory) {
832 + int n = runHistory[1];
833 + assert n <= size * 3;
834 + boolean core = n > 0 && runHistory[2] == n && runHistory[3] == n * 3 && runHistory[4] == n && runHistory[5] == n;
835 + return (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0)
836 + + (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0);
837 + }
838 +
839 +
840 + // Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore().
841 + private int finderPenaltyTerminateAndCount(int currentRunColor, int currentRunLength, int[] runHistory) {
842 + if (currentRunColor == 1) { // Terminate dark run
843 + finderPenaltyAddHistory(currentRunLength, runHistory);
844 + currentRunLength = 0;
845 + }
846 + currentRunLength += size; // Add light border to final run
847 + finderPenaltyAddHistory(currentRunLength, runHistory);
848 + return finderPenaltyCountPatterns(runHistory);
849 + }
850 +
851 +
852 + // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore().
853 + private void finderPenaltyAddHistory(int currentRunLength, int[] runHistory) {
854 + if (runHistory[0] == 0)
855 + currentRunLength += size; // Add light border to initial run
856 + System.arraycopy(runHistory, 0, runHistory, 1, runHistory.length - 1);
857 + runHistory[0] = currentRunLength;
858 + }
859 +
860 +
861 + // Returns 0 or 1 based on the (i mod 32)'th bit of x.
862 + static int getBit(int x, int i) {
863 + return (x >>> i) & 1;
864 + }
865 +
866 +
867 + /*---- Constants and tables ----*/
868 +
869 + /** The minimum version number (1) supported in the QR Code Model 2 standard. */
870 + public static final int MIN_VERSION = 1;
871 +
872 + /** The maximum version number (40) supported in the QR Code Model 2 standard. */
873 + public static final int MAX_VERSION = 40;
874 +
875 +
876 + // For use in getPenaltyScore(), when evaluating which mask is best.
877 + private static final int PENALTY_N1 = 3;
878 + private static final int PENALTY_N2 = 3;
879 + private static final int PENALTY_N3 = 40;
880 + private static final int PENALTY_N4 = 10;
881 +
882 +
883 + private static final byte[][] ECC_CODEWORDS_PER_BLOCK = {
884 + // Version: (note that index 0 is for padding, and is set to an illegal value)
885 + //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
886 + {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low
887 + {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium
888 + {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile
889 + {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High
890 + };
891 +
892 + private static final byte[][] NUM_ERROR_CORRECTION_BLOCKS = {
893 + // Version: (note that index 0 is for padding, and is set to an illegal value)
894 + //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
895 + {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low
896 + {-1, 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}, // Medium
897 + {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile
898 + {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High
899 + };
900 +
901 +
902 +
903 + /*---- Public helper enumeration ----*/
904 +
905 + /**
906 + * The error correction level in a QR Code symbol.
907 + */
908 + public enum Ecc {
909 + // Must be declared in ascending order of error protection
910 + // so that the implicit ordinal() and values() work properly
911 + /** The QR Code can tolerate about 7% erroneous codewords. */ LOW(1),
912 + /** The QR Code can tolerate about 15% erroneous codewords. */ MEDIUM(0),
913 + /** The QR Code can tolerate about 25% erroneous codewords. */ QUARTILE(3),
914 + /** The QR Code can tolerate about 30% erroneous codewords. */ HIGH(2);
915 +
916 + // In the range 0 to 3 (unsigned 2-bit integer).
917 + final int formatBits;
918 +
919 + // Constructor.
920 + private Ecc(int fb) {
921 + formatBits = fb;
922 + }
923 + }
924 +
925 +}
926 diff --git a/src/io/nayuki/fastqrcodegen/QrSegment.java b/src/io/nayuki/fastqrcodegen/QrSegment.java
927 new file mode 100644
928 index 0000000..7ac0234
929 --- /dev/null
930 +++ b/src/io/nayuki/fastqrcodegen/QrSegment.java
931 @@ -0,0 +1,338 @@
932 +/*
933 + * Fast QR Code generator library
934 + *
935 + * Copyright (c) Project Nayuki. (MIT License)
936 + * https://www.nayuki.io/page/fast-qr-code-generator-library
937 + *
938 + * Permission is hereby granted, free of charge, to any person obtaining a copy of
939 + * this software and associated documentation files (the "Software"), to deal in
940 + * the Software without restriction, including without limitation the rights to
941 + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
942 + * the Software, and to permit persons to whom the Software is furnished to do so,
943 + * subject to the following conditions:
944 + * - The above copyright notice and this permission notice shall be included in
945 + * all copies or substantial portions of the Software.
946 + * - The Software is provided "as is", without warranty of any kind, express or
947 + * implied, including but not limited to the warranties of merchantability,
948 + * fitness for a particular purpose and noninfringement. In no event shall the
949 + * authors or copyright holders be liable for any claim, damages or other
950 + * liability, whether in an action of contract, tort or otherwise, arising from,
951 + * out of or in connection with the Software or the use or other dealings in the
952 + * Software.
953 + */
954 +
955 +package io.nayuki.fastqrcodegen;
956 +
957 +import java.nio.charset.StandardCharsets;
958 +import java.util.ArrayList;
959 +import java.util.Arrays;
960 +import java.util.List;
961 +import java.util.Objects;
962 +
963 +
964 +/**
965 + * A segment of character/binary/control data in a QR Code symbol.
966 + * Instances of this class are immutable.
967 + * <p>The mid-level way to create a segment is to take the payload data and call a
968 + * static factory function such as {@link QrSegment#makeNumeric(String)}. The low-level
969 + * way to create a segment is to custom-make the bit buffer and call the {@link
970 + * QrSegment#QrSegment(Mode,int,int[],int) constructor} with appropriate values.</p>
971 + * <p>This segment class imposes no length restrictions, but QR Codes have restrictions.
972 + * Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.
973 + * Any segment longer than this is meaningless for the purpose of generating QR Codes.
974 + * This class can represent kanji mode segments, but provides no help in encoding them
975 + * - see {@link QrSegmentAdvanced} for full kanji support.</p>
976 + */
977 +public final class QrSegment {
978 +
979 + /*---- Static factory functions (mid level) ----*/
980 +
981 + /**
982 + * Returns a segment representing the specified binary data
983 + * encoded in byte mode. All input byte arrays are acceptable.
984 + * <p>Any text string can be converted to UTF-8 bytes ({@code
985 + * s.getBytes(StandardCharsets.UTF_8)}) and encoded as a byte mode segment.</p>
986 + * @param data the binary data (not {@code null})
987 + * @return a segment (not {@code null}) containing the data
988 + * @throws NullPointerException if the array is {@code null}
989 + */
990 + public static QrSegment makeBytes(byte[] data) {
991 + Objects.requireNonNull(data);
992 + if (data.length * 8L > Integer.MAX_VALUE)
993 + throw new IllegalArgumentException("Data too long");
994 + int[] bits = new int[(data.length + 3) / 4];
995 + for (int i = 0; i < data.length; i++)
996 + bits[i >>> 2] |= (data[i] & 0xFF) << (~i << 3);
997 + return new QrSegment(Mode.BYTE, data.length, bits, data.length * 8);
998 + }
999 +
1000 +
1001 + /**
1002 + * Returns a segment representing the specified string of decimal digits encoded in numeric mode.
1003 + * @param digits the text (not {@code null}), with only digits from 0 to 9 allowed
1004 + * @return a segment (not {@code null}) containing the text
1005 + * @throws NullPointerException if the string is {@code null}
1006 + * @throws IllegalArgumentException if the string contains non-digit characters
1007 + */
1008 + public static QrSegment makeNumeric(String digits) {
1009 + Objects.requireNonNull(digits);
1010 + BitBuffer bb = new BitBuffer();
1011 + int accumData = 0;
1012 + int accumCount = 0;
1013 + for (int i = 0; i < digits.length(); i++) {
1014 + char c = digits.charAt(i);
1015 + if (c < '0' || c > '9')
1016 + throw new IllegalArgumentException("String contains non-numeric characters");
1017 + accumData = accumData * 10 + (c - '0');
1018 + accumCount++;
1019 + if (accumCount == 3) {
1020 + bb.appendBits(accumData, 10);
1021 + accumData = 0;
1022 + accumCount = 0;
1023 + }
1024 + }
1025 + if (accumCount > 0) // 1 or 2 digits remaining
1026 + bb.appendBits(accumData, accumCount * 3 + 1);
1027 + return new QrSegment(Mode.NUMERIC, digits.length(), bb.data, bb.bitLength);
1028 + }
1029 +
1030 +
1031 + /**
1032 + * Returns a segment representing the specified text string encoded in alphanumeric mode.
1033 + * The characters allowed are: 0 to 9, A to Z (uppercase only), space,
1034 + * dollar, percent, asterisk, plus, hyphen, period, slash, colon.
1035 + * @param text the text (not {@code null}), with only certain characters allowed
1036 + * @return a segment (not {@code null}) containing the text
1037 + * @throws NullPointerException if the string is {@code null}
1038 + * @throws IllegalArgumentException if the string contains non-encodable characters
1039 + */
1040 + public static QrSegment makeAlphanumeric(String text) {
1041 + Objects.requireNonNull(text);
1042 + BitBuffer bb = new BitBuffer();
1043 + int accumData = 0;
1044 + int accumCount = 0;
1045 + for (int i = 0; i < text.length(); i++) {
1046 + char c = text.charAt(i);
1047 + if (c >= ALPHANUMERIC_MAP.length || ALPHANUMERIC_MAP[c] == -1)
1048 + throw new IllegalArgumentException("String contains unencodable characters in alphanumeric mode");
1049 + accumData = accumData * 45 + ALPHANUMERIC_MAP[c];
1050 + accumCount++;
1051 + if (accumCount == 2) {
1052 + bb.appendBits(accumData, 11);
1053 + accumData = 0;
1054 + accumCount = 0;
1055 + }
1056 + }
1057 + if (accumCount > 0) // 1 character remaining
1058 + bb.appendBits(accumData, 6);
1059 + return new QrSegment(Mode.ALPHANUMERIC, text.length(), bb.data, bb.bitLength);
1060 + }
1061 +
1062 +
1063 + /**
1064 + * Returns a list of zero or more segments to represent the specified Unicode text string.
1065 + * The result may use various segment modes and switch modes to optimize the length of the bit stream.
1066 + * @param text the text to be encoded, which can be any Unicode string
1067 + * @return a new mutable list (not {@code null}) of segments (not {@code null}) containing the text
1068 + * @throws NullPointerException if the text is {@code null}
1069 + */
1070 + public static List<QrSegment> makeSegments(String text) {
1071 + Objects.requireNonNull(text);
1072 +
1073 + // Select the most efficient segment encoding automatically
1074 + List<QrSegment> result = new ArrayList<>();
1075 + if (text.equals("")); // Leave result empty
1076 + else if (isNumeric(text))
1077 + result.add(makeNumeric(text));
1078 + else if (isAlphanumeric(text))
1079 + result.add(makeAlphanumeric(text));
1080 + else
1081 + result.add(makeBytes(text.getBytes(StandardCharsets.UTF_8)));
1082 + return result;
1083 + }
1084 +
1085 +
1086 + /**
1087 + * Returns a segment representing an Extended Channel Interpretation
1088 + * (ECI) designator with the specified assignment value.
1089 + * @param assignVal the ECI assignment number (see the AIM ECI specification)
1090 + * @return a segment (not {@code null}) containing the data
1091 + * @throws IllegalArgumentException if the value is outside the range [0, 10<sup>6</sup>)
1092 + */
1093 + public static QrSegment makeEci(int assignVal) {
1094 + BitBuffer bb = new BitBuffer();
1095 + if (assignVal < 0)
1096 + throw new IllegalArgumentException("ECI assignment value out of range");
1097 + else if (assignVal < (1 << 7))
1098 + bb.appendBits(assignVal, 8);
1099 + else if (assignVal < (1 << 14)) {
1100 + bb.appendBits(2, 2);
1101 + bb.appendBits(assignVal, 14);
1102 + } else if (assignVal < 1_000_000) {
1103 + bb.appendBits(6, 3);
1104 + bb.appendBits(assignVal, 21);
1105 + } else
1106 + throw new IllegalArgumentException("ECI assignment value out of range");
1107 + return new QrSegment(Mode.ECI, 0, bb.data, bb.bitLength);
1108 + }
1109 +
1110 +
1111 + /**
1112 + * Tests whether the specified string can be encoded as a segment in numeric mode.
1113 + * A string is encodable iff each character is in the range 0 to 9.
1114 + * @param text the string to test for encodability (not {@code null})
1115 + * @return {@code true} iff each character is in the range 0 to 9.
1116 + * @throws NullPointerException if the string is {@code null}
1117 + * @see #makeNumeric(String)
1118 + */
1119 + public static boolean isNumeric(String text) {
1120 + for (int i = 0; i < text.length(); i++) {
1121 + char c = text.charAt(i);
1122 + if (c < '0' || c > '9')
1123 + return false;
1124 + }
1125 + return true;
1126 + }
1127 +
1128 +
1129 + /**
1130 + * Tests whether the specified string can be encoded as a segment in alphanumeric mode.
1131 + * A string is encodable iff each character is in the following set: 0 to 9, A to Z
1132 + * (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
1133 + * @param text the string to test for encodability (not {@code null})
1134 + * @return {@code true} iff each character is in the alphanumeric mode character set
1135 + * @throws NullPointerException if the string is {@code null}
1136 + * @see #makeAlphanumeric(String)
1137 + */
1138 + public static boolean isAlphanumeric(String text) {
1139 + for (int i = 0; i < text.length(); i++) {
1140 + char c = text.charAt(i);
1141 + if (c >= ALPHANUMERIC_MAP.length || ALPHANUMERIC_MAP[c] == -1)
1142 + return false;
1143 + }
1144 + return true;
1145 + }
1146 +
1147 +
1148 +
1149 + /*---- Instance fields ----*/
1150 +
1151 + /** The mode indicator of this segment. Not {@code null}. */
1152 + public final Mode mode;
1153 +
1154 + /** The length of this segment's unencoded data. Measured in characters for
1155 + * numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode.
1156 + * Always zero or positive. Not the same as the data's bit length. */
1157 + public final int numChars;
1158 +
1159 + // The data bits of this segment. Not null.
1160 + final int[] data;
1161 +
1162 + // Requires 0 <= bitLength <= data.length * 32.
1163 + final int bitLength;
1164 +
1165 +
1166 + /*---- Constructor (low level) ----*/
1167 +
1168 + /**
1169 + * Constructs a QR Code segment with the specified attributes and data.
1170 + * The character count (numCh) must agree with the mode and the bit buffer length,
1171 + * but the constraint isn't checked. The specified bit buffer is cloned and stored.
1172 + * @param md the mode (not {@code null})
1173 + * @param numCh the data length in characters or bytes, which is non-negative
1174 + * @param data the data bits (not {@code null})
1175 + * @param bitLen the number of valid prefix bits in the data array
1176 + * @throws NullPointerException if the mode or data is {@code null}
1177 + * @throws IllegalArgumentException if the character count is negative
1178 + */
1179 + public QrSegment(Mode md, int numCh, int[] data, int bitLen) {
1180 + mode = Objects.requireNonNull(md);
1181 + this.data = Objects.requireNonNull(data);
1182 + if (numCh < 0 || bitLen < 0 || bitLen > data.length * 32L)
1183 + throw new IllegalArgumentException("Invalid value");
1184 + numChars = numCh;
1185 + bitLength = bitLen;
1186 + }
1187 +
1188 +
1189 + // Calculates the number of bits needed to encode the given segments at the given version.
1190 + // Returns a non-negative number if successful. Otherwise returns -1 if a segment has too
1191 + // many characters to fit its length field, or the total bits exceeds Integer.MAX_VALUE.
1192 + static int getTotalBits(List<QrSegment> segs, int version) {
1193 + Objects.requireNonNull(segs);
1194 + long result = 0;
1195 + for (QrSegment seg : segs) {
1196 + Objects.requireNonNull(seg);
1197 + int ccbits = seg.mode.numCharCountBits(version);
1198 + if (seg.numChars >= (1 << ccbits))
1199 + return -1; // The segment's length doesn't fit the field's bit width
1200 + result += 4L + ccbits + seg.bitLength;
1201 + if (result > Integer.MAX_VALUE)
1202 + return -1; // The sum will overflow an int type
1203 + }
1204 + return (int)result;
1205 + }
1206 +
1207 +
1208 + /*---- Constants ----*/
1209 +
1210 + static final int[] ALPHANUMERIC_MAP;
1211 +
1212 + static {
1213 + final String ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
1214 + int maxCh = -1;
1215 + for (int i = 0; i < ALPHANUMERIC_CHARSET.length(); i++)
1216 + maxCh = Math.max(ALPHANUMERIC_CHARSET.charAt(i), maxCh);
1217 + ALPHANUMERIC_MAP = new int[maxCh + 1];
1218 + Arrays.fill(ALPHANUMERIC_MAP, -1);
1219 + for (int i = 0; i < ALPHANUMERIC_CHARSET.length(); i++)
1220 + ALPHANUMERIC_MAP[ALPHANUMERIC_CHARSET.charAt(i)] = i;
1221 + }
1222 +
1223 +
1224 +
1225 + /*---- Public helper enumeration ----*/
1226 +
1227 + /**
1228 + * Describes how a segment's data bits are interpreted.
1229 + */
1230 + public enum Mode {
1231 +
1232 + /*-- Constants --*/
1233 +
1234 + NUMERIC (0x1, 10, 12, 14),
1235 + ALPHANUMERIC(0x2, 9, 11, 13),
1236 + BYTE (0x4, 8, 16, 16),
1237 + KANJI (0x8, 8, 10, 12),
1238 + ECI (0x7, 0, 0, 0);
1239 +
1240 +
1241 + /*-- Fields --*/
1242 +
1243 + // The mode indicator bits, which is a uint4 value (range 0 to 15).
1244 + final int modeBits;
1245 +
1246 + // Number of character count bits for three different version ranges.
1247 + private final int[] numBitsCharCount;
1248 +
1249 +
1250 + /*-- Constructor --*/
1251 +
1252 + private Mode(int mode, int... ccbits) {
1253 + modeBits = mode;
1254 + numBitsCharCount = ccbits;
1255 + }
1256 +
1257 +
1258 + /*-- Method --*/
1259 +
1260 + // Returns the bit width of the character count field for a segment in this mode
1261 + // in a QR Code at the given version number. The result is in the range [0, 16].
1262 + int numCharCountBits(int ver) {
1263 + assert QrCode.MIN_VERSION <= ver && ver <= QrCode.MAX_VERSION;
1264 + return numBitsCharCount[(ver + 7) / 17];
1265 + }
1266 +
1267 + }
1268 +
1269 +}
1270 diff --git a/src/io/nayuki/fastqrcodegen/QrTemplate.java b/src/io/nayuki/fastqrcodegen/QrTemplate.java
1271 new file mode 100644
1272 index 0000000..b841da2
1273 --- /dev/null
1274 +++ b/src/io/nayuki/fastqrcodegen/QrTemplate.java
1275 @@ -0,0 +1,270 @@
1276 +/*
1277 + * Fast QR Code generator library
1278 + *
1279 + * Copyright (c) Project Nayuki. (MIT License)
1280 + * https://www.nayuki.io/page/fast-qr-code-generator-library
1281 + *
1282 + * Permission is hereby granted, free of charge, to any person obtaining a copy of
1283 + * this software and associated documentation files (the "Software"), to deal in
1284 + * the Software without restriction, including without limitation the rights to
1285 + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
1286 + * the Software, and to permit persons to whom the Software is furnished to do so,
1287 + * subject to the following conditions:
1288 + * - The above copyright notice and this permission notice shall be included in
1289 + * all copies or substantial portions of the Software.
1290 + * - The Software is provided "as is", without warranty of any kind, express or
1291 + * implied, including but not limited to the warranties of merchantability,
1292 + * fitness for a particular purpose and noninfringement. In no event shall the
1293 + * authors or copyright holders be liable for any claim, damages or other
1294 + * liability, whether in an action of contract, tort or otherwise, arising from,
1295 + * out of or in connection with the Software or the use or other dealings in the
1296 + * Software.
1297 + */
1298 +
1299 +package io.nayuki.fastqrcodegen;
1300 +
1301 +
1302 +// Stores the parts of a QR Code that depend only on the version number,
1303 +// and does not depend on the data or error correction level or mask.
1304 +final class QrTemplate {
1305 +
1306 + // Use this memoizer to get instances of this class.
1307 + public static final Memoizer<Integer,QrTemplate> MEMOIZER
1308 + = new Memoizer<>(QrTemplate::new);
1309 +
1310 +
1311 + private final int version; // In the range [1, 40].
1312 + private final int size; // Derived from version.
1313 +
1314 + final int[] template; // Length and values depend on version.
1315 + final int[][] masks; // masks.length == 8, and masks[i].length == template.length.
1316 + final int[] dataOutputBitIndexes; // Length and values depend on version.
1317 +
1318 + // Indicates function modules that are not subjected to masking. Discarded when constructor finishes.
1319 + // Otherwise when the constructor is running, isFunction.length == template.length.
1320 + private int[] isFunction;
1321 +
1322 +
1323 + // Creates a QR Code template for the given version number.
1324 + private QrTemplate(int ver) {
1325 + if (ver < QrCode.MIN_VERSION || ver > QrCode.MAX_VERSION)
1326 + throw new IllegalArgumentException("Version out of range");
1327 + version = ver;
1328 + size = version * 4 + 17;
1329 + template = new int[(size * size + 31) / 32];
1330 + isFunction = new int[template.length];
1331 +
1332 + drawFunctionPatterns(); // Reads and writes fields
1333 + masks = generateMasks(); // Reads fields, returns array
1334 + dataOutputBitIndexes = generateZigzagScan(); // Reads fields, returns array
1335 + isFunction = null;
1336 + }
1337 +
1338 +
1339 + // Reads this object's version field, and draws and marks all function modules.
1340 + private void drawFunctionPatterns() {
1341 + // Draw horizontal and vertical timing patterns
1342 + for (int i = 0; i < size; i++) {
1343 + darkenFunctionModule(6, i, ~i & 1);
1344 + darkenFunctionModule(i, 6, ~i & 1);
1345 + }
1346 +
1347 + // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
1348 + drawFinderPattern(3, 3);
1349 + drawFinderPattern(size - 4, 3);
1350 + drawFinderPattern(3, size - 4);
1351 +
1352 + // Draw numerous alignment patterns
1353 + int[] alignPatPos = getAlignmentPatternPositions();
1354 + int numAlign = alignPatPos.length;
1355 + for (int i = 0; i < numAlign; i++) {
1356 + for (int j = 0; j < numAlign; j++) {
1357 + // Don't draw on the three finder corners
1358 + if (!(i == 0 && j == 0 || i == 0 && j == numAlign - 1 || i == numAlign - 1 && j == 0))
1359 + drawAlignmentPattern(alignPatPos[i], alignPatPos[j]);
1360 + }
1361 + }
1362 +
1363 + // Draw configuration data
1364 + drawDummyFormatBits();
1365 + drawVersion();
1366 + }
1367 +
1368 +
1369 + // Draws two blank copies of the format bits.
1370 + private void drawDummyFormatBits() {
1371 + // Draw first copy
1372 + for (int i = 0; i <= 5; i++)
1373 + darkenFunctionModule(8, i, 0);
1374 + darkenFunctionModule(8, 7, 0);
1375 + darkenFunctionModule(8, 8, 0);
1376 + darkenFunctionModule(7, 8, 0);
1377 + for (int i = 9; i < 15; i++)
1378 + darkenFunctionModule(14 - i, 8, 0);
1379 +
1380 + // Draw second copy
1381 + for (int i = 0; i < 8; i++)
1382 + darkenFunctionModule(size - 1 - i, 8, 0);
1383 + for (int i = 8; i < 15; i++)
1384 + darkenFunctionModule(8, size - 15 + i, 0);
1385 + darkenFunctionModule(8, size - 8, 1); // Always dark
1386 + }
1387 +
1388 +
1389 + // Draws two copies of the version bits (with its own error correction code),
1390 + // based on this object's version field, iff 7 <= version <= 40.
1391 + private void drawVersion() {
1392 + if (version < 7)
1393 + return;
1394 +
1395 + // Calculate error correction code and pack bits
1396 + int rem = version; // version is uint6, in the range [7, 40]
1397 + for (int i = 0; i < 12; i++)
1398 + rem = (rem << 1) ^ ((rem >>> 11) * 0x1F25);
1399 + int bits = version << 12 | rem; // uint18
1400 + assert bits >>> 18 == 0;
1401 +
1402 + // Draw two copies
1403 + for (int i = 0; i < 18; i++) {
1404 + int bit = QrCode.getBit(bits, i);
1405 + int a = size - 11 + i % 3;
1406 + int b = i / 3;
1407 + darkenFunctionModule(a, b, bit);
1408 + darkenFunctionModule(b, a, bit);
1409 + }
1410 + }
1411 +
1412 +
1413 + // Draws a 9*9 finder pattern including the border separator,
1414 + // with the center module at (x, y). Modules can be out of bounds.
1415 + private void drawFinderPattern(int x, int y) {
1416 + for (int dy = -4; dy <= 4; dy++) {
1417 + for (int dx = -4; dx <= 4; dx++) {
1418 + int dist = Math.max(Math.abs(dx), Math.abs(dy)); // Chebyshev/infinity norm
1419 + int xx = x + dx, yy = y + dy;
1420 + if (0 <= xx && xx < size && 0 <= yy && yy < size)
1421 + darkenFunctionModule(xx, yy, (dist != 2 && dist != 4) ? 1 : 0);
1422 + }
1423 + }
1424 + }
1425 +
1426 +
1427 + // Draws a 5*5 alignment pattern, with the center module
1428 + // at (x, y). All modules must be in bounds.
1429 + private void drawAlignmentPattern(int x, int y) {
1430 + for (int dy = -2; dy <= 2; dy++) {
1431 + for (int dx = -2; dx <= 2; dx++)
1432 + darkenFunctionModule(x + dx, y + dy, Math.abs(Math.max(Math.abs(dx), Math.abs(dy)) - 1));
1433 + }
1434 + }
1435 +
1436 +
1437 + // Computes and returns a new array of masks, based on this object's various fields.
1438 + private int[][] generateMasks() {
1439 + int[][] result = new int[8][template.length];
1440 + for (int mask = 0; mask < result.length; mask++) {
1441 + int[] maskModules = result[mask];
1442 + for (int y = 0, i = 0; y < size; y++) {
1443 + for (int x = 0; x < size; x++, i++) {
1444 + boolean invert;
1445 + switch (mask) {
1446 + case 0: invert = (x + y) % 2 == 0; break;
1447 + case 1: invert = y % 2 == 0; break;
1448 + case 2: invert = x % 3 == 0; break;
1449 + case 3: invert = (x + y) % 3 == 0; break;
1450 + case 4: invert = (x / 3 + y / 2) % 2 == 0; break;
1451 + case 5: invert = x * y % 2 + x * y % 3 == 0; break;
1452 + case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
1453 + case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
1454 + default: throw new AssertionError();
1455 + }
1456 + int bit = (invert ? 1 : 0) & ~getModule(isFunction, x, y);
1457 + maskModules[i >>> 5] |= bit << i;
1458 + }
1459 + }
1460 + }
1461 + return result;
1462 + }
1463 +
1464 +
1465 + // Computes and returns an array of bit indexes, based on this object's various fields.
1466 + private int[] generateZigzagScan() {
1467 + int[] result = new int[getNumRawDataModules(version) / 8 * 8];
1468 + int i = 0; // Bit index into the data
1469 + for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
1470 + if (right == 6)
1471 + right = 5;
1472 + for (int vert = 0; vert < size; vert++) { // Vertical counter
1473 + for (int j = 0; j < 2; j++) {
1474 + int x = right - j; // Actual x coordinate
1475 + boolean upward = ((right + 1) & 2) == 0;
1476 + int y = upward ? size - 1 - vert : vert; // Actual y coordinate
1477 + if (getModule(isFunction, x, y) == 0 && i < result.length) {
1478 + result[i] = y * size + x;
1479 + i++;
1480 + }
1481 + }
1482 + }
1483 + }
1484 + assert i == result.length;
1485 + return result;
1486 + }
1487 +
1488 +
1489 + // Returns the value of the bit at the given coordinates in the given grid.
1490 + private int getModule(int[] grid, int x, int y) {
1491 + assert 0 <= x && x < size;
1492 + assert 0 <= y && y < size;
1493 + int i = y * size + x;
1494 + return QrCode.getBit(grid[i >>> 5], i);
1495 + }
1496 +
1497 +
1498 + // Marks the module at the given coordinates as a function module.
1499 + // Also either sets that module dark or keeps its color unchanged.
1500 + private void darkenFunctionModule(int x, int y, int enable) {
1501 + assert 0 <= x && x < size;
1502 + assert 0 <= y && y < size;
1503 + assert enable == 0 || enable == 1;
1504 + int i = y * size + x;
1505 + template[i >>> 5] |= enable << i;
1506 + isFunction[i >>> 5] |= 1 << i;
1507 + }
1508 +
1509 +
1510 + // Returns an ascending list of positions of alignment patterns for this version number.
1511 + // Each position is in the range [0,177), and are used on both the x and y axes.
1512 + // This could be implemented as lookup table of 40 variable-length lists of unsigned bytes.
1513 + private int[] getAlignmentPatternPositions() {
1514 + if (version == 1)
1515 + return new int[]{};
1516 + else {
1517 + int numAlign = version / 7 + 2;
1518 + int step = (version == 32) ? 26 :
1519 + (version * 4 + numAlign * 2 + 1) / (numAlign * 2 - 2) * 2;
1520 + int[] result = new int[numAlign];
1521 + result[0] = 6;
1522 + for (int i = result.length - 1, pos = size - 7; i >= 1; i--, pos -= step)
1523 + result[i] = pos;
1524 + return result;
1525 + }
1526 + }
1527 +
1528 +
1529 + // Returns the number of data bits that can be stored in a QR Code of the given version number, after
1530 + // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
1531 + // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
1532 + static int getNumRawDataModules(int ver) {
1533 + if (ver < QrCode.MIN_VERSION || ver > QrCode.MAX_VERSION)
1534 + throw new IllegalArgumentException("Version number out of range");
1535 + int result = (16 * ver + 128) * ver + 64;
1536 + if (ver >= 2) {
1537 + int numAlign = ver / 7 + 2;
1538 + result -= (25 * numAlign - 10) * numAlign - 55;
1539 + if (ver >= 7)
1540 + result -= 36;
1541 + }
1542 + return result;
1543 + }
1544 +
1545 +}
1546 diff --git a/src/io/nayuki/fastqrcodegen/ReedSolomonGenerator.java b/src/io/nayuki/fastqrcodegen/ReedSolomonGenerator.java
1547 new file mode 100644
1548 index 0000000..a4b77be
1549 --- /dev/null
1550 +++ b/src/io/nayuki/fastqrcodegen/ReedSolomonGenerator.java
1551 @@ -0,0 +1,106 @@
1552 +/*
1553 + * Fast QR Code generator library
1554 + *
1555 + * Copyright (c) Project Nayuki. (MIT License)
1556 + * https://www.nayuki.io/page/fast-qr-code-generator-library
1557 + *
1558 + * Permission is hereby granted, free of charge, to any person obtaining a copy of
1559 + * this software and associated documentation files (the "Software"), to deal in
1560 + * the Software without restriction, including without limitation the rights to
1561 + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
1562 + * the Software, and to permit persons to whom the Software is furnished to do so,
1563 + * subject to the following conditions:
1564 + * - The above copyright notice and this permission notice shall be included in
1565 + * all copies or substantial portions of the Software.
1566 + * - The Software is provided "as is", without warranty of any kind, express or
1567 + * implied, including but not limited to the warranties of merchantability,
1568 + * fitness for a particular purpose and noninfringement. In no event shall the
1569 + * authors or copyright holders be liable for any claim, damages or other
1570 + * liability, whether in an action of contract, tort or otherwise, arising from,
1571 + * out of or in connection with the Software or the use or other dealings in the
1572 + * Software.
1573 + */
1574 +
1575 +package io.nayuki.fastqrcodegen;
1576 +
1577 +import java.util.Arrays;
1578 +import java.util.Objects;
1579 +
1580 +
1581 +// Computes Reed-Solomon error correction codewords for given data codewords.
1582 +final class ReedSolomonGenerator {
1583 +
1584 + // Use this memoizer to get instances of this class.
1585 + public static final Memoizer<Integer,ReedSolomonGenerator> MEMOIZER
1586 + = new Memoizer<>(ReedSolomonGenerator::new);
1587 +
1588 +
1589 + // A table of size 256 * degree, where polynomialMultiply[i][j] = multiply(i, coefficients[j]).
1590 + // 'coefficients' is the temporary array computed in the constructor.
1591 + private byte[][] polynomialMultiply;
1592 +
1593 +
1594 + // Creates a Reed-Solomon ECC generator polynomial for the given degree.
1595 + private ReedSolomonGenerator(int degree) {
1596 + if (degree < 1 || degree > 255)
1597 + throw new IllegalArgumentException("Degree out of range");
1598 +
1599 + // The divisor polynomial, whose coefficients are stored from highest to lowest power.
1600 + // For example, x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.
1601 + byte[] coefficients = new byte[degree];
1602 + coefficients[degree - 1] = 1; // Start off with the monomial x^0
1603 +
1604 + // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
1605 + // and drop the highest monomial term which is always 1x^degree.
1606 + // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
1607 + int root = 1;
1608 + for (int i = 0; i < degree; i++) {
1609 + // Multiply the current product by (x - r^i)
1610 + for (int j = 0; j < coefficients.length; j++) {
1611 + coefficients[j] = (byte)multiply(coefficients[j] & 0xFF, root);
1612 + if (j + 1 < coefficients.length)
1613 + coefficients[j] ^= coefficients[j + 1];
1614 + }
1615 + root = multiply(root, 0x02);
1616 + }
1617 +
1618 + polynomialMultiply = new byte[256][degree];
1619 + for (int i = 0; i < polynomialMultiply.length; i++) {
1620 + for (int j = 0; j < degree; j++)
1621 + polynomialMultiply[i][j] = (byte)multiply(i, coefficients[j] & 0xFF);
1622 + }
1623 + }
1624 +
1625 +
1626 + // Returns the error correction codeword for the given data polynomial and this divisor polynomial.
1627 + public void getRemainder(byte[] data, int dataOff, int dataLen, byte[] result) {
1628 + Objects.requireNonNull(data);
1629 + Objects.requireNonNull(result);
1630 + int degree = polynomialMultiply[0].length;
1631 + assert result.length == degree;
1632 +
1633 + Arrays.fill(result, (byte)0);
1634 + for (int i = dataOff, dataEnd = dataOff + dataLen; i < dataEnd; i++) { // Polynomial division
1635 + byte[] table = polynomialMultiply[(data[i] ^ result[0]) & 0xFF];
1636 + for (int j = 0; j < degree - 1; j++)
1637 + result[j] = (byte)(result[j + 1] ^ table[j]);
1638 + result[degree - 1] = table[degree - 1];
1639 + }
1640 + }
1641 +
1642 +
1643 + // Returns the product of the two given field elements modulo GF(2^8/0x11D). The arguments and result
1644 + // are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8.
1645 + private static int multiply(int x, int y) {
1646 + assert x >> 8 == 0 && y >> 8 == 0;
1647 + // Russian peasant multiplication
1648 + int z = 0;
1649 + for (int i = 7; i >= 0; i--) {
1650 + z = (z << 1) ^ ((z >>> 7) * 0x11D);
1651 + z ^= ((y >>> i) & 1) * x;
1652 + }
1653 + assert z >>> 8 == 0;
1654 + return z;
1655 + }
1656 +
1657 +}
44 0005-Use-mariadb-as-default-driver.patch
55 0006-Disable-version-check.patch
66 0007-Ignore-BLZ_UNGUELTIG-due-to-old-BLZ.txt-in-obantoo.patch
7 0008-Add-fastqrcodegen-lib-till-1010618-is-resolved.patch