See ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels defined by the QR code standard.
private FormatInformation(int formatInfo) { // Bits 3,4 errorCorrectionLevel = ErrorCorrectionLevel.forBits((formatInfo >> 3) & 0x03); // Bottom 3 bits dataMask = (byte)(formatInfo & 0x07); }
private static ZXing.QrCode.Internal.Version ChooseVersion(int RequiredBits, out ErrorCorrectionLevel ECLevel) { var ecls = new ErrorCorrectionLevel[] { ErrorCorrectionLevel.H, ErrorCorrectionLevel.Q, ErrorCorrectionLevel.M, ErrorCorrectionLevel.L }; int totalInputBytes = (RequiredBits + 7) / 8; // In the following comments, we use numbers of Version 7-H. for (int versionNum = 1; versionNum <= 40; versionNum++) { var version = ZXing.QrCode.Internal.Version.getVersionForNumber(versionNum); // numBytes = 196 int numBytes = version.TotalCodewords; // getNumECBytes = 130 if (numBytes >= totalInputBytes) { for (int ecl = 0; ecl < ecls.Length; ecl++) { var ecBlocks = version.getECBlocksForLevel(ecls[ecl]); int numEcBytes = ecBlocks.TotalECCodewords; // getNumDataBytes = 196 - 130 = 66 int numDataBytes = numBytes - numEcBytes; if (numDataBytes >= totalInputBytes) { ECLevel = ecls[ecl]; return version; } } } } throw new ArgumentException("Data too big", nameof(RequiredBits)); }
private static Version chooseVersion(int numInputBits, ErrorCorrectionLevel ecLevel) { for (int versionNum = 1; versionNum <= 40; versionNum++) { var version = Version.getVersionForNumber(versionNum); if (willFit(numInputBits, version, ecLevel)) { return(version); } } throw new WriterException("Data too big"); }
/// <summary> /// Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On /// success, store the result in "matrix" and return true. /// </summary> /// <param name="dataBits">The data bits.</param> /// <param name="ecLevel">The ec level.</param> /// <param name="version">The version.</param> /// <param name="maskPattern">The mask pattern.</param> /// <param name="matrix">The matrix.</param> public static void buildMatrix(BitArray dataBits, ErrorCorrectionLevel ecLevel, Version version, int maskPattern, ByteMatrix matrix) { clearMatrix(matrix); embedBasicPatterns(version, matrix); // Type information appear with any version. embedTypeInfo(ecLevel, maskPattern, matrix); // Version info appear if version >= 7. maybeEmbedVersionInfo(version, matrix); // Data should be embedded at end. embedDataBits(dataBits, maskPattern, matrix); }
private DecoderResult decode(BitMatrixParser parser, IDictionary <DecodeHintType, object> hints) { Version version = parser.readVersion(); if (version == null) { return(null); } var formatinfo = parser.readFormatInformation(); if (formatinfo == null) { return(null); } ErrorCorrectionLevel ecLevel = formatinfo.ErrorCorrectionLevel; // Read codewords byte[] codewords = parser.readCodewords(); if (codewords == null) { return(null); } // Separate into data blocks DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel); // Count total number of data bytes int totalBytes = 0; foreach (var dataBlock in dataBlocks) { totalBytes += dataBlock.NumDataCodewords; } byte[] resultBytes = new byte[totalBytes]; int resultOffset = 0; // Error-correct and copy data blocks together into a stream of bytes foreach (var dataBlock in dataBlocks) { byte[] codewordBytes = dataBlock.Codewords; int numDataCodewords = dataBlock.NumDataCodewords; if (!correctErrors(codewordBytes, numDataCodewords)) { return(null); } for (int i = 0; i < numDataCodewords; i++) { resultBytes[resultOffset++] = codewordBytes[i]; } } // Decode the contents of that stream of bytes return(DecodedBitStreamParser.decode(resultBytes, version, ecLevel, hints)); }
/// <summary> /// Decides the smallest version of QR code that will contain all of the provided data. /// </summary> /// <exception cref="WriterException">if the data cannot fit in any version</exception> private static Version recommendVersion(ErrorCorrectionLevel ecLevel, Mode mode, BitArray headerBits, BitArray dataBits) { // Hard part: need to know version to know how many bits length takes. But need to know how many // bits it takes to know version. First we take a guess at version by assuming version will be // the minimum, 1: var provisionalBitsNeeded = calculateBitsNeeded(mode, headerBits, dataBits, Version.getVersionForNumber(1)); var provisionalVersion = chooseVersion(provisionalBitsNeeded, ecLevel); // Use that guess to calculate the right version. I am still not sure this works in 100% of cases. var bitsNeeded = calculateBitsNeeded(mode, headerBits, dataBits, provisionalVersion); return(chooseVersion(bitsNeeded, ecLevel)); }
/// <summary></summary> /// <returns>true if the number of input bits will fit in a code with the specified version and error correction level.</returns> private static bool willFit(int numInputBits, Version version, ErrorCorrectionLevel ecLevel) { // In the following comments, we use numbers of Version 7-H. // numBytes = 196 var numBytes = version.TotalCodewords; // getNumECBytes = 130 var ecBlocks = version.getECBlocksForLevel(ecLevel); var numEcBytes = ecBlocks.TotalECCodewords; // getNumDataBytes = 196 - 130 = 66 var numDataBytes = numBytes - numEcBytes; var totalInputBytes = (numInputBits + 7) / 8; return(numDataBytes >= totalInputBytes); }
public static ByteMatrix CreateRawQR(byte[] rawData, ErrorCorrectionLevel errorCorrectionLevel) { int versionNumber = GetSmallestVersion(rawData.Length, errorCorrectionLevel); ZXing.QrCode.Internal.Version version = ZXing.QrCode.Internal.Version.getVersionForNumber(versionNumber); BitArray dataBits = new BitArray(); foreach (byte b in rawData) dataBits.appendBits(b, 8); ZXing.QrCode.Internal.Version.ECBlocks ecBlocks = version.getECBlocksForLevel(errorCorrectionLevel); int bytesLength = version.TotalCodewords - ecBlocks.TotalECCodewords; terminateBits(bytesLength, dataBits); BitArray resultBits = interleaveWithECBytes(dataBits, version.TotalCodewords, bytesLength, ecBlocks.NumBlocks); ByteMatrix matrix = new ByteMatrix(version.DimensionForVersion, version.DimensionForVersion); int maskPattern = chooseMaskPattern(resultBits, errorCorrectionLevel, version, matrix); MatrixUtil.buildMatrix(resultBits, errorCorrectionLevel, version, maskPattern, matrix); return matrix; }
private static Version chooseVersion(int numInputBits, ErrorCorrectionLevel ecLevel) { // In the following comments, we use numbers of Version 7-H. for (int versionNum = 1; versionNum <= 40; versionNum++) { Version version = Version.getVersionForNumber(versionNum); // numBytes = 196 int numBytes = version.TotalCodewords; // getNumECBytes = 130 Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); int numEcBytes = ecBlocks.TotalECCodewords; // getNumDataBytes = 196 - 130 = 66 int numDataBytes = numBytes - numEcBytes; int totalInputBytes = (numInputBits + 7) / 8; if (numDataBytes >= totalInputBytes) { return(version); } } throw new WriterException("Data too big"); }
private static int chooseMaskPattern(BitArray bits, ErrorCorrectionLevel ecLevel, Version version, ByteMatrix matrix) { int minPenalty = Int32.MaxValue; // Lower penalty is better. int bestMaskPattern = -1; // We try all mask patterns to choose the best one. for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) { MatrixUtil.buildMatrix(bits, ecLevel, version, maskPattern, matrix); int penalty = calculateMaskPenalty(matrix); if (penalty < minPenalty) { minPenalty = penalty; bestMaskPattern = maskPattern; } } return(bestMaskPattern); }
private static int chooseMaskPattern(BitArray bits, ErrorCorrectionLevel ecLevel, Version version, ByteMatrix matrix) { int minPenalty = Int32.MaxValue; // Lower penalty is better. int bestMaskPattern = -1; // We try all mask patterns to choose the best one. for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) { MatrixUtil.buildMatrix(bits, ecLevel, version, maskPattern, matrix); int penalty = calculateMaskPenalty(matrix); if (penalty < minPenalty) { minPenalty = penalty; bestMaskPattern = maskPattern; } } return bestMaskPattern; }
/// <summary> /// Make bit vector of type information. On success, store the result in "bits" and return true. /// Encode error correction level and mask pattern. See 8.9 of /// JISX0510:2004 (p.45) for details. /// </summary> /// <param name="ecLevel">The ec level.</param> /// <param name="maskPattern">The mask pattern.</param> /// <param name="bits">The bits.</param> public static void makeTypeInfoBits(ErrorCorrectionLevel ecLevel, int maskPattern, BitArray bits) { if (!QRCode.isValidMaskPattern(maskPattern)) { throw new WriterException("Invalid mask pattern"); } int typeInfo = (ecLevel.Bits << 3) | maskPattern; bits.appendBits(typeInfo, 5); int bchCode = calculateBCHCode(typeInfo, TYPE_INFO_POLY); bits.appendBits(bchCode, 10); BitArray maskBits = new BitArray(); maskBits.appendBits(TYPE_INFO_MASK_PATTERN, 15); bits.xor(maskBits); if (bits.Size != 15) { // Just in case. throw new WriterException("should not happen but we got: " + bits.Size); } }
/// <summary> /// Gets the EC blocks for level. /// </summary> /// <param name="ecLevel">The ec level.</param> /// <returns></returns> public ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel) { return ecBlocks[ecLevel.ordinal()]; }
/// <summary> /// Embed type information. On success, modify the matrix. /// </summary> /// <param name="ecLevel">The ec level.</param> /// <param name="maskPattern">The mask pattern.</param> /// <param name="matrix">The matrix.</param> public static void embedTypeInfo(ErrorCorrectionLevel ecLevel, int maskPattern, ByteMatrix matrix) { BitArray typeInfoBits = new BitArray(); makeTypeInfoBits(ecLevel, maskPattern, typeInfoBits); for (int i = 0; i < typeInfoBits.Size; ++i) { // Place bits in LSB to MSB order. LSB (least significant bit) is the last value in // "typeInfoBits". int bit = typeInfoBits[typeInfoBits.Size - 1 - i] ? 1 : 0; // Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46). int x1 = TYPE_INFO_COORDINATES[i][0]; int y1 = TYPE_INFO_COORDINATES[i][1]; matrix[x1, y1] = bit; if (i < 8) { // Right top corner. int x2 = matrix.Width - i - 1; int y2 = 8; matrix[x2, y2] = bit; } else { // Left bottom corner. int x2 = 8; int y2 = matrix.Height - 7 + (i - 8); matrix[x2, y2] = bit; } } }
private void loadSettings() { bool update = false; /// /// QR Detect indicator mask color /// try { maskColor = ColorTranslator.FromHtml( appSection.Settings["MaskColor"].Value ); } catch { appSection.Settings.Add( "MaskColor", ColorTranslator.ToHtml( maskColor ) ); update = true; } colorDlg.Color = maskColor; picMaskColor.BackColor = maskColor; /// /// Overlay Logo Icon /// try { overlayLogo = Convert.ToBoolean( appSection.Settings["OverlayLogo"].Value ); } catch { appSection.Settings.Add( "OverlayLogo", overlayLogo.ToString() ); update = true; } chkOverLogo.Checked = overlayLogo; try { overlayBGColor = ColorTranslator.FromHtml( appSection.Settings["OverlayBGColor"].Value ); } catch { appSection.Settings.Add( "OverlayBGColor", ColorTranslator.ToHtml( overlayBGColor ) ); update = true; } try { overlayLogoImage = appSection.Settings["OverlayLogoImage"].Value; } catch { appSection.Settings.Add( "OverlayLogoImage", overlayLogoImage ); update = true; } /// /// QR Encode Error Level /// string errorString = "M"; try { errorString = appSection.Settings["ErrorCorrectionLevel"].Value; } catch { appSection.Settings.Add( "ErrorCorrectionLevel", errorString ); update = true; } if ( string.Equals( errorString, I18N._( "L" ), StringComparison.CurrentCultureIgnoreCase ) ) { errorLevel = ErrorCorrectionLevel.L; } else if ( string.Equals( errorString, I18N._( "M" ), StringComparison.CurrentCultureIgnoreCase ) ) { errorLevel = ErrorCorrectionLevel.M; } else if ( string.Equals( errorString, I18N._( "Q" ), StringComparison.CurrentCultureIgnoreCase ) ) { errorLevel = ErrorCorrectionLevel.Q; } else if ( string.Equals( errorString, I18N._( "H" ), StringComparison.CurrentCultureIgnoreCase ) ) { errorLevel = ErrorCorrectionLevel.H; } else { errorLevel = ErrorCorrectionLevel.M; } cbErrorLevel.SelectedIndex = cbErrorLevel.Items.IndexOf( I18N._( errorString ) ); /// /// QR Decode Options /// try { chkDecodeFormat1D.Checked = Convert.ToBoolean( appSection.Settings["DecodeFormat1D"].Value ); } catch { appSection.Settings.Add( "DecodeFormat1D", chkDecodeFormat1D.Checked.ToString() ); update = true; } try { chkDecodeFormatDM.Checked = Convert.ToBoolean( appSection.Settings["DecodeFormatDM"].Value ); } catch { appSection.Settings.Add( "DecodeFormatDM", chkDecodeFormatDM.Checked.ToString() ); update = true; } try { chkDecodeFormatQR.Checked = Convert.ToBoolean( appSection.Settings["DecodeFormatQR"].Value ); } catch { appSection.Settings.Add( "DecodeFormatQR", chkDecodeFormatQR.Checked.ToString() ); update = true; } if(update) config.Save(); }
internal static DecoderResult decode(byte[] bytes, Version version, ErrorCorrectionLevel ecLevel, IDictionary<DecodeHintType, object> hints) { var bits = new BitSource(bytes); var result = new StringBuilder(50); var byteSegments = new List<byte[]>(1); var symbolSequence = -1; var parityData = -1; try { // CharacterSetECI currentCharacterSetECI = null; bool fc1InEffect = false; Mode mode; do { // While still another segment to read... if (bits.available() < 4) { // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here mode = Mode.TERMINATOR; } else { try { mode = Mode.forBits(bits.readBits(4)); // mode is encoded by 4 bits } catch (ArgumentException) { return null; } } if (mode != Mode.TERMINATOR) { if (mode == Mode.FNC1_FIRST_POSITION || mode == Mode.FNC1_SECOND_POSITION) { // We do little with FNC1 except alter the parsed result a bit according to the spec fc1InEffect = true; } else if (mode == Mode.STRUCTURED_APPEND) { if (bits.available() < 16) { return null; } // not really supported; but sequence number and parity is added later to the result metadata // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue symbolSequence = bits.readBits(8); parityData = bits.readBits(8); } else if (mode == Mode.ECI) { /* // Count doesn't apply to ECI int value = parseECIValue(bits); currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value); if (currentCharacterSetECI == null) { return null; } * */ } else { // First handle Hanzi mode which does not start with character count if (mode == Mode.HANZI) { //chinese mode contains a sub set indicator right after mode indicator int subset = bits.readBits(4); int countHanzi = bits.readBits(mode.getCharacterCountBits(version)); if (subset == GB2312_SUBSET) { if (!decodeHanziSegment(bits, result, countHanzi)) return null; } } else { // "Normal" QR code modes: // How many characters will follow, encoded in this mode? int count = bits.readBits(mode.getCharacterCountBits(version)); if (mode == Mode.NUMERIC) { if (!decodeNumericSegment(bits, result, count)) return null; } else if (mode == Mode.ALPHANUMERIC) { if (!decodeAlphanumericSegment(bits, result, count, fc1InEffect)) return null; } else if (mode == Mode.BYTE) { if (!decodeByteSegment(bits, result, count, byteSegments, hints)) return null; } else if (mode == Mode.KANJI) { if (!decodeKanjiSegment(bits, result, count)) return null; } else { return null; } } } } } while (mode != Mode.TERMINATOR); } catch (ArgumentException) { // from readBits() calls return null; } #if WindowsCE var resultString = result.ToString().Replace("\n", "\r\n"); #else var resultString = result.ToString().Replace("\r\n", "\n").Replace("\n", Environment.NewLine); #endif return new DecoderResult(bytes, resultString, byteSegments.Count == 0 ? null : byteSegments, ecLevel == null ? null : ecLevel.ToString(), symbolSequence, parityData); }
/// <summary> /// Encode "bytes" with the error correction level "ecLevel". The encoding mode will be chosen /// internally by chooseMode(). On success, store the result in "qrCode". /// We recommend you to use QRCode.EC_LEVEL_L (the lowest level) for /// "getECLevel" since our primary use is to show QR code on desktop screens. We don't need very /// strong error correction for this purpose. /// Note that there is no way to encode bytes in MODE_KANJI. We might want to add EncodeWithMode() /// with which clients can specify the encoding mode. For now, we don't need the functionality. /// </summary> /// <param name="content">The content.</param> /// <param name="ecLevel">The ec level.</param> public static QRCode encode(String content, ErrorCorrectionLevel ecLevel) { return(encode(content, ecLevel, null)); }
internal static DecoderResult decode(byte[] bytes, Version version, ErrorCorrectionLevel ecLevel, IDictionary <DecodeHintType, object> hints) { var bits = new BitSource(bytes); var result = new StringBuilder(50); var byteSegments = new List <byte[]> (1); var symbolSequence = -1; var parityData = -1; try { CharacterSetECI currentCharacterSetECI = null; bool fc1InEffect = false; Mode mode; do { // While still another segment to read... if (bits.available() < 4) { // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here mode = Mode.TERMINATOR; } else { try { mode = Mode.forBits(bits.readBits(4)); // mode is encoded by 4 bits } catch (ArgumentException) { return(null); } } if (mode != Mode.TERMINATOR) { if (mode == Mode.FNC1_FIRST_POSITION || mode == Mode.FNC1_SECOND_POSITION) { // We do little with FNC1 except alter the parsed result a bit according to the spec fc1InEffect = true; } else if (mode == Mode.STRUCTURED_APPEND) { if (bits.available() < 16) { return(null); } // not really supported; but sequence number and parity is added later to the result metadata // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue symbolSequence = bits.readBits(8); parityData = bits.readBits(8); } else if (mode == Mode.ECI) { // Count doesn't apply to ECI int value = parseECIValue(bits); currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value); if (currentCharacterSetECI == null) { return(null); } } else { // First handle Hanzi mode which does not start with character count if (mode == Mode.HANZI) { //chinese mode contains a sub set indicator right after mode indicator int subset = bits.readBits(4); int countHanzi = bits.readBits(mode.getCharacterCountBits(version)); if (subset == GB2312_SUBSET) { if (!decodeHanziSegment(bits, result, countHanzi)) { return(null); } } } else { // "Normal" QR code modes: // How many characters will follow, encoded in this mode? int count = bits.readBits(mode.getCharacterCountBits(version)); if (mode == Mode.NUMERIC) { if (!decodeNumericSegment(bits, result, count)) { return(null); } } else if (mode == Mode.ALPHANUMERIC) { if (!decodeAlphanumericSegment(bits, result, count, fc1InEffect)) { return(null); } } else if (mode == Mode.BYTE) { if (!decodeByteSegment(bits, result, count, currentCharacterSetECI, byteSegments, hints)) { return(null); } } else if (mode == Mode.KANJI) { if (!decodeKanjiSegment(bits, result, count)) { return(null); } } else { return(null); } } } } } while (mode != Mode.TERMINATOR); } catch (ArgumentException) { // from readBits() calls return(null); } #if WindowsCE var resultString = result.ToString().Replace("\n", "\r\n"); #else var resultString = result.ToString().Replace("\r\n", "\n").Replace("\n", Environment.NewLine); #endif return(new DecoderResult(bytes, resultString, byteSegments.Count == 0 ? null : byteSegments, ecLevel == null ? null : ecLevel.ToString(), symbolSequence, parityData)); }
/// <summary> /// Encodes the specified content. /// </summary> /// <param name="content">The content.</param> /// <param name="ecLevel">The ec level.</param> /// <param name="hints">The hints.</param> /// <returns></returns> public static QRCode encode(String content, ErrorCorrectionLevel ecLevel, IDictionary <EncodeHintType, object> hints) { // Determine what character encoding has been specified by the caller, if any bool hasEncodingHint = hints != null && hints.ContainsKey(EncodeHintType.CHARACTER_SET); #if !SILVERLIGHT || WINDOWS_PHONE var encoding = hints == null || !hints.ContainsKey(EncodeHintType.CHARACTER_SET) ? null : (String)hints[EncodeHintType.CHARACTER_SET]; if (encoding == null) { encoding = DEFAULT_BYTE_MODE_ENCODING; } var generateECI = hasEncodingHint || !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding); #else // Silverlight supports only UTF-8 and UTF-16 out-of-the-box const string encoding = "UTF-8"; // caller of the method can only control if the ECI segment should be written // character set is fixed to UTF-8; but some scanners doesn't like the ECI segment var generateECI = hasEncodingHint; #endif // Pick an encoding mode appropriate for the content. Note that this will not attempt to use // multiple modes / segments even if that were more efficient. Twould be nice. var mode = chooseMode(content, encoding); // This will store the header information, like mode and // length, as well as "header" segments like an ECI segment. var headerBits = new BitArray(); // Append ECI segment if applicable if (mode == Mode.BYTE && generateECI) { var eci = CharacterSetECI.getCharacterSetECIByName(encoding); if (eci != null) { var eciIsExplicitDisabled = (hints != null && hints.ContainsKey(EncodeHintType.DISABLE_ECI) && hints[EncodeHintType.DISABLE_ECI] != null && Convert.ToBoolean(hints[EncodeHintType.DISABLE_ECI].ToString())); if (!eciIsExplicitDisabled) { appendECI(eci, headerBits); } } } // Append the FNC1 mode header for GS1 formatted data if applicable var hasGS1FormatHint = hints != null && hints.ContainsKey(EncodeHintType.GS1_FORMAT); if (hasGS1FormatHint && hints[EncodeHintType.GS1_FORMAT] != null && Convert.ToBoolean(hints[EncodeHintType.GS1_FORMAT].ToString())) { // GS1 formatted codes are prefixed with a FNC1 in first position mode header appendModeInfo(Mode.FNC1_FIRST_POSITION, headerBits); } // (With ECI in place,) Write the mode marker appendModeInfo(mode, headerBits); // Collect data within the main segment, separately, to count its size if needed. Don't add it to // main payload yet. var dataBits = new BitArray(); appendBytes(content, mode, dataBits, encoding); Version version; if (hints != null && hints.ContainsKey(EncodeHintType.QR_VERSION)) { int versionNumber = Int32.Parse(hints[EncodeHintType.QR_VERSION].ToString()); version = Version.getVersionForNumber(versionNumber); int bitsNeeded = calculateBitsNeeded(mode, headerBits, dataBits, version); if (!willFit(bitsNeeded, version, ecLevel)) { throw new WriterException("Data too big for requested version"); } } else { version = recommendVersion(ecLevel, mode, headerBits, dataBits); } var headerAndDataBits = new BitArray(); headerAndDataBits.appendBitArray(headerBits); // Find "length" of main segment and write it var numLetters = mode == Mode.BYTE ? dataBits.SizeInBytes : content.Length; appendLengthInfo(numLetters, version, mode, headerAndDataBits); // Put data together into the overall payload headerAndDataBits.appendBitArray(dataBits); var ecBlocks = version.getECBlocksForLevel(ecLevel); var numDataBytes = version.TotalCodewords - ecBlocks.TotalECCodewords; // Terminate the bits properly. terminateBits(numDataBytes, headerAndDataBits); // Interleave data bits with error correction code. var finalBits = interleaveWithECBytes(headerAndDataBits, version.TotalCodewords, numDataBytes, ecBlocks.NumBlocks); var qrCode = new QRCode { ECLevel = ecLevel, Mode = mode, Version = version }; // Choose the mask pattern and set to "qrCode". var dimension = version.DimensionForVersion; var matrix = new ByteMatrix(dimension, dimension); var maskPattern = chooseMaskPattern(finalBits, ecLevel, version, matrix); qrCode.MaskPattern = maskPattern; // Build the matrix and set it to "qrCode". MatrixUtil.buildMatrix(finalBits, ecLevel, version, maskPattern, matrix); qrCode.Matrix = matrix; return(qrCode); }
public static QRCode encode(String content, ErrorCorrectionLevel ecLevel, IDictionary hints) { // Determine what character encoding has been specified by the caller, if any String encoding = hints == null || !hints.Contains(EncodeHintType.CHARACTER_SET) ? null : (String)hints[EncodeHintType.CHARACTER_SET]; if (encoding == null) { encoding = DEFAULT_BYTE_MODE_ENCODING; } bool doSelectMask = hints == null || !hints.Contains(EncodeHintType.QR_DO_MASK_SELECTION) ? false : (bool)hints[EncodeHintType.QR_DO_MASK_SELECTION]; // Pick an encoding mode appropriate for the content. Note that this will not attempt to use // multiple modes / segments even if that were more efficient. Twould be nice. Mode mode = chooseMode(content, encoding); // This will store the header information, like mode and // length, as well as "header" segments like an ECI segment. BitArray headerBits = new BitArray(); // Append ECI segment if applicable if (mode == Mode.BYTE && !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding)) { CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding); if (eci != null) { appendECI(eci, headerBits); } } // (With ECI in place,) Write the mode marker appendModeInfo(mode, headerBits); // Collect data within the main segment, separately, to count its size if needed. Don't add it to // main payload yet. BitArray dataBits = new BitArray(); appendBytes(content, mode, dataBits, encoding); // Hard part: need to know version to know how many bits length takes. But need to know how many // bits it takes to know version. To pick version size assume length takes maximum bits int bitsNeeded = headerBits.Size + mode.getCharacterCountBits(Version.getVersionForNumber(40)) + dataBits.Size; Version version = chooseVersion(bitsNeeded, ecLevel); BitArray headerAndDataBits = new BitArray(); headerAndDataBits.appendBitArray(headerBits); // Find "length" of main segment and write it int numLetters = mode == Mode.BYTE ? dataBits.SizeInBytes : content.Length; appendLengthInfo(numLetters, version, mode, headerAndDataBits); // Put data together into the overall payload headerAndDataBits.appendBitArray(dataBits); Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); int numDataBytes = version.TotalCodewords - ecBlocks.TotalECCodewords; // Terminate the bits properly. terminateBits(numDataBytes, headerAndDataBits); // Interleave data bits with error correction code. BitArray finalBits = interleaveWithECBytes(headerAndDataBits, version.TotalCodewords, numDataBytes, ecBlocks.NumBlocks); QRCode qrCode = new QRCode { ECLevel = ecLevel, Mode = mode, Version = version }; // Choose the mask pattern and set to "qrCode". int dimension = version.DimensionForVersion; ByteMatrix matrix = new ByteMatrix(dimension, dimension); int maskPattern = 3; if (doSelectMask) maskPattern = chooseMaskPattern(finalBits, ecLevel, version, matrix); qrCode.MaskPattern = maskPattern; // Build the matrix and set it to "qrCode". MatrixUtil.buildMatrix(finalBits, ecLevel, version, maskPattern, matrix); qrCode.Matrix = matrix; return qrCode; }
/// <summary> /// Gets the EC blocks for level. /// </summary> /// <param name="ecLevel">The ec level.</param> /// <returns></returns> public ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel) { return(ecBlocks[ecLevel.ordinal()]); }
public static QRCode encode(String content, ErrorCorrectionLevel ecLevel, IDictionary hints) { // Determine what character encoding has been specified by the caller, if any String encoding = hints == null || !hints.Contains(EncodeHintType.CHARACTER_SET) ? null : (String)hints[EncodeHintType.CHARACTER_SET]; if (encoding == null) { encoding = DEFAULT_BYTE_MODE_ENCODING; } bool doSelectMask = hints == null || !hints.Contains(EncodeHintType.QR_DO_MASK_SELECTION) ? false : (bool)hints[EncodeHintType.QR_DO_MASK_SELECTION]; // Pick an encoding mode appropriate for the content. Note that this will not attempt to use // multiple modes / segments even if that were more efficient. Twould be nice. Mode mode = chooseMode(content, encoding); // This will store the header information, like mode and // length, as well as "header" segments like an ECI segment. BitArray headerBits = new BitArray(); // Append ECI segment if applicable if (mode == Mode.BYTE && !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding)) { CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding); if (eci != null) { appendECI(eci, headerBits); } } // (With ECI in place,) Write the mode marker appendModeInfo(mode, headerBits); // Collect data within the main segment, separately, to count its size if needed. Don't add it to // main payload yet. BitArray dataBits = new BitArray(); appendBytes(content, mode, dataBits, encoding); // Hard part: need to know version to know how many bits length takes. But need to know how many // bits it takes to know version. To pick version size assume length takes maximum bits int bitsNeeded = headerBits.Size + mode.getCharacterCountBits(Version.getVersionForNumber(40)) + dataBits.Size; Version version = chooseVersion(bitsNeeded, ecLevel); BitArray headerAndDataBits = new BitArray(); headerAndDataBits.appendBitArray(headerBits); // Find "length" of main segment and write it int numLetters = mode == Mode.BYTE ? dataBits.SizeInBytes : content.Length; appendLengthInfo(numLetters, version, mode, headerAndDataBits); // Put data together into the overall payload headerAndDataBits.appendBitArray(dataBits); Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); int numDataBytes = version.TotalCodewords - ecBlocks.TotalECCodewords; // Terminate the bits properly. terminateBits(numDataBytes, headerAndDataBits); // Interleave data bits with error correction code. BitArray finalBits = interleaveWithECBytes(headerAndDataBits, version.TotalCodewords, numDataBytes, ecBlocks.NumBlocks); QRCode qrCode = new QRCode { ECLevel = ecLevel, Mode = mode, Version = version }; // Choose the mask pattern and set to "qrCode". int dimension = version.DimensionForVersion; ByteMatrix matrix = new ByteMatrix(dimension, dimension); int maskPattern = 3; if (doSelectMask) { maskPattern = chooseMaskPattern(finalBits, ecLevel, version, matrix); } qrCode.MaskPattern = maskPattern; // Build the matrix and set it to "qrCode". MatrixUtil.buildMatrix(finalBits, ecLevel, version, maskPattern, matrix); qrCode.Matrix = matrix; return(qrCode); }
private static int GetSmallestVersion(int size, ErrorCorrectionLevel errorCorrectionLevel) { return Array.FindIndex(MaxQRSize[errorCorrectionLevel.ordinal()], i => i >= size) + 1; }
/// <summary> /// Encodes the specified content. /// </summary> /// <param name="content">The content.</param> /// <param name="ecLevel">The ec level.</param> /// <param name="hints">The hints.</param> /// <returns></returns> public static QRCode encode(String content, ErrorCorrectionLevel ecLevel, IDictionary <EncodeHintType, object> hints) { // Determine what character encoding has been specified by the caller, if any #if !SILVERLIGHT || WINDOWS_PHONE String encoding = hints == null || !hints.ContainsKey(EncodeHintType.CHARACTER_SET) ? null : (String)hints[EncodeHintType.CHARACTER_SET]; if (encoding == null) { encoding = DEFAULT_BYTE_MODE_ENCODING; } bool generateECI = !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding); #else // Silverlight supports only UTF-8 and UTF-16 out-of-the-box const string encoding = "UTF-8"; // caller of the method can only control if the ECI segment should be written // character set is fixed to UTF-8; but some scanners doesn't like the ECI segment bool generateECI = (hints != null && hints.ContainsKey(EncodeHintType.CHARACTER_SET)); #endif // http://zxingnet.codeplex.com/discussions/399045 if (hints != null && hints.ContainsKey(EncodeHintType.DISABLE_ECI) && (bool)hints[EncodeHintType.DISABLE_ECI]) { generateECI = false; } // Pick an encoding mode appropriate for the content. Note that this will not attempt to use // multiple modes / segments even if that were more efficient. Twould be nice. Mode mode = chooseMode(content, encoding); // This will store the header information, like mode and // length, as well as "header" segments like an ECI segment. BitArray headerBits = new BitArray(); // Append ECI segment if applicable if (mode == Mode.BYTE && generateECI) { CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding); if (eci != null) { appendECI(eci, headerBits); } } // (With ECI in place,) Write the mode marker appendModeInfo(mode, headerBits); // Collect data within the main segment, separately, to count its size if needed. Don't add it to // main payload yet. BitArray dataBits = new BitArray(); appendBytes(content, mode, dataBits, encoding); // Hard part: need to know version to know how many bits length takes. But need to know how many // bits it takes to know version. First we take a guess at version by assuming version will be // the minimum, 1: int provisionalBitsNeeded = headerBits.Size + mode.getCharacterCountBits(Version.getVersionForNumber(1)) + dataBits.Size; Version provisionalVersion = chooseVersion(provisionalBitsNeeded, ecLevel); // Use that guess to calculate the right version. I am still not sure this works in 100% of cases. int bitsNeeded = headerBits.Size + mode.getCharacterCountBits(provisionalVersion) + dataBits.Size; Version version = chooseVersion(bitsNeeded, ecLevel); BitArray headerAndDataBits = new BitArray(); headerAndDataBits.appendBitArray(headerBits); // Find "length" of main segment and write it int numLetters = mode == Mode.BYTE ? dataBits.SizeInBytes : content.Length; appendLengthInfo(numLetters, version, mode, headerAndDataBits); // Put data together into the overall payload headerAndDataBits.appendBitArray(dataBits); Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); int numDataBytes = version.TotalCodewords - ecBlocks.TotalECCodewords; // Terminate the bits properly. terminateBits(numDataBytes, headerAndDataBits); // Interleave data bits with error correction code. BitArray finalBits = interleaveWithECBytes(headerAndDataBits, version.TotalCodewords, numDataBytes, ecBlocks.NumBlocks); QRCode qrCode = new QRCode { ECLevel = ecLevel, Mode = mode, Version = version }; // Choose the mask pattern and set to "qrCode". int dimension = version.DimensionForVersion; ByteMatrix matrix = new ByteMatrix(dimension, dimension); int maskPattern = chooseMaskPattern(finalBits, ecLevel, version, matrix); qrCode.MaskPattern = maskPattern; // Build the matrix and set it to "qrCode". MatrixUtil.buildMatrix(finalBits, ecLevel, version, maskPattern, matrix); qrCode.Matrix = matrix; return(qrCode); }
/// <summary> /// Encode "bytes" with the error correction level "ecLevel". The encoding mode will be chosen /// internally by chooseMode(). On success, store the result in "qrCode". /// We recommend you to use QRCode.EC_LEVEL_L (the lowest level) for /// "getECLevel" since our primary use is to show QR code on desktop screens. We don't need very /// strong error correction for this purpose. /// Note that there is no way to encode bytes in MODE_KANJI. We might want to add EncodeWithMode() /// with which clients can specify the encoding mode. For now, we don't need the functionality. /// </summary> /// <param name="content">text to encode</param> /// <param name="ecLevel">error correction level to use</param> /// <returns><see cref="QRCode"/> representing the encoded QR code</returns> public static QRCode encode(String content, ErrorCorrectionLevel ecLevel) { return encode(content, ecLevel, null); }
private static void compareToGoldenFile(String contents, ErrorCorrectionLevel ecLevel, int resolution, String fileName) { var image = loadImage(fileName); Assert.NotNull(image); BitMatrix goldenResult = createMatrixFromImage(image); Assert.NotNull(goldenResult); QRCodeWriter writer = new QRCodeWriter(); IDictionary<EncodeHintType, Object> hints = new Dictionary<EncodeHintType, Object>(); hints[EncodeHintType.ERROR_CORRECTION] = ecLevel; BitMatrix generatedResult = writer.encode(contents, BarcodeFormat.QR_CODE, resolution, resolution, hints); Assert.AreEqual(resolution, generatedResult.Width); Assert.AreEqual(resolution, generatedResult.Height); Assert.AreEqual(goldenResult, generatedResult); }
private void cbErrorLevel_SelectedIndexChanged( object sender, EventArgs e ) { if ( !this.Visible ) return; string errorString = cbErrorLevel.SelectedItem.ToString(); if ( string.Equals( errorString, I18N._( "L" ), StringComparison.CurrentCultureIgnoreCase ) ) { errorLevel = ErrorCorrectionLevel.L; } else if ( string.Equals( errorString, I18N._( "M" ), StringComparison.CurrentCultureIgnoreCase ) ) { errorLevel = ErrorCorrectionLevel.M; } else if ( string.Equals( errorString, I18N._( "Q" ), StringComparison.CurrentCultureIgnoreCase ) ) { errorLevel = ErrorCorrectionLevel.Q; } else if ( string.Equals( errorString, I18N._( "H" ), StringComparison.CurrentCultureIgnoreCase ) ) { errorLevel = ErrorCorrectionLevel.H; } else { errorLevel = ErrorCorrectionLevel.Q; } appSection.Settings["ErrorCorrectionLevel"].Value = errorString; config.Save(); }
private static Version chooseVersion(int numInputBits, ErrorCorrectionLevel ecLevel) { // In the following comments, we use numbers of Version 7-H. for (int versionNum = 1; versionNum <= 40; versionNum++) { Version version = Version.getVersionForNumber(versionNum); // numBytes = 196 int numBytes = version.TotalCodewords; // getNumECBytes = 130 Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); int numEcBytes = ecBlocks.TotalECCodewords; // getNumDataBytes = 196 - 130 = 66 int numDataBytes = numBytes - numEcBytes; int totalInputBytes = (numInputBits + 7) / 8; if (numDataBytes >= totalInputBytes) { return version; } } throw new WriterException("Data too big"); }
/// <summary> /// Creates a MinimalEncoder /// </summary> /// <param name="stringToEncode">The string to encode</param> /// <param name="priorityCharset">The preferred <see cref="System.Text.Encoding"/>. When the value of the argument is null, the algorithm /// * chooses charsets that leads to a minimal representation.Otherwise the algorithm will use the priority /// * charset to encode any character in the input that can be encoded by it if the charset is among the /// * supported charsets.</param> /// <param name="isGS1"> {@code true} if a FNC1 is to be prepended; {@code false} otherwise</param> /// <param name="ecLevel">The error correction level.</param> public MinimalEncoder(String stringToEncode, Encoding priorityCharset, bool isGS1, ErrorCorrectionLevel ecLevel) { this.stringToEncode = stringToEncode; this.isGS1 = isGS1; this.ecLevel = ecLevel; var neededEncoders = new List <Encoding>(); neededEncoders.Add(Clone(StringUtils.ISO88591_ENCODING)); var needUnicodeEncoder = priorityCharset != null && priorityCharset.WebName.StartsWith("UTF", StringComparison.OrdinalIgnoreCase); for (int i = 0; i < stringToEncode.Length; i++) { bool canEnc = false; foreach (var encoder in neededEncoders) { if (canEncode(encoder, stringToEncode[i])) { canEnc = true; break; } } if (!canEnc) { foreach (var encoder in ENCODERS) { if (canEncode(encoder, stringToEncode[i])) { neededEncoders.Add(encoder); canEnc = true; break; } } } if (!canEnc) { needUnicodeEncoder = true; } } if (neededEncoders.Count == 1 && !needUnicodeEncoder) { encoders = new Encoding[] { neededEncoders[0] }; } else { encoders = new Encoding[neededEncoders.Count + 2]; int index = 0; foreach (var encoder in neededEncoders) { encoders[index++] = encoder; } encoders[index] = Clone(Encoding.UTF8); encoders[index + 1] = Clone(Encoding.BigEndianUnicode); } int priorityEncoderIndexValue = -1; if (priorityCharset != null) { for (int i = 0; i < encoders.Length; i++) { if (encoders[i] != null && priorityCharset.WebName.Equals(encoders[i].WebName)) { priorityEncoderIndexValue = i; break; } } } priorityEncoderIndex = priorityEncoderIndexValue; }
/// <summary> /// Encodes the specified content. /// </summary> /// <param name="content">The content.</param> /// <param name="ecLevel">The ec level.</param> /// <param name="hints">The hints.</param> /// <returns></returns> public static QRCode encode(String content, ErrorCorrectionLevel ecLevel, IDictionary<EncodeHintType, object> hints) { // Determine what character encoding has been specified by the caller, if any #if !SILVERLIGHT || WINDOWS_PHONE String encoding = hints == null || !hints.ContainsKey(EncodeHintType.CHARACTER_SET) ? null : (String)hints[EncodeHintType.CHARACTER_SET]; if (encoding == null) { encoding = DEFAULT_BYTE_MODE_ENCODING; } bool generateECI = !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding); #else // Silverlight supports only UTF-8 and UTF-16 out-of-the-box const string encoding = "UTF-8"; // caller of the method can only control if the ECI segment should be written // character set is fixed to UTF-8; but some scanners doesn't like the ECI segment bool generateECI = (hints != null && hints.ContainsKey(EncodeHintType.CHARACTER_SET)); #endif // Pick an encoding mode appropriate for the content. Note that this will not attempt to use // multiple modes / segments even if that were more efficient. Twould be nice. Mode mode = chooseMode(content, encoding); // This will store the header information, like mode and // length, as well as "header" segments like an ECI segment. BitArray headerBits = new BitArray(); // Append ECI segment if applicable if (mode == Mode.BYTE && generateECI) { CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding); if (eci != null) { var eciIsExplicitDisabled = (hints != null && hints.ContainsKey(EncodeHintType.DISABLE_ECI) ? (bool)hints[EncodeHintType.DISABLE_ECI] : false); if (!eciIsExplicitDisabled) { appendECI(eci, headerBits); } } } // (With ECI in place,) Write the mode marker appendModeInfo(mode, headerBits); // Collect data within the main segment, separately, to count its size if needed. Don't add it to // main payload yet. BitArray dataBits = new BitArray(); appendBytes(content, mode, dataBits, encoding); // Hard part: need to know version to know how many bits length takes. But need to know how many // bits it takes to know version. First we take a guess at version by assuming version will be // the minimum, 1: int provisionalBitsNeeded = headerBits.Size + mode.getCharacterCountBits(Version.getVersionForNumber(1)) + dataBits.Size; Version provisionalVersion = chooseVersion(provisionalBitsNeeded, ecLevel); // Use that guess to calculate the right version. I am still not sure this works in 100% of cases. int bitsNeeded = headerBits.Size + mode.getCharacterCountBits(provisionalVersion) + dataBits.Size; Version version = chooseVersion(bitsNeeded, ecLevel); BitArray headerAndDataBits = new BitArray(); headerAndDataBits.appendBitArray(headerBits); // Find "length" of main segment and write it int numLetters = mode == Mode.BYTE ? dataBits.SizeInBytes : content.Length; appendLengthInfo(numLetters, version, mode, headerAndDataBits); // Put data together into the overall payload headerAndDataBits.appendBitArray(dataBits); Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); int numDataBytes = version.TotalCodewords - ecBlocks.TotalECCodewords; // Terminate the bits properly. terminateBits(numDataBytes, headerAndDataBits); // Interleave data bits with error correction code. BitArray finalBits = interleaveWithECBytes(headerAndDataBits, version.TotalCodewords, numDataBytes, ecBlocks.NumBlocks); QRCode qrCode = new QRCode { ECLevel = ecLevel, Mode = mode, Version = version }; // Choose the mask pattern and set to "qrCode". int dimension = version.DimensionForVersion; ByteMatrix matrix = new ByteMatrix(dimension, dimension); int maskPattern = chooseMaskPattern(finalBits, ecLevel, version, matrix); qrCode.MaskPattern = maskPattern; // Build the matrix and set it to "qrCode". MatrixUtil.buildMatrix(finalBits, ecLevel, version, maskPattern, matrix); qrCode.Matrix = matrix; return qrCode; }
/// <summary> /// Encodes the string minimally /// </summary> /// <param name="stringToEncode">The string to encode</param> /// <param name="version">The preferred <see cref="Version"/>. A minimal version is computed(see /// {@link ResultList#getVersion method} when the value of the argument is null</param> /// <param name="priorityCharset">The preferred { @link Charset}. When the value of the argument is null, the algorithm /// chooses charsets that leads to a minimal representation.Otherwise the algorithm will use the priority /// charset to encode any character in the input that can be encoded by it if the charset is among the /// supported charsets.</param> /// <param name="isGS1">{ @code true} if a FNC1 is to be prepended;{ @code false}otherwise</param> /// <param name="ecLevel">The error correction level.</param> /// <returns>An instance of { @code ResultList} /// representing the minimal solution. /// @see ResultList#getBits /// @see ResultList#getVersion /// @see ResultList#getSize</returns> public static ResultList encode(String stringToEncode, Version version, Encoding priorityCharset, bool isGS1, ErrorCorrectionLevel ecLevel) { return(new MinimalEncoder(stringToEncode, priorityCharset, isGS1, ecLevel).encode(version)); }