1 /* 2 * Fast QR Code generator library 3 * 4 * Copyright (c) Project Nayuki. (MIT License) 5 * https://www.nayuki.io/page/fast-qr-code-generator-library 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy of 8 * this software and associated documentation files (the "Software"), to deal in 9 * the Software without restriction, including without limitation the rights to 10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 * the Software, and to permit persons to whom the Software is furnished to do so, 12 * subject to the following conditions: 13 * - The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * - The Software is provided "as is", without warranty of any kind, express or 16 * implied, including but not limited to the warranties of merchantability, 17 * fitness for a particular purpose and noninfringement. In no event shall the 18 * authors or copyright holders be liable for any claim, damages or other 19 * liability, whether in an action of contract, tort or otherwise, arising from, 20 * out of or in connection with the Software or the use or other dealings in the 21 * Software. 22 */ 23 24 package io.nayuki.fastqrcodegen; 25 26 import java.util.Arrays; 27 import java.util.List; 28 import java.util.Objects; 29 30 31 /** 32 * A QR Code symbol, which is a type of two-dimension barcode. 33 * Invented by Denso Wave and described in the ISO/IEC 18004 standard. 34 * <p>Instances of this class represent an immutable square grid of dark and light cells. 35 * The class provides static factory functions to create a QR Code from text or binary data. 36 * The class covers the QR Code Model 2 specification, supporting all versions (sizes) 37 * from 1 to 40, all 4 error correction levels, and 4 character encoding modes.</p> 38 * <p>Ways to create a QR Code object:</p> 39 * <ul> 40 * <li><p>High level: Take the payload data and call {@link QrCode#encodeText(String,Ecc)} 41 * or {@link QrCode#encodeBinary(byte[],Ecc)}.</p></li> 42 * <li><p>Mid level: Custom-make the list of {@link QrSegment segments} 43 * and call {@link QrCode#encodeSegments(List,Ecc)} or 44 * {@link QrCode#encodeSegments(List,Ecc,int,int,int,boolean)}</p></li> 45 * <li><p>Low level: Custom-make the array of data codeword bytes (including segment headers and 46 * final padding, excluding error correction codewords), supply the appropriate version number, 47 * and call the {@link QrCode#QrCode(int,Ecc,byte[],int) constructor}.</p></li> 48 * </ul> 49 * <p>(Note that all ways require supplying the desired error correction level.)</p> 50 * @see QrSegment 51 */ 52 public final class QrCode { 53 54 /*---- Static factory functions (high level) ----*/ 55 56 /** 57 * Returns a QR Code representing the specified Unicode text string at the specified error correction level. 58 * As a conservative upper bound, this function is guaranteed to succeed for strings that have 738 or fewer 59 * Unicode code points (not UTF-16 code units) if the low error correction level is used. The smallest possible 60 * QR Code version is automatically chosen for the output. The ECC level of the result may be higher than the 61 * ecl argument if it can be done without increasing the version. 62 * @param text the text to be encoded (not {@code null}), which can be any Unicode string 63 * @param ecl the error correction level to use (not {@code null}) (boostable) 64 * @return a QR Code (not {@code null}) representing the text 65 * @throws NullPointerException if the text or error correction level is {@code null} 66 * @throws DataTooLongException if the text fails to fit in the 67 * largest version QR Code at the ECL, which means it is too long 68 */ encodeText(String text, Ecc ecl)69 public static QrCode encodeText(String text, Ecc ecl) { 70 Objects.requireNonNull(text); 71 Objects.requireNonNull(ecl); 72 List<QrSegment> segs = QrSegment.makeSegments(text); 73 return encodeSegments(segs, ecl); 74 } 75 76 77 /** 78 * Returns a QR Code representing the specified binary data at the specified error correction level. 79 * This function always encodes using the binary segment mode, not any text mode. The maximum number of 80 * bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output. 81 * The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version. 82 * @param data the binary data to encode (not {@code null}) 83 * @param ecl the error correction level to use (not {@code null}) (boostable) 84 * @return a QR Code (not {@code null}) representing the data 85 * @throws NullPointerException if the data or error correction level is {@code null} 86 * @throws DataTooLongException if the data fails to fit in the 87 * largest version QR Code at the ECL, which means it is too long 88 */ encodeBinary(byte[] data, Ecc ecl)89 public static QrCode encodeBinary(byte[] data, Ecc ecl) { 90 Objects.requireNonNull(data); 91 Objects.requireNonNull(ecl); 92 QrSegment seg = QrSegment.makeBytes(data); 93 return encodeSegments(Arrays.asList(seg), ecl); 94 } 95 96 97 /*---- Static factory functions (mid level) ----*/ 98 99 /** 100 * Returns a QR Code representing the specified segments at the specified error correction 101 * level. The smallest possible QR Code version is automatically chosen for the output. The ECC level 102 * of the result may be higher than the ecl argument if it can be done without increasing the version. 103 * <p>This function allows the user to create a custom sequence of segments that switches 104 * between modes (such as alphanumeric and byte) to encode text in less space. 105 * This is a mid-level API; the high-level API is {@link #encodeText(String,Ecc)} 106 * and {@link #encodeBinary(byte[],Ecc)}.</p> 107 * @param segs the segments to encode 108 * @param ecl the error correction level to use (not {@code null}) (boostable) 109 * @return a QR Code (not {@code null}) representing the segments 110 * @throws NullPointerException if the list of segments, any segment, or the error correction level is {@code null} 111 * @throws DataTooLongException if the segments fail to fit in the 112 * largest version QR Code at the ECL, which means they are too long 113 */ encodeSegments(List<QrSegment> segs, Ecc ecl)114 public static QrCode encodeSegments(List<QrSegment> segs, Ecc ecl) { 115 return encodeSegments(segs, ecl, MIN_VERSION, MAX_VERSION, -1, true); 116 } 117 118 119 /** 120 * Returns a QR Code representing the specified segments with the specified encoding parameters. 121 * The smallest possible QR Code version within the specified range is automatically 122 * chosen for the output. Iff boostEcl is {@code true}, then the ECC level of the 123 * result may be higher than the ecl argument if it can be done without increasing 124 * the version. The mask number is either between 0 to 7 (inclusive) to force that 125 * mask, or −1 to automatically choose an appropriate mask (which may be slow). 126 * <p>This function allows the user to create a custom sequence of segments that switches 127 * between modes (such as alphanumeric and byte) to encode text in less space. 128 * This is a mid-level API; the high-level API is {@link #encodeText(String,Ecc)} 129 * and {@link #encodeBinary(byte[],Ecc)}.</p> 130 * @param segs the segments to encode 131 * @param ecl the error correction level to use (not {@code null}) (boostable) 132 * @param minVersion the minimum allowed version of the QR Code (at least 1) 133 * @param maxVersion the maximum allowed version of the QR Code (at most 40) 134 * @param mask the mask number to use (between 0 and 7 (inclusive)), or −1 for automatic mask 135 * @param boostEcl increases the ECC level as long as it doesn't increase the version number 136 * @return a QR Code (not {@code null}) representing the segments 137 * @throws NullPointerException if the list of segments, any segment, or the error correction level is {@code null} 138 * @throws IllegalArgumentException if 1 ≤ minVersion ≤ maxVersion ≤ 40 139 * or −1 ≤ mask ≤ 7 is violated 140 * @throws DataTooLongException if the segments fail to fit in 141 * the maxVersion QR Code at the ECL, which means they are too long 142 */ encodeSegments(List<QrSegment> segs, Ecc ecl, int minVersion, int maxVersion, int mask, boolean boostEcl)143 public static QrCode encodeSegments(List<QrSegment> segs, Ecc ecl, int minVersion, int maxVersion, int mask, boolean boostEcl) { 144 Objects.requireNonNull(segs); 145 Objects.requireNonNull(ecl); 146 if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7) 147 throw new IllegalArgumentException("Invalid value"); 148 149 // Find the minimal version number to use 150 int version, dataUsedBits; 151 for (version = minVersion; ; version++) { 152 int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available 153 dataUsedBits = QrSegment.getTotalBits(segs, version); 154 if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits) 155 break; // This version number is found to be suitable 156 if (version >= maxVersion) { // All versions in the range could not fit the given data 157 String msg = "Segment too long"; 158 if (dataUsedBits != -1) 159 msg = String.format("Data length = %d bits, Max capacity = %d bits", dataUsedBits, dataCapacityBits); 160 throw new DataTooLongException(msg); 161 } 162 } 163 assert dataUsedBits != -1; 164 165 // Increase the error correction level while the data still fits in the current version number 166 for (Ecc newEcl : Ecc.values()) { // From low to high 167 if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8) 168 ecl = newEcl; 169 } 170 171 // Concatenate all segments to create the data bit string 172 BitBuffer bb = new BitBuffer(); 173 for (QrSegment seg : segs) { 174 bb.appendBits(seg.mode.modeBits, 4); 175 bb.appendBits(seg.numChars, seg.mode.numCharCountBits(version)); 176 bb.appendBits(seg.data, seg.bitLength); 177 } 178 assert bb.bitLength == dataUsedBits; 179 180 // Add terminator and pad up to a byte if applicable 181 int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; 182 assert bb.bitLength <= dataCapacityBits; 183 bb.appendBits(0, Math.min(4, dataCapacityBits - bb.bitLength)); 184 bb.appendBits(0, (8 - bb.bitLength % 8) % 8); 185 assert bb.bitLength % 8 == 0; 186 187 // Pad with alternating bytes until data capacity is reached 188 for (int padByte = 0xEC; bb.bitLength < dataCapacityBits; padByte ^= 0xEC ^ 0x11) 189 bb.appendBits(padByte, 8); 190 191 // Create the QR Code object 192 return new QrCode(version, ecl, bb.getBytes(), mask); 193 } 194 195 196 197 /*---- Instance fields ----*/ 198 199 // Public immutable scalar parameters: 200 201 /** The version number of this QR Code, which is between 1 and 40 (inclusive). 202 * This determines the size of this barcode. */ 203 public final int version; 204 205 /** The width and height of this QR Code, measured in modules, between 206 * 21 and 177 (inclusive). This is equal to version × 4 + 17. */ 207 public final int size; 208 209 /** The error correction level used in this QR Code, which is not {@code null}. */ 210 public final Ecc errorCorrectionLevel; 211 212 /** The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive). 213 * <p>Even if a QR Code is created with automatic masking requested (mask = 214 * −1), the resulting object still has a mask value between 0 and 7. */ 215 public final int mask; 216 217 // Private grid of modules of this QR Code, packed tightly into bits. 218 // Immutable after constructor finishes. Accessed through getModule(). 219 private final int[] modules; 220 221 222 223 /*---- Constructor (low level) ----*/ 224 225 /** 226 * Constructs a QR Code with the specified version number, 227 * error correction level, data codeword bytes, and mask number. 228 * <p>This is a low-level API that most users should not use directly. A mid-level 229 * API is the {@link #encodeSegments(List,Ecc,int,int,int,boolean)} function.</p> 230 * @param ver the version number to use, which must be in the range 1 to 40 (inclusive) 231 * @param ecl the error correction level to use 232 * @param dataCodewords the bytes representing segments to encode (without ECC) 233 * @param msk the mask pattern to use, which is either −1 for automatic choice or from 0 to 7 for fixed choice 234 * @throws NullPointerException if the byte array or error correction level is {@code null} 235 * @throws IllegalArgumentException if the version or mask value is out of range, 236 * or if the data is the wrong length for the specified version and error correction level 237 */ QrCode(int ver, Ecc ecl, byte[] dataCodewords, int msk)238 public QrCode(int ver, Ecc ecl, byte[] dataCodewords, int msk) { 239 // Check arguments and initialize fields 240 if (ver < MIN_VERSION || ver > MAX_VERSION) 241 throw new IllegalArgumentException("Version value out of range"); 242 if (msk < -1 || msk > 7) 243 throw new IllegalArgumentException("Mask value out of range"); 244 version = ver; 245 size = ver * 4 + 17; 246 errorCorrectionLevel = Objects.requireNonNull(ecl); 247 Objects.requireNonNull(dataCodewords); 248 249 QrTemplate tpl = QrTemplate.MEMOIZER.get(ver); 250 modules = tpl.template.clone(); 251 252 // Compute ECC, draw modules, do masking 253 byte[] allCodewords = addEccAndInterleave(dataCodewords); 254 drawCodewords(tpl.dataOutputBitIndexes, allCodewords); 255 mask = handleConstructorMasking(tpl.masks, msk); 256 } 257 258 259 260 /*---- Public instance methods ----*/ 261 262 /** 263 * Returns the color of the module (pixel) at the specified coordinates, which is {@code false} 264 * for light or {@code true} for dark. The top left corner has the coordinates (x=0, y=0). 265 * If the specified coordinates are out of bounds, then {@code false} (light) is returned. 266 * @param x the x coordinate, where 0 is the left edge and size−1 is the right edge 267 * @param y the y coordinate, where 0 is the top edge and size−1 is the bottom edge 268 * @return {@code true} if the coordinates are in bounds and the module 269 * at that location is dark, or {@code false} (light) otherwise 270 */ getModule(int x, int y)271 public boolean getModule(int x, int y) { 272 if (0 <= x && x < size && 0 <= y && y < size) { 273 int i = y * size + x; 274 return getBit(modules[i >>> 5], i) != 0; 275 } else 276 return false; 277 } 278 279 280 281 /*---- Private helper methods for constructor: Drawing function modules ----*/ 282 283 // Draws two copies of the format bits (with its own error correction code) 284 // based on the given mask and this object's error correction level field. drawFormatBits(int msk)285 private void drawFormatBits(int msk) { 286 // Calculate error correction code and pack bits 287 int data = errorCorrectionLevel.formatBits << 3 | msk; // errCorrLvl is uint2, mask is uint3 288 int rem = data; 289 for (int i = 0; i < 10; i++) 290 rem = (rem << 1) ^ ((rem >>> 9) * 0x537); 291 int bits = (data << 10 | rem) ^ 0x5412; // uint15 292 assert bits >>> 15 == 0; 293 294 // Draw first copy 295 for (int i = 0; i <= 5; i++) 296 setModule(8, i, getBit(bits, i)); 297 setModule(8, 7, getBit(bits, 6)); 298 setModule(8, 8, getBit(bits, 7)); 299 setModule(7, 8, getBit(bits, 8)); 300 for (int i = 9; i < 15; i++) 301 setModule(14 - i, 8, getBit(bits, i)); 302 303 // Draw second copy 304 for (int i = 0; i < 8; i++) 305 setModule(size - 1 - i, 8, getBit(bits, i)); 306 for (int i = 8; i < 15; i++) 307 setModule(8, size - 15 + i, getBit(bits, i)); 308 setModule(8, size - 8, 1); // Always dark 309 } 310 311 312 // Sets the module at the given coordinates to the given color. 313 // Only used by the constructor. Coordinates must be in bounds. setModule(int x, int y, int dark)314 private void setModule(int x, int y, int dark) { 315 assert 0 <= x && x < size; 316 assert 0 <= y && y < size; 317 assert dark == 0 || dark == 1; 318 int i = y * size + x; 319 modules[i >>> 5] &= ~(1 << i); 320 modules[i >>> 5] |= dark << i; 321 } 322 323 324 /*---- Private helper methods for constructor: Codewords and masking ----*/ 325 326 // Returns a new byte string representing the given data with the appropriate error correction 327 // codewords appended to it, based on this object's version and error correction level. addEccAndInterleave(byte[] data)328 private byte[] addEccAndInterleave(byte[] data) { 329 Objects.requireNonNull(data); 330 if (data.length != getNumDataCodewords(version, errorCorrectionLevel)) 331 throw new IllegalArgumentException(); 332 333 // Calculate parameter numbers 334 int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[errorCorrectionLevel.ordinal()][version]; 335 int blockEccLen = ECC_CODEWORDS_PER_BLOCK [errorCorrectionLevel.ordinal()][version]; 336 int rawCodewords = QrTemplate.getNumRawDataModules(version) / 8; 337 int numShortBlocks = numBlocks - rawCodewords % numBlocks; 338 int shortBlockDataLen = rawCodewords / numBlocks - blockEccLen; 339 340 // Split data into blocks, calculate ECC, and interleave 341 // (not concatenate) the bytes into a single sequence 342 byte[] result = new byte[rawCodewords]; 343 ReedSolomonGenerator rs = ReedSolomonGenerator.MEMOIZER.get(blockEccLen); 344 byte[] ecc = new byte[blockEccLen]; // Temporary storage per iteration 345 for (int i = 0, k = 0; i < numBlocks; i++) { 346 int datLen = shortBlockDataLen + (i < numShortBlocks ? 0 : 1); 347 rs.getRemainder(data, k, datLen, ecc); 348 for (int j = 0, l = i; j < datLen; j++, k++, l += numBlocks) { // Copy data 349 if (j == shortBlockDataLen) 350 l -= numShortBlocks; 351 result[l] = data[k]; 352 } 353 for (int j = 0, l = data.length + i; j < blockEccLen; j++, l += numBlocks) // Copy ECC 354 result[l] = ecc[j]; 355 } 356 return result; 357 } 358 359 360 // Draws the given sequence of 8-bit codewords (data and error correction) 361 // onto the entire data area of this QR Code, based on the given bit indexes. drawCodewords(int[] dataOutputBitIndexes, byte[] allCodewords)362 private void drawCodewords(int[] dataOutputBitIndexes, byte[] allCodewords) { 363 Objects.requireNonNull(dataOutputBitIndexes); 364 Objects.requireNonNull(allCodewords); 365 if (allCodewords.length * 8 != dataOutputBitIndexes.length) 366 throw new IllegalArgumentException(); 367 for (int i = 0; i < dataOutputBitIndexes.length; i++) { 368 int j = dataOutputBitIndexes[i]; 369 int bit = getBit(allCodewords[i >>> 3], ~i & 7); 370 modules[j >>> 5] |= bit << j; 371 } 372 } 373 374 375 // XORs the codeword modules in this QR Code with the given mask pattern. 376 // The function modules must be marked and the codeword bits must be drawn 377 // before masking. Due to the arithmetic of XOR, calling applyMask() with 378 // the same mask value a second time will undo the mask. A final well-formed 379 // QR Code needs exactly one (not zero, two, etc.) mask applied. applyMask(int[] msk)380 private void applyMask(int[] msk) { 381 if (msk.length != modules.length) 382 throw new IllegalArgumentException(); 383 for (int i = 0; i < msk.length; i++) 384 modules[i] ^= msk[i]; 385 } 386 387 388 // A messy helper function for the constructor. This QR Code must be in an unmasked state when this 389 // method is called. The 'mask' argument is the requested mask, which is -1 for auto or 0 to 7 for fixed. 390 // This method applies and returns the actual mask chosen, from 0 to 7. handleConstructorMasking(int[][] masks, int msk)391 private int handleConstructorMasking(int[][] masks, int msk) { 392 if (msk == -1) { // Automatically choose best mask 393 int minPenalty = Integer.MAX_VALUE; 394 for (int i = 0; i < 8; i++) { 395 applyMask(masks[i]); 396 drawFormatBits(i); 397 int penalty = getPenaltyScore(); 398 if (penalty < minPenalty) { 399 msk = i; 400 minPenalty = penalty; 401 } 402 applyMask(masks[i]); // Undoes the mask due to XOR 403 } 404 } 405 assert 0 <= msk && msk <= 7; 406 applyMask(masks[msk]); // Apply the final choice of mask 407 drawFormatBits(msk); // Overwrite old format bits 408 return msk; // The caller shall assign this value to the final-declared field 409 } 410 411 412 // Calculates and returns the penalty score based on state of this QR Code's current modules. 413 // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score. getPenaltyScore()414 private int getPenaltyScore() { 415 int result = 0; 416 int dark = 0; 417 int[] runHistory = new int[7]; 418 419 // Iterate over adjacent pairs of rows 420 for (int index = 0, downIndex = size, end = size * size; index < end; ) { 421 int runColor = 0; 422 int runX = 0; 423 Arrays.fill(runHistory, 0); 424 int curRow = 0; 425 int nextRow = 0; 426 for (int x = 0; x < size; x++, index++, downIndex++) { 427 int c = getBit(modules[index >>> 5], index); 428 if (c == runColor) { 429 runX++; 430 if (runX == 5) 431 result += PENALTY_N1; 432 else if (runX > 5) 433 result++; 434 } else { 435 finderPenaltyAddHistory(runX, runHistory); 436 if (runColor == 0) 437 result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; 438 runColor = c; 439 runX = 1; 440 } 441 dark += c; 442 if (downIndex < end) { 443 curRow = ((curRow << 1) | c) & 3; 444 nextRow = ((nextRow << 1) | getBit(modules[downIndex >>> 5], downIndex)) & 3; 445 // 2*2 blocks of modules having same color 446 if (x >= 1 && (curRow == 0 || curRow == 3) && curRow == nextRow) 447 result += PENALTY_N2; 448 } 449 } 450 result += finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3; 451 } 452 453 // Iterate over single columns 454 for (int x = 0; x < size; x++) { 455 int runColor = 0; 456 int runY = 0; 457 Arrays.fill(runHistory, 0); 458 for (int y = 0, index = x; y < size; y++, index += size) { 459 int c = getBit(modules[index >>> 5], index); 460 if (c == runColor) { 461 runY++; 462 if (runY == 5) 463 result += PENALTY_N1; 464 else if (runY > 5) 465 result++; 466 } else { 467 finderPenaltyAddHistory(runY, runHistory); 468 if (runColor == 0) 469 result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; 470 runColor = c; 471 runY = 1; 472 } 473 } 474 result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3; 475 } 476 477 // Balance of dark and light modules 478 int total = size * size; // Note that size is odd, so dark/total != 1/2 479 // Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)% 480 int k = (Math.abs(dark * 20 - total * 10) + total - 1) / total - 1; 481 result += k * PENALTY_N4; 482 return result; 483 } 484 485 486 487 /*---- Private helper functions ----*/ 488 489 // Returns the number of 8-bit data (i.e. not error correction) codewords contained in any 490 // QR Code of the given version number and error correction level, with remainder bits discarded. 491 // This stateless pure function could be implemented as a (40*4)-cell lookup table. getNumDataCodewords(int ver, Ecc ecl)492 static int getNumDataCodewords(int ver, Ecc ecl) { 493 return QrTemplate.getNumRawDataModules(ver) / 8 494 - ECC_CODEWORDS_PER_BLOCK [ecl.ordinal()][ver] 495 * NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal()][ver]; 496 } 497 498 499 // Can only be called immediately after a light run is added, and 500 // returns either 0, 1, or 2. A helper function for getPenaltyScore(). finderPenaltyCountPatterns(int[] runHistory)501 private int finderPenaltyCountPatterns(int[] runHistory) { 502 int n = runHistory[1]; 503 assert n <= size * 3; 504 boolean core = n > 0 && runHistory[2] == n && runHistory[3] == n * 3 && runHistory[4] == n && runHistory[5] == n; 505 return (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0) 506 + (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0); 507 } 508 509 510 // Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore(). finderPenaltyTerminateAndCount(int currentRunColor, int currentRunLength, int[] runHistory)511 private int finderPenaltyTerminateAndCount(int currentRunColor, int currentRunLength, int[] runHistory) { 512 if (currentRunColor == 1) { // Terminate dark run 513 finderPenaltyAddHistory(currentRunLength, runHistory); 514 currentRunLength = 0; 515 } 516 currentRunLength += size; // Add light border to final run 517 finderPenaltyAddHistory(currentRunLength, runHistory); 518 return finderPenaltyCountPatterns(runHistory); 519 } 520 521 522 // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). finderPenaltyAddHistory(int currentRunLength, int[] runHistory)523 private void finderPenaltyAddHistory(int currentRunLength, int[] runHistory) { 524 if (runHistory[0] == 0) 525 currentRunLength += size; // Add light border to initial run 526 System.arraycopy(runHistory, 0, runHistory, 1, runHistory.length - 1); 527 runHistory[0] = currentRunLength; 528 } 529 530 531 // Returns 0 or 1 based on the (i mod 32)'th bit of x. getBit(int x, int i)532 static int getBit(int x, int i) { 533 return (x >>> i) & 1; 534 } 535 536 537 /*---- Constants and tables ----*/ 538 539 /** The minimum version number (1) supported in the QR Code Model 2 standard. */ 540 public static final int MIN_VERSION = 1; 541 542 /** The maximum version number (40) supported in the QR Code Model 2 standard. */ 543 public static final int MAX_VERSION = 40; 544 545 546 // For use in getPenaltyScore(), when evaluating which mask is best. 547 private static final int PENALTY_N1 = 3; 548 private static final int PENALTY_N2 = 3; 549 private static final int PENALTY_N3 = 40; 550 private static final int PENALTY_N4 = 10; 551 552 553 private static final byte[][] ECC_CODEWORDS_PER_BLOCK = { 554 // Version: (note that index 0 is for padding, and is set to an illegal value) 555 //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 556 {-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 557 {-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 558 {-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 559 {-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 560 }; 561 562 private static final byte[][] NUM_ERROR_CORRECTION_BLOCKS = { 563 // Version: (note that index 0 is for padding, and is set to an illegal value) 564 //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 565 {-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 566 {-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 567 {-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 568 {-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 569 }; 570 571 572 573 /*---- Public helper enumeration ----*/ 574 575 /** 576 * The error correction level in a QR Code symbol. 577 */ 578 public enum Ecc { 579 // Must be declared in ascending order of error protection 580 // so that the implicit ordinal() and values() work properly 581 /** The QR Code can tolerate about 7% erroneous codewords. */ LOW(1), 582 /** The QR Code can tolerate about 15% erroneous codewords. */ MEDIUM(0), 583 /** The QR Code can tolerate about 25% erroneous codewords. */ QUARTILE(3), 584 /** The QR Code can tolerate about 30% erroneous codewords. */ HIGH(2); 585 586 // In the range 0 to 3 (unsigned 2-bit integer). 587 final int formatBits; 588 589 // Constructor. Ecc(int fb)590 private Ecc(int fb) { 591 formatBits = fb; 592 } 593 } 594 595 } 596