コード例 #1
0
        public static QrCode EncodeText(string text, Ecc ecl)
        {
            Utils.CheckNull(text, nameof(text));

            var segs = QrSegment.MakeSegments(text);

            return(EncodeSegments(segs, ecl));
        }
コード例 #2
0
        /// <summary>
        /// Creates a QR code representing the specified text using the specified error correction level.
        /// <para>
        /// As a conservative upper bound, this function is guaranteed to succeed for strings with up to 738
        /// Unicode code points (not UTF-16 code units) if the low error correction level is used. The smallest possible
        /// QR code version (size) is automatically chosen. The resulting ECC level will be higher than the one
        /// specified if it can be achieved without increasing the size (version).
        /// </para>
        /// </summary>
        /// <param name="text">The text to be encoded. The full range of Unicode characters may be used.</param>
        /// <param name="ecl">The minimum error correction level to use.</param>
        /// <returns>The created QR code instance representing the specified text.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="text"/> or <paramref name="ecl"/> is <c>null</c>.</exception>
        /// <exception cref="DataTooLongException">The text is too long to fit in the largest QR code size (version)
        /// at the specified error correction level.</exception>
        public static QrCode EncodeText(string text, Ecc ecl)
        {
            Objects.RequireNonNull(text);
            Objects.RequireNonNull(ecl);
            List <QrSegment> segs = QrSegment.MakeSegments(text);

            return(EncodeSegments(segs, ecl));
        }
コード例 #3
0
        /// <summary>
        /// Creates a QR code representing the specified binary data using the specified error correction level.
        /// <para>
        /// This function encodes the data in the binary segment mode. The maximum number of
        /// bytes allowed is 2953. The smallest possible QR code version is automatically chosen.
        /// The resulting ECC level will be higher than the one specified if it can be achieved without increasing the size (version).
        /// </para>
        /// </summary>
        /// <param name="data">The binary data to encode.</param>
        /// <param name="ecl">The minimum error correction level to use.</param>
        /// <returns>The created QR code representing the specified data.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="data"/> or <paramref name="ecl"/> is <c>null</c>.</exception>
        /// <exception cref="DataTooLongException">The specified data is too long to fit in the largest QR code size (version)
        /// at the specified error correction level.</exception>
        public static QrCode EncodeBinary(byte[] data, Ecc ecl)
        {
            Objects.RequireNonNull(data);
            Objects.RequireNonNull(ecl);
            QrSegment seg = QrSegment.MakeBytes(data);

            return(EncodeSegments(new List <QrSegment> {
                seg
            }, ecl));
        }
コード例 #4
0
        private static List <QrSegment> SplitIntoSegments(int[] codePoints, Mode[] charModes)
        {
            if (codePoints.Length == 0)
            {
                throw new ArgumentException();
            }

            var result = new List <QrSegment>();

            // Accumulate run of modes
            var curMode = charModes[0];
            int start   = 0;

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

                var s = FromCodePoint(codePoints, start, i - start);
                if (curMode == Mode.BYTE)
                {
                    result.Add(QrSegment.MakeBytes(Encoding.UTF8.GetBytes(s)));
                }
                else if (curMode == Mode.NUMERIC)
                {
                    result.Add(QrSegment.MakeNumeric(s));
                }
                else if (curMode == Mode.ALPHANUMERIC)
                {
                    result.Add(QrSegment.MakeAlphanumeric(s));
                }
                else if (curMode == Mode.KANJI)
                {
                    result.Add(MakeKanji(s));
                }
                else
                {
                    throw new ApplicationException();
                }

                if (i >= codePoints.Length)
                {
                    return(result);
                }
                curMode = charModes[i];
                start   = i;
            }
        }
コード例 #5
0
        public static List <QrSegment> MakeSegmentsOptimally(string text, Ecc ecl, int minVersion, int maxVersion)
        {
            Utils.CheckNull(text, nameof(text));

            if (!(QrCode.MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= QrCode.MAX_VERSION))
            {
                throw new ArgumentException("Invalid value");
            }

            List <QrSegment> segs = null;
            var codePoints        = ToCodePoints(text);

            for (int version = minVersion; ; version++)
            {
                if (version == minVersion || version == 10 || version == 27)
                {
                    segs = MakeSegmentsOptimally(codePoints, version);
                }

                var dataCapacityBits = QrCode.GetNumDataCodewords(version, ecl) * 8;
                var dataUsedBits     = QrSegment.GetTotalBits(segs, version);
                if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
                {
                    return(segs);
                }
                if (version >= maxVersion)
                {
                    var msg = "Segment too long";
                    if (dataUsedBits != -1)
                    {
                        msg = String.Format("Data length = {0} bits, Max capacity = {1} bits", dataUsedBits, dataCapacityBits);
                    }
                    throw new DataTooLongException(msg);
                }
            }
        }
コード例 #6
0
        /// <summary>
        /// Creates a QR code representing the specified segments with the specified encoding parameters.
        /// <para>
        /// The smallest possible QR code version (size) is used. The range of versions can be
        /// restricted by the <paramref name="minVersion"/> and <paramref name="maxVersion"/> parameters.
        /// </para>
        /// <para>
        /// If <paramref name="boostEcl"/> is <c>true</c>, the resulting ECC level will be higher than the
        /// one specified if it can be achieved without increasing the size (version).
        /// </para>
        /// <para>
        /// The QR code mask is usually automatically chosen. It can be explicitly set with the <paramref name="mask"/>
        /// parameter by using a value between 0 to 7 (inclusive). -1 is for automatic mode (which may be slow).
        /// </para>
        /// <para>
        /// This function allows the user to create a custom sequence of segments that switches
        /// between modes (such as alphanumeric and byte) to encode text in less space and gives full control over all
        /// encoding paramters.
        /// </para>
        /// </summary>
        /// <remarks>
        /// This is a mid-level API; the high-level APIs are <see cref="EncodeText(string, Ecc)"/>
        /// and <see cref="EncodeBinary(byte[], Ecc)"/>.
        /// </remarks>
        /// <param name="segments">The segments to encode.</param>
        /// <param name="ecl">The minimal or fixed 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>
        /// <param name="mask">The mask number to use (between 0 and 7), or -1 for automatic mask selection.</param>
        /// <param name="boostEcl">If <c>true</c> the ECC level wil be increased if it can be achieved without increasing the size (version).</param>
        /// <returns>The created QR code representing the segments.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="segments"/>, any list element, or <paramref name="ecl"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentOutOfRangeException">1 &#x2264; minVersion &#x2264; maxVersion &#x2264; 40
        /// or -1 &#x2264; mask &#x2264; 7 is violated.</exception>
        /// <exception cref="DataTooLongException">The segments are too long to fit in the largest QR code size (version)
        /// at the specified error correction level.</exception>
        public static QrCode EncodeSegments(List <QrSegment> segments, Ecc ecl, int minVersion = MinVersion, int maxVersion = MaxVersion, int mask = -1, bool boostEcl = true)
        {
            Objects.RequireNonNull(segments);
            Objects.RequireNonNull(ecl);
            if (minVersion < MinVersion || minVersion > maxVersion)
            {
                throw new ArgumentOutOfRangeException(nameof(minVersion), "Invalid value");
            }
            if (maxVersion > MaxVersion)
            {
                throw new ArgumentOutOfRangeException(nameof(maxVersion), "Invalid value");
            }
            if (mask < -1 || mask > 7)
            {
                throw new ArgumentOutOfRangeException(nameof(mask), "Invalid value");
            }

            // Find the minimal version number to use
            int version, dataUsedBits;

            for (version = minVersion; ; version++)
            {
                int numDataBits = GetNumDataCodewords(version, ecl) * 8;  // Number of data bits available
                dataUsedBits = QrSegment.GetTotalBits(segments, version);
                if (dataUsedBits != -1 && dataUsedBits <= numDataBits)
                {
                    break;  // This version number is found to be suitable
                }

                if (version >= maxVersion)
                {  // All versions in the range could not fit the given data
                    string msg = "Segment too long";
                    if (dataUsedBits != -1)
                    {
                        msg = $"Data length = {dataUsedBits} bits, Max capacity = {numDataBits} bits";
                    }

                    throw new DataTooLongException(msg);
                }
            }
            Debug.Assert(dataUsedBits != -1);

            // Increase the error correction level while the data still fits in the current version number
            foreach (Ecc newEcl in Ecc.AllValues)
            {  // From low to high
                if (boostEcl && dataUsedBits <= GetNumDataCodewords(version, newEcl) * 8)
                {
                    ecl = newEcl;
                }
            }

            // Concatenate all segments to create the data bit string
            BitArray ba = new BitArray(0);

            foreach (QrSegment seg in segments)
            {
                ba.AppendBits(seg.EncodingMode.ModeBits, 4);
                ba.AppendBits((uint)seg.NumChars, seg.EncodingMode.NumCharCountBits(version));
                ba.AppendData(seg.GetData());
            }
            Debug.Assert(ba.Length == dataUsedBits);

            // Add terminator and pad up to a byte if applicable
            int dataCapacityBits = GetNumDataCodewords(version, ecl) * 8;

            Debug.Assert(ba.Length <= dataCapacityBits);
            ba.AppendBits(0, Math.Min(4, dataCapacityBits - ba.Length));
            ba.AppendBits(0, (8 - ba.Length % 8) % 8);
            Debug.Assert(ba.Length % 8 == 0);

            // Pad with alternating bytes until data capacity is reached
            for (uint padByte = 0xEC; ba.Length < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
            {
                ba.AppendBits(padByte, 8);
            }

            // Pack bits into bytes in big endian
            byte[] dataCodewords = new byte[ba.Length / 8];
            for (int i = 0; i < ba.Length; i++)
            {
                if (ba.Get(i))
                {
                    dataCodewords[i >> 3] |= (byte)(1 << (7 - (i & 7)));
                }
            }

            // Create the QR code object
            return(new QrCode(version, ecl, dataCodewords, mask));
        }
コード例 #7
0
        public static QrCode EncodeSegments(List <QrSegment> segs, Ecc ecl, int minVersion, int maxVersion, int mask, bool boostEcl)
        {
            Utils.CheckNull(segs, nameof(segs));

            if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
            {
                throw new ArgumentException("Invalid value");
            }

            int version, dataUsedBits;

            for (version = minVersion; ; version++)
            {
                var capacityBits = GetNumDataCodewords(version, ecl) * 8;
                dataUsedBits = QrSegment.GetTotalBits(segs, version);
                if (dataUsedBits != -1 && dataUsedBits <= capacityBits)
                {
                    break;
                }

                if (version >= maxVersion)
                {
                    var msg = "Segment too long";
                    if (dataUsedBits != -1)
                    {
                        msg = string.Format("Data length = {0} bits, Max capacity = {1} bits", dataUsedBits, capacityBits);
                    }
                    throw new DataTooLongException(msg);
                }
            }

            foreach (var newEcl in new Ecc[] { Ecc.Low, Ecc.Medium, Ecc.Quartitle, Ecc.High })
            {
                if (boostEcl && dataUsedBits <= GetNumDataCodewords(version, newEcl) * 8)
                {
                    ecl = newEcl;
                }
            }

            var bb = new BitBuffer();

            foreach (var seg in segs)
            {
                bb.AppendBits(seg.Mode.ModeBits, 4);
                bb.AppendBits(seg.NumChars, seg.Mode.NumCharCountBits(version));
                bb.AppendData(seg.Data);
            }

            var dataCapacityBits = GetNumDataCodewords(version, ecl) * 8;

            bb.AppendBits(0, Math.Min(4, dataCapacityBits - bb.Length));
            bb.AppendBits(0, (8 - bb.Length % 8) % 8);

            for (var padByte = 0xEC; bb.Length < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
            {
                bb.AppendBits(padByte, 8);
            }

            var dataCodewords = new byte[bb.Length / 8];

            for (var i = 0; i < bb.Length; i++)
            {
                dataCodewords[i >> 3] = (byte)(dataCodewords[i >> 3] | bb.GetBit(i) << (7 - (i & 7)));
            }

            // Create the QR Code object
            return(new QrCode(version, ecl, dataCodewords, mask));
        }