예제 #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;
            }
        }
예제 #2
0
        // Returns a new array representing the optimal mode per code point based on the given text and version.
        private static QrSegment.Mode[] ComputeCharacterModes(int[] codePoints, int version)
        {
            if (codePoints.Length == 0)
            {
                throw new ArgumentOutOfRangeException(nameof(codePoints));
            }

            QrSegment.Mode[] modeTypes = { QrSegment.Mode.Byte, QrSegment.Mode.Alphanumeric, QrSegment.Mode.Numeric, QrSegment.Mode.Kanji }; // Do not modify
            int numModes = modeTypes.Length;

            // Segment header sizes, measured in 1/6 bits
            int[] headCosts = new int[numModes];
            for (int i = 0; i < numModes; i++)
            {
                headCosts[i] = (4 + modeTypes[i].NumCharCountBits(version)) * 6;
            }

            // charModes[i][j] represents the mode to encode the code point at
            // index i such that the final segment ends in modeTypes[j] and the
            // total number of bits is minimized over all possible choices
            QrSegment.Mode[,] charModes = new QrSegment.Mode[codePoints.Length, numModes];

            // At the beginning of each iteration of the loop below,
            // prevCosts[j] is the exact minimum number of 1/6 bits needed to
            // encode the entire string prefix of length i, and end in modeTypes[j]
            int[] prevCosts = (int[])headCosts.Clone();

            // Calculate costs using dynamic programming
            for (int i = 0; i < codePoints.Length; i++)
            {
                int   c        = codePoints[i];
                int[] curCosts = new int[numModes];
                {
                    // Always extend a byte mode segment
                    curCosts[0]     = prevCosts[0] + CountUtf8Bytes(c) * 8 * 6;
                    charModes[i, 0] = modeTypes[0];
                }
                // Extend a segment if possible
                if (QrSegment.AlphanumericCharset.IndexOf((char)c) != -1)
                {
                    // Is alphanumeric
                    curCosts[1]     = prevCosts[1] + 33; // 5.5 bits per alphanumeric char
                    charModes[i, 1] = modeTypes[1];
                }

                if ('0' <= c && c <= '9')
                {
                    // Is numeric
                    curCosts[2]     = prevCosts[2] + 20; // 3.33 bits per digit
                    charModes[i, 2] = modeTypes[2];
                }

                if (IsKanji(c))
                {
                    curCosts[3]     = prevCosts[3] + 78; // 13 bits per Shift JIS char
                    charModes[i, 3] = modeTypes[3];
                }

                // Start new segment at the end to switch modes
                for (int j = 0; j < numModes; j++)
                {
                    // To mode
                    for (int k = 0; k < numModes; k++)
                    {
                        // From mode
                        int newCost = (curCosts[k] + 5) / 6 * 6 + headCosts[j];
                        if (charModes[i, k] == null || charModes[i, j] != null && newCost >= curCosts[j])
                        {
                            continue;
                        }
                        curCosts[j]     = newCost;
                        charModes[i, j] = modeTypes[k];
                    }
                }

                prevCosts = curCosts;
            }

            // Find optimal ending mode
            QrSegment.Mode curMode = null;
            for (int i = 0, minCost = 0; i < numModes; i++)
            {
                if (curMode != null && prevCosts[i] >= minCost)
                {
                    continue;
                }
                minCost = prevCosts[i];
                curMode = modeTypes[i];
            }

            // Get optimal mode for each code point by tracing backwards
            QrSegment.Mode[] result = new QrSegment.Mode[codePoints.Length];
            for (int i = result.Length - 1; i >= 0; i--)
            {
                for (int j = 0; j < numModes; j++)
                {
                    if (modeTypes[j] != curMode)
                    {
                        continue;
                    }
                    curMode   = charModes[i, j];
                    result[i] = curMode;
                    break;
                }
            }

            return(result);
        }