在 QR 码符号中编码 UTF-8 字符

Encoding UTF-8 characters in QR Code symbols

从 iOS 7 开始,可以通过 Core Image 框架的名为 CIQRCodeGeneratorCIFilter 生成 QR 码。

通过查看文档,Apple 指出用于生成 QR 码的字符串必须使用 NSISOLatin1StringEncoding 编码。

To create a QR code from a string or URL, convert it to an NSData object using the NSISOLatin1StringEncoding string encoding.

不过,我尝试用NSUTF8StringEncoding编码汉字,效果很好。你认为我使用 NSUTF8StringEncoding 会有问题吗?有任何已知问题吗?

以下是一般性建议,了解 Core Image 框架的人可能会提供更具体的答案。尽管如此,我希望它能阐明为什么库会提供此类特定的编码建议、忽略该建议的可能后果,以及您如何对 Latin-1 无法使用的字符进行编码。

一般来说,QR 码的 ISO/IEC 18004 标准(“QR 码 2005”)和所有其他二维条码国际标准都指定在解释时必须使用 Latin-1 字符编码读取器返回的 QR 代码字节序列,除非在数据中提供了指定替代字符编码的扩展通道解释 (ECI) 序列。

然而,用户使用 UTF-8 对数据进行编码非常普遍,以至于实际上大多数条形码阅读器都使用专有的启发式算法来猜测内容是否根据某些格式进行了编码Latin-1 以外的其他编码,例如 UTF-8。在许多情况下,这会导致歧义并导致误读,尤其是在打开的应用程序中使用任意数据时。

如果要求严谨,要求数据使用UTF-8编码,那么编码库需要支持在UTF-8数据前设置ECI 000026。

2020 年编辑: 我写了一篇详细的文章,准确描述了这个问题以及标准机构目前为促进使用 ECI 所做的工作:https://www.linkedin.com/pulse/enhanced-channel-interpretation-terry-burton/

已分配的 ECI 代码的寄存器可从 AIM 商店以 "ECI Part 3: Register" 的形式付费获得。

[*] CIQRCodeGenerator 似乎不是这种情况。

“ISO-8859-1”是二维码的默认编码。

在二维码中有 4 种存储文本的模式:

  • 数字 (0-9);
  • 字母数字(数字加大写字母 A-Z,space 和八个标点字符)– 总共 45 个字符;
  • 8 位(默认为“ISO-8859-1”编码文本);
  • 汉字(“Shift_JIS”编码的 JIS X 0208 字符,范围为​​ 8140 - 9FFC 和 E040-EBBF)。

这就是 NSISOLatin1StringEncoding 用于 CIQRCodeGenerator 的原因 – 以适应 QR 码中的 8 位文本编码模式,因为“ISO-8859-1”是 QR 码中的默认编码.

要在 8 位字符串中使用 UTF-8 编码而不是默认的“ISO-8859-1”,实现必须在字符串之前插入 ECI(扩展通道解释)。

ECI 是 QR 码的可选附加功能。 ECI 启用使用默认字符集以外的字符集进行数据编码。它还支持对其他数据解释(例如,使用定义的压缩方案压缩数据)或其他行业特定要求进行编码。

ECI 协议在 AIM ECI 规范中有完整定义(由 AIM, Inc 开发 - 20399 Route 19, Suite 203, Cranberry Township, Pennsylvania 16066 USA)。它是与 QR 码规范不同的规范。 ECI 协议提供了一种方法来指定打印前和解码后字节值的特定解释。该规格可在 https://www.aimglobal.org/technical-symbology.html

以 50 美元的价格购买

不幸的是,并非所有 QR 解码器实现都可以处理 ECI 协议,即使是将默认编码更改为 UTF-8 这样的基本操作也是如此。大多数实现使用一种或另一种字符编码检测算法来猜测编码,即使在解码的 QR 码的 ECI 中明确指定了编码。

之所以需要使用检测算法,可能是因为 2000 年发布的初始 QR 码标准 (ISO/IEC 18004:2000) 确实指定了 8 位 Latin/Kana 字符根据 JIS X 0201(JIS8 也称为 ISO-2022-JP)设置为 8 位模式的默认编码,而 2005 年发布的更新标准确实将默认值更改为 ISO-8859-1。

例如,MIUI Global v11.0.3 的小米手机无法正确显示以 UTF-8 编码的西里尔字符字符串,即使此编码是通过 ECI 指定的。西里尔字符显示为问号。但是如果你在西里尔文字中加入一个Chinese/Japanese字符(如日),整个文字小米都能正确显示。

应就 QR 解码器的一组最佳实践达成一致。该集合应规定,如果给出 ECI 扩展以指定字符编码,则不应使用任何字符编码检测算法来覆盖指定的编码。