15317bbafSopenharmony_ci/* 25317bbafSopenharmony_ci * Fast QR Code generator library 35317bbafSopenharmony_ci * 45317bbafSopenharmony_ci * Copyright (c) Project Nayuki. (MIT License) 55317bbafSopenharmony_ci * https://www.nayuki.io/page/fast-qr-code-generator-library 65317bbafSopenharmony_ci * 75317bbafSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy of 85317bbafSopenharmony_ci * this software and associated documentation files (the "Software"), to deal in 95317bbafSopenharmony_ci * the Software without restriction, including without limitation the rights to 105317bbafSopenharmony_ci * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 115317bbafSopenharmony_ci * the Software, and to permit persons to whom the Software is furnished to do so, 125317bbafSopenharmony_ci * subject to the following conditions: 135317bbafSopenharmony_ci * - The above copyright notice and this permission notice shall be included in 145317bbafSopenharmony_ci * all copies or substantial portions of the Software. 155317bbafSopenharmony_ci * - The Software is provided "as is", without warranty of any kind, express or 165317bbafSopenharmony_ci * implied, including but not limited to the warranties of merchantability, 175317bbafSopenharmony_ci * fitness for a particular purpose and noninfringement. In no event shall the 185317bbafSopenharmony_ci * authors or copyright holders be liable for any claim, damages or other 195317bbafSopenharmony_ci * liability, whether in an action of contract, tort or otherwise, arising from, 205317bbafSopenharmony_ci * out of or in connection with the Software or the use or other dealings in the 215317bbafSopenharmony_ci * Software. 225317bbafSopenharmony_ci */ 235317bbafSopenharmony_ci 245317bbafSopenharmony_cipackage io.nayuki.fastqrcodegen; 255317bbafSopenharmony_ci 265317bbafSopenharmony_ci 275317bbafSopenharmony_ci// Stores the parts of a QR Code that depend only on the version number, 285317bbafSopenharmony_ci// and does not depend on the data or error correction level or mask. 295317bbafSopenharmony_cifinal class QrTemplate { 305317bbafSopenharmony_ci 315317bbafSopenharmony_ci // Use this memoizer to get instances of this class. 325317bbafSopenharmony_ci public static final Memoizer<Integer,QrTemplate> MEMOIZER 335317bbafSopenharmony_ci = new Memoizer<>(QrTemplate::new); 345317bbafSopenharmony_ci 355317bbafSopenharmony_ci 365317bbafSopenharmony_ci private final int version; // In the range [1, 40]. 375317bbafSopenharmony_ci private final int size; // Derived from version. 385317bbafSopenharmony_ci 395317bbafSopenharmony_ci final int[] template; // Length and values depend on version. 405317bbafSopenharmony_ci final int[][] masks; // masks.length == 8, and masks[i].length == template.length. 415317bbafSopenharmony_ci final int[] dataOutputBitIndexes; // Length and values depend on version. 425317bbafSopenharmony_ci 435317bbafSopenharmony_ci // Indicates function modules that are not subjected to masking. Discarded when constructor finishes. 445317bbafSopenharmony_ci // Otherwise when the constructor is running, isFunction.length == template.length. 455317bbafSopenharmony_ci private int[] isFunction; 465317bbafSopenharmony_ci 475317bbafSopenharmony_ci 485317bbafSopenharmony_ci // Creates a QR Code template for the given version number. 495317bbafSopenharmony_ci private QrTemplate(int ver) { 505317bbafSopenharmony_ci if (ver < QrCode.MIN_VERSION || ver > QrCode.MAX_VERSION) 515317bbafSopenharmony_ci throw new IllegalArgumentException("Version out of range"); 525317bbafSopenharmony_ci version = ver; 535317bbafSopenharmony_ci size = version * 4 + 17; 545317bbafSopenharmony_ci template = new int[(size * size + 31) / 32]; 555317bbafSopenharmony_ci isFunction = new int[template.length]; 565317bbafSopenharmony_ci 575317bbafSopenharmony_ci drawFunctionPatterns(); // Reads and writes fields 585317bbafSopenharmony_ci masks = generateMasks(); // Reads fields, returns array 595317bbafSopenharmony_ci dataOutputBitIndexes = generateZigzagScan(); // Reads fields, returns array 605317bbafSopenharmony_ci isFunction = null; 615317bbafSopenharmony_ci } 625317bbafSopenharmony_ci 635317bbafSopenharmony_ci 645317bbafSopenharmony_ci // Reads this object's version field, and draws and marks all function modules. 655317bbafSopenharmony_ci private void drawFunctionPatterns() { 665317bbafSopenharmony_ci // Draw horizontal and vertical timing patterns 675317bbafSopenharmony_ci for (int i = 0; i < size; i++) { 685317bbafSopenharmony_ci darkenFunctionModule(6, i, ~i & 1); 695317bbafSopenharmony_ci darkenFunctionModule(i, 6, ~i & 1); 705317bbafSopenharmony_ci } 715317bbafSopenharmony_ci 725317bbafSopenharmony_ci // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules) 735317bbafSopenharmony_ci drawFinderPattern(3, 3); 745317bbafSopenharmony_ci drawFinderPattern(size - 4, 3); 755317bbafSopenharmony_ci drawFinderPattern(3, size - 4); 765317bbafSopenharmony_ci 775317bbafSopenharmony_ci // Draw numerous alignment patterns 785317bbafSopenharmony_ci int[] alignPatPos = getAlignmentPatternPositions(); 795317bbafSopenharmony_ci int numAlign = alignPatPos.length; 805317bbafSopenharmony_ci for (int i = 0; i < numAlign; i++) { 815317bbafSopenharmony_ci for (int j = 0; j < numAlign; j++) { 825317bbafSopenharmony_ci // Don't draw on the three finder corners 835317bbafSopenharmony_ci if (!(i == 0 && j == 0 || i == 0 && j == numAlign - 1 || i == numAlign - 1 && j == 0)) 845317bbafSopenharmony_ci drawAlignmentPattern(alignPatPos[i], alignPatPos[j]); 855317bbafSopenharmony_ci } 865317bbafSopenharmony_ci } 875317bbafSopenharmony_ci 885317bbafSopenharmony_ci // Draw configuration data 895317bbafSopenharmony_ci drawDummyFormatBits(); 905317bbafSopenharmony_ci drawVersion(); 915317bbafSopenharmony_ci } 925317bbafSopenharmony_ci 935317bbafSopenharmony_ci 945317bbafSopenharmony_ci // Draws two blank copies of the format bits. 955317bbafSopenharmony_ci private void drawDummyFormatBits() { 965317bbafSopenharmony_ci // Draw first copy 975317bbafSopenharmony_ci for (int i = 0; i <= 5; i++) 985317bbafSopenharmony_ci darkenFunctionModule(8, i, 0); 995317bbafSopenharmony_ci darkenFunctionModule(8, 7, 0); 1005317bbafSopenharmony_ci darkenFunctionModule(8, 8, 0); 1015317bbafSopenharmony_ci darkenFunctionModule(7, 8, 0); 1025317bbafSopenharmony_ci for (int i = 9; i < 15; i++) 1035317bbafSopenharmony_ci darkenFunctionModule(14 - i, 8, 0); 1045317bbafSopenharmony_ci 1055317bbafSopenharmony_ci // Draw second copy 1065317bbafSopenharmony_ci for (int i = 0; i < 8; i++) 1075317bbafSopenharmony_ci darkenFunctionModule(size - 1 - i, 8, 0); 1085317bbafSopenharmony_ci for (int i = 8; i < 15; i++) 1095317bbafSopenharmony_ci darkenFunctionModule(8, size - 15 + i, 0); 1105317bbafSopenharmony_ci darkenFunctionModule(8, size - 8, 1); // Always dark 1115317bbafSopenharmony_ci } 1125317bbafSopenharmony_ci 1135317bbafSopenharmony_ci 1145317bbafSopenharmony_ci // Draws two copies of the version bits (with its own error correction code), 1155317bbafSopenharmony_ci // based on this object's version field, iff 7 <= version <= 40. 1165317bbafSopenharmony_ci private void drawVersion() { 1175317bbafSopenharmony_ci if (version < 7) 1185317bbafSopenharmony_ci return; 1195317bbafSopenharmony_ci 1205317bbafSopenharmony_ci // Calculate error correction code and pack bits 1215317bbafSopenharmony_ci int rem = version; // version is uint6, in the range [7, 40] 1225317bbafSopenharmony_ci for (int i = 0; i < 12; i++) 1235317bbafSopenharmony_ci rem = (rem << 1) ^ ((rem >>> 11) * 0x1F25); 1245317bbafSopenharmony_ci int bits = version << 12 | rem; // uint18 1255317bbafSopenharmony_ci assert bits >>> 18 == 0; 1265317bbafSopenharmony_ci 1275317bbafSopenharmony_ci // Draw two copies 1285317bbafSopenharmony_ci for (int i = 0; i < 18; i++) { 1295317bbafSopenharmony_ci int bit = QrCode.getBit(bits, i); 1305317bbafSopenharmony_ci int a = size - 11 + i % 3; 1315317bbafSopenharmony_ci int b = i / 3; 1325317bbafSopenharmony_ci darkenFunctionModule(a, b, bit); 1335317bbafSopenharmony_ci darkenFunctionModule(b, a, bit); 1345317bbafSopenharmony_ci } 1355317bbafSopenharmony_ci } 1365317bbafSopenharmony_ci 1375317bbafSopenharmony_ci 1385317bbafSopenharmony_ci // Draws a 9*9 finder pattern including the border separator, 1395317bbafSopenharmony_ci // with the center module at (x, y). Modules can be out of bounds. 1405317bbafSopenharmony_ci private void drawFinderPattern(int x, int y) { 1415317bbafSopenharmony_ci for (int dy = -4; dy <= 4; dy++) { 1425317bbafSopenharmony_ci for (int dx = -4; dx <= 4; dx++) { 1435317bbafSopenharmony_ci int dist = Math.max(Math.abs(dx), Math.abs(dy)); // Chebyshev/infinity norm 1445317bbafSopenharmony_ci int xx = x + dx, yy = y + dy; 1455317bbafSopenharmony_ci if (0 <= xx && xx < size && 0 <= yy && yy < size) 1465317bbafSopenharmony_ci darkenFunctionModule(xx, yy, (dist != 2 && dist != 4) ? 1 : 0); 1475317bbafSopenharmony_ci } 1485317bbafSopenharmony_ci } 1495317bbafSopenharmony_ci } 1505317bbafSopenharmony_ci 1515317bbafSopenharmony_ci 1525317bbafSopenharmony_ci // Draws a 5*5 alignment pattern, with the center module 1535317bbafSopenharmony_ci // at (x, y). All modules must be in bounds. 1545317bbafSopenharmony_ci private void drawAlignmentPattern(int x, int y) { 1555317bbafSopenharmony_ci for (int dy = -2; dy <= 2; dy++) { 1565317bbafSopenharmony_ci for (int dx = -2; dx <= 2; dx++) 1575317bbafSopenharmony_ci darkenFunctionModule(x + dx, y + dy, Math.abs(Math.max(Math.abs(dx), Math.abs(dy)) - 1)); 1585317bbafSopenharmony_ci } 1595317bbafSopenharmony_ci } 1605317bbafSopenharmony_ci 1615317bbafSopenharmony_ci 1625317bbafSopenharmony_ci // Computes and returns a new array of masks, based on this object's various fields. 1635317bbafSopenharmony_ci private int[][] generateMasks() { 1645317bbafSopenharmony_ci int[][] result = new int[8][template.length]; 1655317bbafSopenharmony_ci for (int mask = 0; mask < result.length; mask++) { 1665317bbafSopenharmony_ci int[] maskModules = result[mask]; 1675317bbafSopenharmony_ci for (int y = 0, i = 0; y < size; y++) { 1685317bbafSopenharmony_ci for (int x = 0; x < size; x++, i++) { 1695317bbafSopenharmony_ci boolean invert; 1705317bbafSopenharmony_ci switch (mask) { 1715317bbafSopenharmony_ci case 0: invert = (x + y) % 2 == 0; break; 1725317bbafSopenharmony_ci case 1: invert = y % 2 == 0; break; 1735317bbafSopenharmony_ci case 2: invert = x % 3 == 0; break; 1745317bbafSopenharmony_ci case 3: invert = (x + y) % 3 == 0; break; 1755317bbafSopenharmony_ci case 4: invert = (x / 3 + y / 2) % 2 == 0; break; 1765317bbafSopenharmony_ci case 5: invert = x * y % 2 + x * y % 3 == 0; break; 1775317bbafSopenharmony_ci case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break; 1785317bbafSopenharmony_ci case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break; 1795317bbafSopenharmony_ci default: throw new AssertionError(); 1805317bbafSopenharmony_ci } 1815317bbafSopenharmony_ci int bit = (invert ? 1 : 0) & ~getModule(isFunction, x, y); 1825317bbafSopenharmony_ci maskModules[i >>> 5] |= bit << i; 1835317bbafSopenharmony_ci } 1845317bbafSopenharmony_ci } 1855317bbafSopenharmony_ci } 1865317bbafSopenharmony_ci return result; 1875317bbafSopenharmony_ci } 1885317bbafSopenharmony_ci 1895317bbafSopenharmony_ci 1905317bbafSopenharmony_ci // Computes and returns an array of bit indexes, based on this object's various fields. 1915317bbafSopenharmony_ci private int[] generateZigzagScan() { 1925317bbafSopenharmony_ci int[] result = new int[getNumRawDataModules(version) / 8 * 8]; 1935317bbafSopenharmony_ci int i = 0; // Bit index into the data 1945317bbafSopenharmony_ci for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair 1955317bbafSopenharmony_ci if (right == 6) 1965317bbafSopenharmony_ci right = 5; 1975317bbafSopenharmony_ci for (int vert = 0; vert < size; vert++) { // Vertical counter 1985317bbafSopenharmony_ci for (int j = 0; j < 2; j++) { 1995317bbafSopenharmony_ci int x = right - j; // Actual x coordinate 2005317bbafSopenharmony_ci boolean upward = ((right + 1) & 2) == 0; 2015317bbafSopenharmony_ci int y = upward ? size - 1 - vert : vert; // Actual y coordinate 2025317bbafSopenharmony_ci if (getModule(isFunction, x, y) == 0 && i < result.length) { 2035317bbafSopenharmony_ci result[i] = y * size + x; 2045317bbafSopenharmony_ci i++; 2055317bbafSopenharmony_ci } 2065317bbafSopenharmony_ci } 2075317bbafSopenharmony_ci } 2085317bbafSopenharmony_ci } 2095317bbafSopenharmony_ci assert i == result.length; 2105317bbafSopenharmony_ci return result; 2115317bbafSopenharmony_ci } 2125317bbafSopenharmony_ci 2135317bbafSopenharmony_ci 2145317bbafSopenharmony_ci // Returns the value of the bit at the given coordinates in the given grid. 2155317bbafSopenharmony_ci private int getModule(int[] grid, int x, int y) { 2165317bbafSopenharmony_ci assert 0 <= x && x < size; 2175317bbafSopenharmony_ci assert 0 <= y && y < size; 2185317bbafSopenharmony_ci int i = y * size + x; 2195317bbafSopenharmony_ci return QrCode.getBit(grid[i >>> 5], i); 2205317bbafSopenharmony_ci } 2215317bbafSopenharmony_ci 2225317bbafSopenharmony_ci 2235317bbafSopenharmony_ci // Marks the module at the given coordinates as a function module. 2245317bbafSopenharmony_ci // Also either sets that module dark or keeps its color unchanged. 2255317bbafSopenharmony_ci private void darkenFunctionModule(int x, int y, int enable) { 2265317bbafSopenharmony_ci assert 0 <= x && x < size; 2275317bbafSopenharmony_ci assert 0 <= y && y < size; 2285317bbafSopenharmony_ci assert enable == 0 || enable == 1; 2295317bbafSopenharmony_ci int i = y * size + x; 2305317bbafSopenharmony_ci template[i >>> 5] |= enable << i; 2315317bbafSopenharmony_ci isFunction[i >>> 5] |= 1 << i; 2325317bbafSopenharmony_ci } 2335317bbafSopenharmony_ci 2345317bbafSopenharmony_ci 2355317bbafSopenharmony_ci // Returns an ascending list of positions of alignment patterns for this version number. 2365317bbafSopenharmony_ci // Each position is in the range [0,177), and are used on both the x and y axes. 2375317bbafSopenharmony_ci // This could be implemented as lookup table of 40 variable-length lists of unsigned bytes. 2385317bbafSopenharmony_ci private int[] getAlignmentPatternPositions() { 2395317bbafSopenharmony_ci if (version == 1) 2405317bbafSopenharmony_ci return new int[]{}; 2415317bbafSopenharmony_ci else { 2425317bbafSopenharmony_ci int numAlign = version / 7 + 2; 2435317bbafSopenharmony_ci int step = (version == 32) ? 26 : 2445317bbafSopenharmony_ci (version * 4 + numAlign * 2 + 1) / (numAlign * 2 - 2) * 2; 2455317bbafSopenharmony_ci int[] result = new int[numAlign]; 2465317bbafSopenharmony_ci result[0] = 6; 2475317bbafSopenharmony_ci for (int i = result.length - 1, pos = size - 7; i >= 1; i--, pos -= step) 2485317bbafSopenharmony_ci result[i] = pos; 2495317bbafSopenharmony_ci return result; 2505317bbafSopenharmony_ci } 2515317bbafSopenharmony_ci } 2525317bbafSopenharmony_ci 2535317bbafSopenharmony_ci 2545317bbafSopenharmony_ci // Returns the number of data bits that can be stored in a QR Code of the given version number, after 2555317bbafSopenharmony_ci // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. 2565317bbafSopenharmony_ci // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. 2575317bbafSopenharmony_ci static int getNumRawDataModules(int ver) { 2585317bbafSopenharmony_ci if (ver < QrCode.MIN_VERSION || ver > QrCode.MAX_VERSION) 2595317bbafSopenharmony_ci throw new IllegalArgumentException("Version number out of range"); 2605317bbafSopenharmony_ci int result = (16 * ver + 128) * ver + 64; 2615317bbafSopenharmony_ci if (ver >= 2) { 2625317bbafSopenharmony_ci int numAlign = ver / 7 + 2; 2635317bbafSopenharmony_ci result -= (25 * numAlign - 10) * numAlign - 55; 2645317bbafSopenharmony_ci if (ver >= 7) 2655317bbafSopenharmony_ci result -= 36; 2665317bbafSopenharmony_ci } 2675317bbafSopenharmony_ci return result; 2685317bbafSopenharmony_ci } 2695317bbafSopenharmony_ci 2705317bbafSopenharmony_ci} 271