Esempio n. 1
0
        // Returns a new list of segments based on the given text and modes, such that
        // consecutive code points in the same mode are put into the same segment.
        private static List <QrSegment> SplitIntoSegments(int[] codePoints,
                                                          QrSegment.Mode[] charModes)
        {
            if (codePoints.Length == 0)
            {
                throw new ArgumentOutOfRangeException((codePoints.GetType().Name));
            }
            List <QrSegment> result = new List <QrSegment>();

            // Accumulate run of modes
            QrSegment.Mode curMode = charModes[0];
            int            start   = 0;

            for (int i = 1;; i++)
            {
                if (i < codePoints.Length && charModes[i] == curMode)
                {
                    continue;
                }

                string s = FromCodePoints(codePoints, start, i - start);
                if (curMode == QrSegment.Mode.Byte)
                {
                    result.Add(QrSegment.MakeBytes(Encoding.UTF8.GetBytes(s)));
                }
                else if (curMode == QrSegment.Mode.Numeric)
                {
                    result.Add(QrSegment.MakeNumeric(s));
                }
                else if (curMode == QrSegment.Mode.Alphanumeric)
                {
                    result.Add(QrSegment.MakeAlphanumeric(s));
                }
                else if (curMode == QrSegment.Mode.Kanji)
                {
                    result.Add(MakeKanji(s));
                }
                else
                {
                    Debug.Assert(false);
                }

                if (i >= codePoints.Length)
                {
                    return(result);
                }

                curMode = charModes[i];
                start   = i;
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Creates a list of zero or more segments to represent the specified text string.
        /// The resulting list optimally minimizes the total encoded bit length, subjected to the constraints
        /// of the specified error correction level, minimum and maximum version number.
        /// <para>
        /// This function potentially uses all four text encoding modes: numeric, alphanumeric, byte (UTF-8),
        /// and Kanji. It is a more sophisticated but slower replacement for <see cref="MakeSegments"/>.
        /// </para>
        /// <para>
        /// The text to be encoded can contain the full set of Unicode characters (code points).
        /// </para>
        /// </summary>
        /// <param name="text">The text to be encoded.</param>
        /// <param name="ecl">The error correction level to use.</param>
        /// <param name="minVersion">The minimum version (size) of the QR code (between 1 and 40).</param>
        /// <param name="maxVersion">The maximum version (size) of the QR code (between 1 and 40).</param>
        /// <returns>The created mutable list of segments encoding the specified text with a minimal bit length.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="text"/> or <paramref name="ecl"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentOutOfRangeException">1 &#x2264; minVersion &#x2264; maxVersion &#x2264; 40 is violated.</exception>
        /// <exception cref="DataTooLongException">The text is too long to fit into the QR code with the given encoding parameters.</exception>
        public static List <QrSegment> MakeSegmentsOptimally(string text, QrCode.Ecc ecl, int minVersion, int maxVersion)
        {
            // Check arguments
            Objects.RequireNonNull(text);
            Objects.RequireNonNull(ecl);
            if (minVersion < QrCode.MinVersion || minVersion > maxVersion)
            {
                throw new ArgumentOutOfRangeException(nameof(minVersion), "Invalid value");
            }

            if (maxVersion > QrCode.MaxVersion)
            {
                throw new ArgumentOutOfRangeException(nameof(maxVersion), "Invalid value");
            }

            // Iterate through version numbers, and make tentative segments
            List <QrSegment> segs = null;

            int[] codePoints = ToCodePoints(text);
            for (int version = minVersion;; version++)
            {
                if (version == minVersion || version == 10 || version == 27)
                {
                    segs = MakeSegmentsOptimally(codePoints, version);
                }
                Debug.Assert(segs != null);

                // Check if the segments fit
                int dataCapacityBits = QrCode.GetNumDataCodewords(version, ecl) * 8;
                int dataUsedBits     = QrSegment.GetTotalBits(segs, version);
                if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
                {
                    return(segs); // This version number is found to be suitable
                }
                if (version < maxVersion)
                {
                    continue;
                }

                // All versions in the range could not fit the given text
                string msg = "Segment too long";
                if (dataUsedBits != -1)
                {
                    msg = "Data length = {dataUsedBits} bits, Max capacity = {dataCapacityBits} bits";
                }
                throw new DataTooLongException(msg);
            }
        }