boofcv.alg.fiducial.qrcode.QrCode Maven / Gradle / Ivy
/*
* Copyright (c) 2022, Peter Abeles. All Rights Reserved.
*
* This file is part of BoofCV (http://boofcv.org).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package boofcv.alg.fiducial.qrcode;
import georegression.struct.homography.Homography2D_F64;
import georegression.struct.point.Point2D_F64;
import georegression.struct.point.Point2D_I32;
import georegression.struct.shapes.Polygon2D_F64;
import org.ddogleg.struct.DogArray;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import static boofcv.alg.fiducial.qrcode.QrCode.ErrorLevel.*;
/**
* Information for a detected QR Code.
*
* Position Patterns (PP) have their vertices CCW order. The polygons are oriented such that the following sides are
* paired: ppCorner[1,2] paired ppRight[3,0] and ppCorner[2,3] paired ppDown[0,1].
*
* @author Peter Abeles
*/
@SuppressWarnings({"MutablePublicArray", "NullAway.Init"})
public class QrCode implements Cloneable {
/** Mask that's applied to format information when encoding */
public static final int FORMAT_MASK = 0b101010000010010;
/** Maximum possible version of a QR Code */
public static final int MAX_VERSION = 40;
/** The QR code version after which and including version information is encoded into the QR code */
public static final int VERSION_ENCODED_AT = 7;
public static final VersionInfo[] VERSION_INFO = new VersionInfo[MAX_VERSION + 1];
/** Location of data bits in the code qr for each version. Precomputed for speed. */
public static final List[] LOCATION_BITS = new ArrayList[MAX_VERSION + 1];
/**
* The finder pattern that is composed of the 3 position patterns. Orientation of corners in each
* position pattern goes in clockwise direction (when viewed in an image, CCW mathematically) 0 = top left,
* 1 = top right, 2 = bottom right, 3 = bottom left.
*/
public Polygon2D_F64 ppRight = new Polygon2D_F64(4);
public Polygon2D_F64 ppCorner = new Polygon2D_F64(4);
public Polygon2D_F64 ppDown = new Polygon2D_F64(4);
/** locally computed binary threshold at each position pattern */
public double threshRight, threshCorner, threshDown;
/** local threshold from bottom-right corner of QR code. Computed from local neighborhood */
public double threshDownRight;
/** which version of QR code was found. 1 to 40 */
public int version;
/** Level of error correction */
public ErrorLevel error;
/** Which masking pattern is applied */
public QrCodeMaskPattern mask;
/** Alignment pattern information */
public DogArray alignment = new DogArray<>(Alignment::new);
/** QR encoding mode */
public Mode mode = Mode.UNKNOWN;
/**
* Which string encoding was used decoding a {@link Mode#BYTE} message. If there is no BYTE encoding then
* this will be an empty string. If there are multiple independent BYTE segments then this will
* be the first one encountered.
*/
public String byteEncoding = "";
/** The raw byte data encoded into the QR Code. data + ecc */
public byte[] rawbits;
/** Raw byte data after error correction has been applied to it. Only contains the data portion. */
public byte[] corrected;
/** If applicable the message is decoded into a sequence of characters. */
public String message = "";
/** Specifies where the QR code parsing failed */
public Failure failureCause = Failure.NONE;
/**
* Approximate bounding box for QR-Code. The bottom right corner is estimated by intersecting lines
* and should not be used in SFM applications.
*
* Order: top-left = 0. Top-right = 1, Bottom-Right = 2, Bottom-Left = 3.
*/
public Polygon2D_F64 bounds = new Polygon2D_F64(4);
/** A homography transform from grid bit coordinates into image pixels. */
public Homography2D_F64 Hinv = new Homography2D_F64();
/** Number of bit errors detected when apply error correction to the message */
public int totalBitErrors;
/**
* True if the QR code was incorrectly encoded and the bits are transposed. If this is true then the position
* patterns are stored in a transposed order. Bounds will not be affected.
*/
public boolean bitsTransposed;
static {
// Manually entered from QR Code table. There's no simple equation for these magic numbers
VERSION_INFO[1] = new VersionInfo(26, new int[0]);
VERSION_INFO[1].add(L, 26, 19, 1);
VERSION_INFO[1].add(M, 26, 16, 1);
VERSION_INFO[1].add(Q, 26, 13, 1);
VERSION_INFO[1].add(H, 26, 9, 1);
VERSION_INFO[2] = new VersionInfo(44, new int[]{6, 18});
VERSION_INFO[2].add(L, 44, 34, 1);
VERSION_INFO[2].add(M, 44, 28, 1);
VERSION_INFO[2].add(Q, 44, 22, 1);
VERSION_INFO[2].add(H, 44, 16, 1);
VERSION_INFO[3] = new VersionInfo(70, new int[]{6, 22});
VERSION_INFO[3].add(L, 70, 55, 1);
VERSION_INFO[3].add(M, 70, 44, 1);
VERSION_INFO[3].add(Q, 35, 17, 2);
VERSION_INFO[3].add(H, 35, 13, 2);
VERSION_INFO[4] = new VersionInfo(100, new int[]{6, 26});
VERSION_INFO[4].add(L, 100, 80, 1);
VERSION_INFO[4].add(M, 50, 32, 2);
VERSION_INFO[4].add(Q, 50, 24, 2);
VERSION_INFO[4].add(H, 25, 9, 4);
VERSION_INFO[5] = new VersionInfo(134, new int[]{6, 30});
VERSION_INFO[5].add(L, 134, 108, 1);
VERSION_INFO[5].add(M, 67, 43, 2);
VERSION_INFO[5].add(Q, 33, 15, 2);
VERSION_INFO[5].add(H, 33, 11, 2);
VERSION_INFO[6] = new VersionInfo(172, new int[]{6, 34});
VERSION_INFO[6].add(L, 86, 68, 2);
VERSION_INFO[6].add(M, 43, 27, 4);
VERSION_INFO[6].add(Q, 43, 19, 4);
VERSION_INFO[6].add(H, 43, 15, 4);
VERSION_INFO[7] = new VersionInfo(196, new int[]{6, 22, 38});
VERSION_INFO[7].add(L, 98, 78, 2);
VERSION_INFO[7].add(M, 49, 31, 4);
VERSION_INFO[7].add(Q, 32, 14, 2);
VERSION_INFO[7].add(H, 39, 13, 4);
VERSION_INFO[8] = new VersionInfo(242, new int[]{6, 24, 42});
VERSION_INFO[8].add(L, 121, 97, 2);
VERSION_INFO[8].add(M, 60, 38, 2);
VERSION_INFO[8].add(Q, 40, 18, 4);
VERSION_INFO[8].add(H, 40, 14, 4);
VERSION_INFO[9] = new VersionInfo(292, new int[]{6, 26, 46});
VERSION_INFO[9].add(L, 146, 116, 2);
VERSION_INFO[9].add(M, 58, 36, 3);
VERSION_INFO[9].add(Q, 36, 16, 4);
VERSION_INFO[9].add(H, 36, 12, 4);
VERSION_INFO[10] = new VersionInfo(346, new int[]{6, 28, 50});
VERSION_INFO[10].add(L, 86, 68, 2);
VERSION_INFO[10].add(M, 69, 43, 4);
VERSION_INFO[10].add(Q, 43, 19, 6);
VERSION_INFO[10].add(H, 43, 15, 6);
VERSION_INFO[11] = new VersionInfo(404, new int[]{6, 30, 54});
VERSION_INFO[11].add(L, 101, 81, 4);
VERSION_INFO[11].add(M, 80, 50, 1);
VERSION_INFO[11].add(Q, 50, 22, 4);
VERSION_INFO[11].add(H, 36, 12, 3);
VERSION_INFO[12] = new VersionInfo(466, new int[]{6, 32, 58});
VERSION_INFO[12].add(L, 116, 92, 2);
VERSION_INFO[12].add(M, 58, 36, 6);
VERSION_INFO[12].add(Q, 46, 20, 4);
VERSION_INFO[12].add(H, 42, 14, 7);
VERSION_INFO[13] = new VersionInfo(532, new int[]{6, 34, 62});
VERSION_INFO[13].add(L, 133, 107, 4);
VERSION_INFO[13].add(M, 59, 37, 8);
VERSION_INFO[13].add(Q, 44, 20, 8);
VERSION_INFO[13].add(H, 33, 11, 12);
VERSION_INFO[14] = new VersionInfo(581, new int[]{6, 26, 46, 66});
VERSION_INFO[14].add(L, 145, 115, 3);
VERSION_INFO[14].add(M, 64, 40, 4);
VERSION_INFO[14].add(Q, 36, 16, 11);
VERSION_INFO[14].add(H, 36, 12, 11);
VERSION_INFO[15] = new VersionInfo(655, new int[]{6, 26, 48, 70});
VERSION_INFO[15].add(L, 109, 87, 5);
VERSION_INFO[15].add(M, 65, 41, 5);
VERSION_INFO[15].add(Q, 54, 24, 5);
VERSION_INFO[15].add(H, 36, 12, 11);
VERSION_INFO[16] = new VersionInfo(733, new int[]{6, 26, 50, 74});
VERSION_INFO[16].add(L, 122, 98, 5);
VERSION_INFO[16].add(M, 73, 45, 7);
VERSION_INFO[16].add(Q, 43, 19, 15);
VERSION_INFO[16].add(H, 45, 15, 3);
VERSION_INFO[17] = new VersionInfo(815, new int[]{6, 30, 54, 78});
VERSION_INFO[17].add(L, 135, 107, 1);
VERSION_INFO[17].add(M, 74, 46, 10);
VERSION_INFO[17].add(Q, 50, 22, 1);
VERSION_INFO[17].add(H, 42, 14, 2);
VERSION_INFO[18] = new VersionInfo(901, new int[]{6, 30, 56, 82});
VERSION_INFO[18].add(L, 150, 120, 5);
VERSION_INFO[18].add(M, 69, 43, 9);
VERSION_INFO[18].add(Q, 50, 22, 17);
VERSION_INFO[18].add(H, 42, 14, 2);
VERSION_INFO[19] = new VersionInfo(991, new int[]{6, 30, 58, 86});
VERSION_INFO[19].add(L, 141, 113, 3);
VERSION_INFO[19].add(M, 70, 44, 3);
VERSION_INFO[19].add(Q, 47, 21, 17);
VERSION_INFO[19].add(H, 39, 13, 9);
VERSION_INFO[20] = new VersionInfo(1085, new int[]{6, 34, 62, 90});
VERSION_INFO[20].add(L, 135, 107, 3);
VERSION_INFO[20].add(M, 67, 41, 3);
VERSION_INFO[20].add(Q, 54, 24, 15);
VERSION_INFO[20].add(H, 43, 15, 15);
VERSION_INFO[21] = new VersionInfo(1156, new int[]{6, 28, 50, 72, 94});
VERSION_INFO[21].add(L, 144, 116, 4);
VERSION_INFO[21].add(M, 68, 42, 17);
VERSION_INFO[21].add(Q, 50, 22, 17);
VERSION_INFO[21].add(H, 46, 16, 19);
VERSION_INFO[22] = new VersionInfo(1258, new int[]{6, 26, 50, 74, 98});
VERSION_INFO[22].add(L, 139, 111, 2);
VERSION_INFO[22].add(M, 74, 46, 17);
VERSION_INFO[22].add(Q, 54, 24, 7);
VERSION_INFO[22].add(H, 37, 13, 34);
VERSION_INFO[23] = new VersionInfo(1364, new int[]{6, 30, 54, 78, 102});
VERSION_INFO[23].add(L, 151, 121, 4);
VERSION_INFO[23].add(M, 75, 47, 4);
VERSION_INFO[23].add(Q, 54, 24, 11);
VERSION_INFO[23].add(H, 45, 15, 16);
VERSION_INFO[24] = new VersionInfo(1474, new int[]{6, 28, 54, 80, 106});
VERSION_INFO[24].add(L, 147, 117, 6);
VERSION_INFO[24].add(M, 73, 45, 6);
VERSION_INFO[24].add(Q, 54, 24, 11);
VERSION_INFO[24].add(H, 46, 16, 30);
VERSION_INFO[25] = new VersionInfo(1588, new int[]{6, 32, 58, 84, 110});
VERSION_INFO[25].add(L, 132, 106, 8);
VERSION_INFO[25].add(M, 75, 47, 8);
VERSION_INFO[25].add(Q, 54, 24, 7);
VERSION_INFO[25].add(H, 45, 15, 22);
VERSION_INFO[26] = new VersionInfo(1706, new int[]{6, 30, 58, 86, 114});
VERSION_INFO[26].add(L, 142, 114, 10);
VERSION_INFO[26].add(M, 74, 46, 19);
VERSION_INFO[26].add(Q, 50, 22, 28);
VERSION_INFO[26].add(H, 46, 16, 33);
VERSION_INFO[27] = new VersionInfo(1828, new int[]{6, 34, 62, 90, 118});
VERSION_INFO[27].add(L, 152, 122, 8);
VERSION_INFO[27].add(M, 73, 45, 22);
VERSION_INFO[27].add(Q, 53, 23, 8);
VERSION_INFO[27].add(H, 45, 15, 12);
VERSION_INFO[28] = new VersionInfo(1921, new int[]{6, 26, 50, 74, 98, 122});
VERSION_INFO[28].add(L, 147, 117, 3);
VERSION_INFO[28].add(M, 73, 45, 3);
VERSION_INFO[28].add(Q, 54, 24, 4);
VERSION_INFO[28].add(H, 45, 15, 11);
VERSION_INFO[29] = new VersionInfo(2051, new int[]{6, 30, 54, 78, 102, 126});
VERSION_INFO[29].add(L, 146, 116, 7);
VERSION_INFO[29].add(M, 73, 45, 21);
VERSION_INFO[29].add(Q, 53, 23, 1);
VERSION_INFO[29].add(H, 45, 15, 19);
VERSION_INFO[30] = new VersionInfo(2185, new int[]{6, 26, 52, 78, 104, 130});
VERSION_INFO[30].add(L, 145, 115, 5);
VERSION_INFO[30].add(M, 75, 47, 19);
VERSION_INFO[30].add(Q, 54, 24, 15);
VERSION_INFO[30].add(H, 45, 15, 23);
VERSION_INFO[31] = new VersionInfo(2323, new int[]{6, 30, 56, 82, 108, 134});
VERSION_INFO[31].add(L, 145, 115, 13);
VERSION_INFO[31].add(M, 74, 46, 2);
VERSION_INFO[31].add(Q, 54, 24, 42);
VERSION_INFO[31].add(H, 45, 15, 23);
VERSION_INFO[32] = new VersionInfo(2465, new int[]{6, 34, 60, 86, 112, 138});
VERSION_INFO[32].add(L, 145, 115, 17);
VERSION_INFO[32].add(M, 74, 46, 10);
VERSION_INFO[32].add(Q, 54, 24, 10);
VERSION_INFO[32].add(H, 45, 15, 19);
VERSION_INFO[33] = new VersionInfo(2611, new int[]{6, 30, 58, 86, 114, 142});
VERSION_INFO[33].add(L, 145, 115, 17);
VERSION_INFO[33].add(M, 74, 46, 14);
VERSION_INFO[33].add(Q, 54, 24, 29);
VERSION_INFO[33].add(H, 45, 15, 11);
VERSION_INFO[34] = new VersionInfo(2761, new int[]{6, 34, 62, 90, 118, 146});
VERSION_INFO[34].add(L, 145, 115, 13);
VERSION_INFO[34].add(M, 74, 46, 14);
VERSION_INFO[34].add(Q, 54, 24, 44);
VERSION_INFO[34].add(H, 46, 16, 59);
VERSION_INFO[35] = new VersionInfo(2876, new int[]{6, 30, 54, 78, 102, 126, 150});
VERSION_INFO[35].add(L, 151, 121, 12);
VERSION_INFO[35].add(M, 75, 47, 12);
VERSION_INFO[35].add(Q, 54, 24, 39);
VERSION_INFO[35].add(H, 45, 15, 22);
VERSION_INFO[36] = new VersionInfo(3034, new int[]{6, 24, 50, 76, 102, 128, 154});
VERSION_INFO[36].add(L, 151, 121, 6);
VERSION_INFO[36].add(M, 75, 47, 6);
VERSION_INFO[36].add(Q, 54, 24, 46);
VERSION_INFO[36].add(H, 45, 15, 2);
VERSION_INFO[37] = new VersionInfo(3196, new int[]{6, 28, 54, 80, 106, 132, 158});
VERSION_INFO[37].add(L, 152, 122, 17);
VERSION_INFO[37].add(M, 74, 46, 29);
VERSION_INFO[37].add(Q, 54, 24, 49);
VERSION_INFO[37].add(H, 45, 15, 24);
VERSION_INFO[38] = new VersionInfo(3362, new int[]{6, 32, 58, 84, 110, 136, 162});
VERSION_INFO[38].add(L, 152, 122, 4);
VERSION_INFO[38].add(M, 74, 46, 13);
VERSION_INFO[38].add(Q, 54, 24, 48);
VERSION_INFO[38].add(H, 45, 15, 42);
VERSION_INFO[39] = new VersionInfo(3532, new int[]{6, 26, 54, 82, 110, 138, 166});
VERSION_INFO[39].add(L, 147, 117, 20);
VERSION_INFO[39].add(M, 75, 47, 40);
VERSION_INFO[39].add(Q, 54, 24, 43);
VERSION_INFO[39].add(H, 45, 15, 10);
VERSION_INFO[40] = new VersionInfo(3706, new int[]{6, 30, 58, 86, 114, 142, 170});
VERSION_INFO[40].add(L, 148, 118, 19);
VERSION_INFO[40].add(M, 75, 47, 18);
VERSION_INFO[40].add(Q, 54, 24, 34);
VERSION_INFO[40].add(H, 45, 15, 20);
for (int version = 1; version <= MAX_VERSION; version++) {
LOCATION_BITS[version] = QrCodeCodeWordLocations.qrcode(version).bits;
}
}
public QrCode() {
reset();
}
public int getNumberOfModules() {
return totalModules(version);
}
public int getNumberOfDataBytes() {
return VERSION_INFO[version].totalDataBytes(error);
}
public static int totalModules( int version ) {
return version*4 + 17;
}
/**
* Resets the QR-Code so that it's in its initial state.
*/
@SuppressWarnings({"NullAway"})
public void reset() {
for (int i = 0; i < 4; i++) {
ppCorner.get(i).setTo(0, 0);
ppDown.get(i).setTo(0, 0);
ppRight.get(i).setTo(0, 0);
}
this.threshCorner = 0;
this.threshDown = 0;
this.threshRight = 0;
version = -1;
error = L;
mask = QrCodeMaskPattern.M111;
alignment.reset();
mode = Mode.UNKNOWN;
failureCause = Failure.NONE;
byteEncoding = "";
rawbits = null;
corrected = null;
message = null;
bitsTransposed = false;
totalBitErrors = 0;
}
@Override public QrCode clone() {
return new QrCode().setTo(this);
}
/**
* Sets 'this' so that it's equivalent to 'o'.
*
* @param o The target object
*/
@SuppressWarnings("NullAway")
public QrCode setTo( QrCode o ) {
this.version = o.version;
this.error = o.error;
this.mask = o.mask;
this.mode = o.mode;
this.rawbits = o.rawbits == null ? null : o.rawbits.clone();
this.corrected = o.corrected == null ? null : o.corrected.clone();
this.message = o.message;
this.threshCorner = o.threshCorner;
this.threshDown = o.threshDown;
this.threshRight = o.threshRight;
this.ppCorner.setTo(o.ppCorner);
this.ppDown.setTo(o.ppDown);
this.ppRight.setTo(o.ppRight);
this.failureCause = o.failureCause;
this.bounds.setTo(o.bounds);
this.alignment.reset();
for (int i = 0; i < o.alignment.size; i++) {
this.alignment.grow().set(o.alignment.get(i));
}
this.Hinv.setTo(o.Hinv);
this.bitsTransposed = o.bitsTransposed;
this.totalBitErrors = o.totalBitErrors;
return this;
}
/** Error correction level */
public enum ErrorLevel {
/** Error correction of about 7% */
L(0b01),
/** Error correction of about 15% */
M(0b00),
/** Error correction of about 25% */
Q(0b11),
/** Error correction of about 30% */
H(0b10);
ErrorLevel( int value ) {
this.value = value;
}
public int getValue() {
return value;
}
public static ErrorLevel lookup( int value ) {
return switch (value) {
case 0b01 -> L;
case 0b00 -> M;
case 0b11 -> Q;
case 0b10 -> H;
default -> throw new IllegalArgumentException("Unknown");
};
}
public static ErrorLevel lookup( String letter ) {
return switch (letter) {
case "L" -> L;
case "M" -> M;
case "Q" -> Q;
case "H" -> H;
default -> throw new IllegalArgumentException("Unknown");
};
}
final int value;
}
/** Information related to a specific alignment pattern. The center coordinate is stored. */
public static class Alignment {
/** Pixel coordinate of this alignment pattern's center */
public Point2D_F64 pixel = new Point2D_F64();
/** Center grid coordinate of alignment pattern. */
public int moduleX, moduleY;
/** The found grid coordinate */
Point2D_F64 moduleFound = new Point2D_F64();
/** Threshold value selected at this alignment pattern */
public double threshold;
public void set( Alignment o ) {
this.pixel.setTo(o.pixel);
this.moduleX = o.moduleX;
this.moduleY = o.moduleY;
this.moduleFound.setTo(o.moduleFound);
}
}
public static class VersionInfo {
// total number of codewords available
final public int codewords;
// location of alignment patterns
final public int[] alignment;
// information for each error correction level
final public Map levels = new HashMap<>();
public VersionInfo( int codewords, int[] alignment ) {
this.codewords = codewords;
this.alignment = alignment;
}
public void add( ErrorLevel level, int codeWords, int dataCodewords, int eccBlocks ) {
levels.put(level, new BlockInfo(codeWords, dataCodewords, eccBlocks));
}
/**
* Returns the total number of bytes in the data area that can be stored in at this version and error
* correction level.
*
* @param error Error correction level
* @return total bytes that can be stored.
*/
public int totalDataBytes( ErrorLevel error ) {
BlockInfo b = Objects.requireNonNull(levels.get(error));
int remaining = codewords - b.codewords*b.blocks;
int blocksB = remaining/(b.codewords + 1);
return b.dataCodewords*b.blocks + (b.dataCodewords + 1)*blocksB;
}
}
/**
* Specifies the format for a data block. Storage for data and ECC plus the number of blocks of each size.
*/
public static class BlockInfo {
/** Code words per block */
final public int codewords;
/** Number of data codewords */
final public int dataCodewords;
/**
* Number of error data blocks of this size. There can be one other set of blocks which will store codewords
* + 1 and dataCodewords + 1.
*/
final public int blocks;
public BlockInfo( int codewords, int dataCodewords, int blocks ) {
this.codewords = codewords;
this.dataCodewords = dataCodewords;
this.blocks = blocks;
}
}
/**
* The encoding mode. A QR Code can be encoded with multiple modes. The most complex character set is what the
* final mode is set to when decoding a QR code.
*/
public enum Mode {
NUMERIC(0b0001),
ALPHANUMERIC(0b0010),
BYTE(0b0100),
KANJI(0b1000),
ECI(0b0111),
STRUCTURE_APPENDED(0b0011),
FNC1_FIRST(0b0101),
FNC1_SECOND(0b1001),
/** Place holder */
UNKNOWN(-1),
/** The message has been encoded using multiple modes */
MIXED(-2);
// how this mode is encoded for a QR Code. Micro QR has a different approach.
final int bits;
Mode( int bits ) {
this.bits = bits;
}
public static Mode lookup( int bits ) {
if (NUMERIC.bits == bits)
return NUMERIC;
else if (ALPHANUMERIC.bits == bits)
return ALPHANUMERIC;
else if (BYTE.bits == bits)
return BYTE;
else if (KANJI.bits == bits)
return KANJI;
else if (ECI.bits == bits)
return ECI;
else if (STRUCTURE_APPENDED.bits == bits)
return STRUCTURE_APPENDED;
else if (FNC1_FIRST.bits == bits)
return FNC1_FIRST;
else if (FNC1_SECOND.bits == bits)
return FNC1_SECOND;
else
return UNKNOWN;
}
public static @Nullable Mode lookup( String name ) {
name = name.toUpperCase();
Mode[] modes = values();
for (int modeIdx = 0; modeIdx < modes.length; modeIdx++) {
Mode m = modes[modeIdx];
if (m.toString().equals(name))
return m;
}
return null;
}
}
/**
* Specifies the step at which decoding failed
*/
public enum Failure {
NONE,
FORMAT,
VERSION,
ALIGNMENT,
READING_BITS,
ERROR_CORRECTION,
UNKNOWN_MODE,
READING_PADDING,
MESSAGE_OVERFLOW,
DECODING_MESSAGE,
KANJI_UNAVAILABLE,
STRING_ENCODING_UNAVAILABLE
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy