/// <summary> /// appends the bits /// </summary> /// <param name="bits"></param> public void getBits(BitArray bits) { bits.appendBits(mode.Bits, 4); if (characterLength > 0) { int length = CharacterCountIndicator; bits.appendBits(length, mode.getCharacterCountBits(resultList.version)); } if (mode == Mode.ECI) { bits.appendBits(CharacterSetECI.getCharacterSetECI(encoder.encoders[charsetEncoderIndex]).Value, 8); } else if (characterLength > 0) { // append data Encoder.appendBytes(encoder.stringToEncode.Substring(fromPosition, characterLength), mode, bits, encoder.encoders[charsetEncoderIndex]); } }
/// <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) { Version version; BitArray headerAndDataBits; Mode mode; var hasGS1FormatHint = hints != null && hints.ContainsKey(EncodeHintType.GS1_FORMAT) && hints[EncodeHintType.GS1_FORMAT] != null && Convert.ToBoolean(hints[EncodeHintType.GS1_FORMAT].ToString()); var hasCompactionHint = hints != null && hints.ContainsKey(EncodeHintType.QR_COMPACT) && hints[EncodeHintType.QR_COMPACT] != null && Convert.ToBoolean(hints[EncodeHintType.QR_COMPACT].ToString()); // Determine what character encoding has been specified by the caller, if any bool hasEncodingHint = hints != null && hints.ContainsKey(EncodeHintType.CHARACTER_SET); var encoding = StringUtils.PLATFORM_DEFAULT_ENCODING_T; // 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; if (hasCompactionHint) { mode = Mode.BYTE; var priorityEncoding = encoding.Equals(DEFAULT_BYTE_MODE_ENCODING) ? null : encoding; var rn = MinimalEncoder.encode(content, null, priorityEncoding, hasGS1FormatHint, ecLevel); headerAndDataBits = new BitArray(); rn.getBits(headerAndDataBits); version = rn.getVersion(); } else { // 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. 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.getCharacterSetECI(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 if (hasGS1FormatHint) { // 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); 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); } 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); // Enable manual selection of the pattern to be used via hint var maskPattern = -1; if (hints != null && hints.ContainsKey(EncodeHintType.QR_MASK_PATTERN)) { var hintMaskPattern = Int32.Parse(hints[EncodeHintType.QR_MASK_PATTERN].ToString()); maskPattern = QRCode.isValidMaskPattern(hintMaskPattern) ? hintMaskPattern : -1; } if (maskPattern == -1) { 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> /// Convert the text represented by this High Level Encoder into a BitArray. /// </summary> /// <returns>text represented by this encoder encoded as a <see cref="BitArray"/></returns> public BitArray encode() { State initialState = State.INITIAL_STATE; if (encoding != null && !disableEci) { CharacterSetECI eci = CharacterSetECI.getCharacterSetECI(encoding); if (null == eci) { throw new ArgumentException("No ECI code for character set " + encoding.WebName); } initialState = initialState.appendFLGn(eci.Value); } ICollection <State> states = new Collection <State>(); states.Add(initialState); for (int index = 0; index < text.Length; index++) { int pairCode; // don't remove the (int) type cast, mono compiler needs it int nextChar = (index + 1 < text.Length) ? (int)text[index + 1] : 0; switch (text[index]) { case (byte)'\r': pairCode = nextChar == '\n' ? 2 : 0; break; case (byte)'.': pairCode = nextChar == ' ' ? 3 : 0; break; case (byte)',': pairCode = nextChar == ' ' ? 4 : 0; break; case (byte)':': pairCode = nextChar == ' ' ? 5 : 0; break; default: pairCode = 0; break; } if (pairCode > 0) { // We have one of the four special PUNCT pairs. Treat them specially. // Get a new set of states for the two new characters. states = updateStateListForPair(states, index, pairCode); index++; } else { // Get a new set of states for the new character. states = updateStateListForChar(states, index); } } // We are left with a set of states. Find the shortest one. State minState = null; foreach (var state in states) { if (minState == null) { minState = state; } else { if (state.BitCount < minState.BitCount) { minState = state; } } } /* * State minState = Collections.min(states, new Comparator<State>() { * @Override * public int compare(State a, State b) { * return a.getBitCount() - b.getBitCount(); * } * }); */ // Convert it to a bit array, and return. return(minState.toBitArray(text)); }
/// <summary> /// Performs high-level encoding of a PDF417 message using the algorithm described in annex P /// of ISO/IEC 15438:2001(E). If byte compaction has been selected, then only byte compaction /// is used. /// </summary> /// <param name="msg">the message</param> /// <param name="compaction">compaction mode to use</param> /// <param name="encoding">character encoding used to encode in default or byte compaction /// or null for default / not applicable</param> /// <param name="disableEci">if true, don't add an ECI segment for different encodings than default</param> /// <returns>the encoded message (the char values range from 0 to 928)</returns> internal static String encodeHighLevel(String msg, Compaction compaction, Encoding encoding, bool disableEci) { //the codewords 0..928 are encoded as Unicode characters var sb = new StringBuilder(msg.Length); if (encoding != null && !disableEci && String.Compare(DEFAULT_ENCODING_NAME, encoding.WebName.ToUpper(), StringComparison.Ordinal) != 0) { CharacterSetECI eci = CharacterSetECI.getCharacterSetECI(encoding); if (eci != null) { encodingECI(eci.Value, sb); } } int len = msg.Length; int p = 0; int textSubMode = SUBMODE_ALPHA; // User selected encoding mode switch (compaction) { case Compaction.TEXT: encodeText(msg, p, len, sb, textSubMode); break; case Compaction.BYTE: var msgBytes = toBytes(msg, encoding); encodeBinary(msgBytes, p, msgBytes.Length, BYTE_COMPACTION, sb); break; case Compaction.NUMERIC: sb.Append((char)LATCH_TO_NUMERIC); encodeNumeric(msg, p, len, sb); break; default: int encodingMode = TEXT_COMPACTION; //Default mode, see 4.4.2.1 byte[] bytes = null; while (p < len) { int n = determineConsecutiveDigitCount(msg, p); if (n >= 13) { sb.Append((char)LATCH_TO_NUMERIC); encodingMode = NUMERIC_COMPACTION; textSubMode = SUBMODE_ALPHA; //Reset after latch encodeNumeric(msg, p, n, sb); p += n; } else { int t = determineConsecutiveTextCount(msg, p); if (t >= 5 || n == len) { if (encodingMode != TEXT_COMPACTION) { sb.Append((char)LATCH_TO_TEXT); encodingMode = TEXT_COMPACTION; textSubMode = SUBMODE_ALPHA; //start with submode alpha after latch } textSubMode = encodeText(msg, p, t, sb, textSubMode); p += t; } else { if (bytes == null) { bytes = toBytes(msg, encoding); } int byteCount; int b = determineConsecutiveBinaryCount(msg, bytes, p, encoding, out byteCount); if (b == 0) { b = 1; } if (b == 1 && byteCount == 1 && encodingMode == TEXT_COMPACTION) { //Switch for one byte (instead of latch) encodeBinary(bytes, 0, 1, TEXT_COMPACTION, sb); } else { //Mode latch performed by encodeBinary() encodeBinary(bytes, toBytes(msg.Substring(0, p), encoding).Length, toBytes(msg.Substring(p, b), encoding).Length, encodingMode, sb); encodingMode = BYTE_COMPACTION; textSubMode = SUBMODE_ALPHA; //Reset after latch } p += b; } } } break; } return(sb.ToString()); }