如何用iTextSharp生成的QR条码对中文文本进行编码? [英] How to encode Chinese text in QR barcodes generated with iTextSharp?

查看:337
本文介绍了如何用iTextSharp生成的QR条码对中文文本进行编码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用iTextSharp在PDF文件中绘制QR条形码。如果我使用英文文本条形码很好,它们会被正确解码,但如果我使用中文文本,条形码会被解码为问号。例如,该字符'测'(\ u6D4B)被解码为'?'。我尝试了所有支持的字符集,但没有一个帮助。

我应该使用iTextSharp中QR条码的哪些参数组合才能正确编码中文文本?

I'm trying to draw QR barcodes in a PDF file using iTextSharp. If I'm using English text the barcodes are fine, they are decoded properly, but if I'm using Chinese text, the barcode is decoded as question marks. For example this character '测' (\u6D4B) is decoded as '?'. I tried all supported character sets, but none of them helped.
What combination of parameters should I use for the QR barcode in iTextSharp in order to encode correctly Chinese text?

推荐答案

iText和iTextSharp显然本身不支持此功能,但您可以编写一些代码来自行处理。诀窍是让QR代码解析器只使用任意字节数组而不是字符串。真正好的是iTextSharp代码几乎已经准备就绪,但没有公开功能。不幸的是,许多必需的类都是密封,所以你不能只是将它们子类化,你必须重新创建它们。您可以下载整个源并添加这些更改,也可以只创建具有相同名称的单独类。 (请检查许可证以确保您可以这样做。)我在下面的更改没有任何错误更正,所以请确保您也这样做。

iText and iTextSharp apparently don't natively support this but you can write some code to handle this on your own. The trick is to get the QR code parser to work with just an arbitrary byte array instead of a string. What's really nice is that the iTextSharp code is almost ready for this but doesn't expose the functionality. Unfortunately many of the required classes are sealed so you can't just subclass them, you'll have to recreate them. You can either download the entire source and add these changes or just create separate classes with the same names. (Please check over the license to make sure you are allowed to do this.) My changes below don't have any error correction so make sure you do that, too.

您需要重新创建的第一个类是 iTextSharp.text.pdf.qrcode.BlockPair 并且您需要进行的唯一更改make是使构造函数 public 而不是 internal 。 (如果您要创建自己的代码而不修改现有代码,则只需执行此操作。)

The first class that you'll need to recreate is iTextSharp.text.pdf.qrcode.BlockPair and the only change you'll need to make is to make the constructor public instead of internal. (You only need to do this if you are creating your own code and not modifying the existing code.)

第二个类是 iTextSharp.text.pdf.qrcode.Encoder 。这是我们将做出最大改变的地方。添加一个重载到 Append8BitBytes ,如下所示:

The second class is iTextSharp.text.pdf.qrcode.Encoder. This is where we'll make the most changes. Add an overload to Append8BitBytes that looks like this:

static void Append8BitBytes(byte[] bytes, BitVector bits) {
    for (int i = 0; i < bytes.Length; ++i) {
        bits.AppendBits(bytes[i], 8);
    }
}

此方法的字符串版本将文本转换为字节数组,然后使用上面所以我们只是切断了中间人。接下来,向构造函数添加一个新的重载,它接受一个字节数组而不是字符串。然后我们将切断字符串检测部分并强制系统进入字节模式,否则下面的代码几乎相同。

The string version of this method converts text to a byte array and then uses the above so we're just cutting out the middle man. Next, add a new overload to the constructor that takes in a byte array instead of a string. We'll then just cut out the string detection part and force the system to byte-mode, otherwise the code below is pretty much the same.

    public static void Encode(byte[] bytes, ErrorCorrectionLevel ecLevel, IDictionary<EncodeHintType, Object> hints, QRCode qrCode) {
        String encoding = DEFAULT_BYTE_MODE_ENCODING;

        // Step 1: Choose the mode (encoding).
        Mode mode = Mode.BYTE;

        // Step 2: Append "bytes" into "dataBits" in appropriate encoding.
        BitVector dataBits = new BitVector();
        Append8BitBytes(bytes, dataBits);

        // Step 3: Initialize QR code that can contain "dataBits".
        int numInputBytes = dataBits.SizeInBytes();
        InitQRCode(numInputBytes, ecLevel, mode, qrCode);

        // Step 4: Build another bit vector that contains header and data.
        BitVector headerAndDataBits = new BitVector();

        // Step 4.5: Append ECI message if applicable
        if (mode == Mode.BYTE && !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding)) {
            CharacterSetECI eci = CharacterSetECI.GetCharacterSetECIByName(encoding);
            if (eci != null) {
                AppendECI(eci, headerAndDataBits);
            }
        }

        AppendModeInfo(mode, headerAndDataBits);

        int numLetters = dataBits.SizeInBytes();
        AppendLengthInfo(numLetters, qrCode.GetVersion(), mode, headerAndDataBits);
        headerAndDataBits.AppendBitVector(dataBits);

        // Step 5: Terminate the bits properly.
        TerminateBits(qrCode.GetNumDataBytes(), headerAndDataBits);

        // Step 6: Interleave data bits with error correction code.
        BitVector finalBits = new BitVector();
        InterleaveWithECBytes(headerAndDataBits, qrCode.GetNumTotalBytes(), qrCode.GetNumDataBytes(),
            qrCode.GetNumRSBlocks(), finalBits);

        // Step 7: Choose the mask pattern and set to "qrCode".
        ByteMatrix matrix = new ByteMatrix(qrCode.GetMatrixWidth(), qrCode.GetMatrixWidth());
        qrCode.SetMaskPattern(ChooseMaskPattern(finalBits, qrCode.GetECLevel(), qrCode.GetVersion(),
            matrix));

        // Step 8.  Build the matrix and set it to "qrCode".
        MatrixUtil.BuildMatrix(finalBits, qrCode.GetECLevel(), qrCode.GetVersion(),
            qrCode.GetMaskPattern(), matrix);
        qrCode.SetMatrix(matrix);
        // Step 9.  Make sure we have a valid QR Code.
        if (!qrCode.IsValid()) {
            throw new WriterException("Invalid QR code: " + qrCode.ToString());
        }
    }

第三类是 iTextSharp.text.pdf.qrcode.QRCodeWriter 再一次我们只需要添加一个重载的 Encode 方法支持一个字节数组和调用是上面创建的新构造函数:

The third class is iTextSharp.text.pdf.qrcode.QRCodeWriter and once again we just need to add an overloaded Encode method supports a byte array and that calls are new constructor created above:

    public ByteMatrix Encode(byte[] bytes, int width, int height, IDictionary<EncodeHintType, Object> hints) {
        ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L;
        if (hints != null && hints.ContainsKey(EncodeHintType.ERROR_CORRECTION))
            errorCorrectionLevel = (ErrorCorrectionLevel)hints[EncodeHintType.ERROR_CORRECTION];

        QRCode code = new QRCode();
        Encoder.Encode(bytes, errorCorrectionLevel, hints, code);
        return RenderResult(code, width, height);
    }

最后一个类是 iTextSharp.text.pdf .BarcodeQRCode 我们再次添加新的构造函数重载:

The last class is iTextSharp.text.pdf.BarcodeQRCode which we once again add our new constructor overload:

    public BarcodeQRCode(byte[] bytes, int width, int height, IDictionary<EncodeHintType, Object> hints) {
        newCode.QRCodeWriter qc = new newCode.QRCodeWriter();
        bm = qc.Encode(bytes, width, height, hints);
    }

最后一招是确保在调用时包含字节顺序标记(BOM),以便解码器知道正确解码,在这种情况下UTF-8。

The last trick is to make sure when calling this that you include the byte order mark (BOM) so that decoders know to decode this properly, in this case UTF-8.

//Create an encoder that supports outputting a BOM
System.Text.Encoding enc = new System.Text.UTF8Encoding(true, true);

//Get the BOM
byte[] bom = enc.GetPreamble();

//Get the raw bytes for the string
byte[] bytes = enc.GetBytes("测");

//Combine the byte arrays
byte[] final = new byte[bom.Length + bytes.Length];
System.Buffer.BlockCopy(bom, 0, final, 0, bom.Length);
System.Buffer.BlockCopy(bytes, 0, final, bom.Length, bytes.Length);

//Create are barcode using our new constructor
var q = new BarcodeQRCode(final, 100, 100, null);

//Add it to the document
doc.Add(q.GetImage());

这篇关于如何用iTextSharp生成的QR条码对中文文本进行编码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆