/// <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]);
     }
 }
Example #2
0
        /// <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));
        }
Example #4
0
        /// <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());
        }