0

我需要从一些文本生成 PDF417 条形码。我有一个 API(我没有创建),它根据数据、行数和列数(以及与问题无关的其他参数)生成 PDF417 条形码。

我的 PDF417 条码使用文本编码。这意味着 1 个代码字最多可容纳 2 个字符。现在,必须固定列数,因为我在非常有限的空间中打印此条形码。

以下是我从本文档中推断出的内容(请参阅第 38 页 - 调整条码大小):

  1. 让每行的码字数,CWPerRow = 7。
  2. 某些给定文本所需的代码字数,ReqCW = strlen(text) / 2。
  3. 所需的行数 = ReqCW / CWPerRow

当我测试上述算法时,没有任何显示。当我在数据非常小且行数 = 25 时使用相同的 API 时,条形码打印得很好(由各种条形码扫描仪验证)。

那么,当列数已知时,如何计算某些给定文本所需的行数?

4

2 回答 2

1

我已经制作了 Markus Jarderot 答案的 Python 端口。计算保持不变。

import string

SUBMODE_ALPHA = string.ascii_uppercase + ' '
SUBMODE_LOWER = string.ascii_lowercase + ' '
SUBMODE_MIXED = "\t\r #$%&*+,-./0123456789:=^"
SUBMODE_PUNCTUATION = "\t\n\r!\"$'()*,-./:;<>?@[\\]_`{|}~"


def calculateNumberOfRows(sourceCodeWords, errorCorrectionCodeWords, columns):
    rows = ((sourceCodeWords + 1 + errorCorrectionCodeWords) / columns) + 1
    if columns * rows >= sourceCodeWords + 1 + errorCorrectionCodeWords + columns:
        rows -= 1
    return rows

def getErrorCorrectionCodewordCount(errorCorrectionLevel):
    if 0 > errorCorrectionLevel > 8:
        raise ValueError("Error correction level must be between 0 and 8!")
    return 1 << (errorCorrectionLevel + 1)


def calculateSourceCodeWords(msg):
    length = 0;
    submode = SUBMODE_ALPHA
    msgLength = len(msg)
    idx = 0
    while(idx < msgLength):
        ch = msg[idx]
        length += 1

        if not ch in submode:
            old_submode = submode
            if submode == SUBMODE_ALPHA:
                for mode in (SUBMODE_LOWER, SUBMODE_MIXED):
                    if ch in mode:
                        submode = mode

            elif submode == SUBMODE_LOWER:
                if ch in SUBMODE_MIXED:
                    submode = SUBMODE_MIXED

            elif submode == SUBMODE_MIXED:
                for mode in (SUBMODE_ALPHA, SUBMODE_LOWER):
                    if ch in mode:
                        submode = mode

                if idx + 1 < len(msg) and msg[idx + 1] in SUBMODE_PUNCTUATION:
                    submode = SUBMODE_PUNCTUATION


            elif submode == SUBMODE_PUNCTUATION:
                submode = SUBMODE_ALPHA

            if old_submode != submode:
                # submode changed
                continue

            length += 1

        idx += 1 # Don't increment if 'continue' was used.
    return (length + 1) / 2


def main():
    msg = "Hello, world!"
    columns = 7
    sourceCodeWords = calculateSourceCodeWords(msg)
    errorCorrectionCodeWords = getErrorCorrectionCodewordCount(0)
    rows = calculateNumberOfRows(sourceCodeWords, errorCorrectionCodeWords, columns)
    print("\"%s\" requires %d code-words, and %d error correction code-words. This becomes %d rows.\n"
           %( msg, sourceCodeWords, errorCorrectionCodeWords, rows))



if __name__ == '__main__':
    main()
于 2014-08-19T12:11:52.210 回答
1

您可以查看一些 PDF417 实现的源代码,例如ZXing

文本编码不仅仅是每个代码字两个字符。如果您使用大写字母和空格以外的任何其他字符,编码器将添加额外的字符来切换字符集等。您确实必须对文本进行编码以查看它将变成多少个代码字。

public class Test
{
    public static void main(String[] args)
    {
        String msg = "Hello, world!";
        int columns = 7;
        int sourceCodeWords = calculateSourceCodeWords(msg);
        int errorCorrectionCodeWords = getErrorCorrectionCodewordCount(0);
        int rows = calculateNumberOfRows(sourceCodeWords, errorCorrectionCodeWords, columns);
        System.out.printf("\"%s\" requires %d code-words, and %d error correction code-words. This becomes %d rows.%n",
                msg, sourceCodeWords, errorCorrectionCodeWords, rows);
    }


    public static int calculateNumberOfRows(int sourceCodeWords, int errorCorrectionCodeWords, int columns) {
        int rows = ((sourceCodeWords + 1 + errorCorrectionCodeWords) / columns) + 1;
        if (columns * rows >= (sourceCodeWords + 1 + errorCorrectionCodeWords + columns)) {
            rows--;
        }
        return rows;
    }

    public static int getErrorCorrectionCodewordCount(int errorCorrectionLevel) {
        if (errorCorrectionLevel < 0 || errorCorrectionLevel > 8) {
            throw new IllegalArgumentException("Error correction level must be between 0 and 8!");
        }
        return 1 << (errorCorrectionLevel + 1);
    }

    private static boolean isAlphaUpper(char ch) {
        return ch == ' ' || (ch >= 'A' && ch <= 'Z');
    }

    private static boolean isAlphaLower(char ch) {
        return ch == ' ' || (ch >= 'a' && ch <= 'z');
    }

    private static boolean isMixed(char ch) {
        return "\t\r #$%&*+,-./0123456789:=^".indexOf(ch) > -1;
    }

    private static boolean isPunctuation(char ch) {
        return "\t\n\r!\"$'()*,-./:;<>?@[\\]_`{|}~".indexOf(ch) > -1;
    }

    private static final int SUBMODE_ALPHA = 0;
    private static final int SUBMODE_LOWER = 1;
    private static final int SUBMODE_MIXED = 2;
    private static final int SUBMODE_PUNCTUATION = 3;

    public static int calculateSourceCodeWords(String msg)
    {
        int len = 0;
        int submode = SUBMODE_ALPHA;
        int msgLength = msg.length();
        for (int idx = 0; idx < msgLength;)
        {
            char ch = msg.charAt(idx);
            switch (submode)
            {
                case SUBMODE_ALPHA:
                    if (isAlphaUpper(ch))
                    {
                        len++;
                    }
                    else
                    {
                        if (isAlphaLower(ch))
                        {
                            submode = SUBMODE_LOWER;
                            len++;
                            continue;
                        }
                        else if (isMixed(ch))
                        {
                            submode = SUBMODE_MIXED;
                            len++;
                            continue;
                        }
                        else
                        {
                            len += 2;
                            break;
                        }
                    }
                    break;
                case SUBMODE_LOWER:
                    if (isAlphaLower(ch))
                    {
                        len++;
                    }
                    else
                    {
                        if (isAlphaUpper(ch))
                        {
                            len += 2;
                            break;
                        }
                        else if (isMixed(ch))
                        {
                            submode = SUBMODE_MIXED;
                            len++;
                            continue;
                        }
                        else
                        {
                            len += 2;
                            break;
                        }
                    }
                    break;
                case SUBMODE_MIXED:
                    if (isMixed(ch))
                    {
                        len++;
                    }
                    else
                    {
                        if (isAlphaUpper(ch))
                        {
                            submode = SUBMODE_ALPHA;
                            len++;
                            continue;
                        }
                        else if (isAlphaLower(ch))
                        {
                            submode = SUBMODE_LOWER;
                            len++;
                            continue;
                        }
                        else
                        {
                            if (idx + 1 < msgLength)
                            {
                                char next = msg.charAt(idx + 1);
                                if (isPunctuation(next))
                                {
                                    submode = SUBMODE_PUNCTUATION;
                                    len++;
                                    continue;
                                }
                            }
                            len += 2;
                        }
                    }
                    break;
                default:
                    if (isPunctuation(ch))
                    {
                        len++;
                    }
                    else
                    {
                        submode = SUBMODE_ALPHA;
                        len++;
                        continue;
                    }
                    break;
            }
            idx++; // Don't increment if 'continue' was used.
        }
        return (len + 1) / 2;
    }
}

输出:

"Hello, world!" requires 9 code-words, and 2 error correction code-words. This becomes 2 rows.

于 2013-06-03T22:47:30.913 回答