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