【问题标题】:Graphics.DrawString Not Rendering Code128A Font Like the Character MapGraphics.DrawString 不渲染 Code128A 字体喜欢字符映射
【发布时间】:2015-09-11 00:49:51
【问题描述】:

我正在尝试使用 Code128A.ttf 字体生成条形码。多年来,我一直在使用 Delphi 的 Windows 2000 和 2003 中使用相同的字体。但是,当我现在尝试在 Windows 8.x 中将字体与 C# 和 .NET 4.5 一起使用时,所有文本字符似乎都可以工作,但是,开始和停止代码字符的呈现方式与 Windows 字符映射显示的不同他们。

例如:在字符映射中,\u008A 在字符映射中显示了一个漂亮的 Code128 停止码条形码字形。然而,当Graphics.DrawString 渲染它时,该字符看起来像Š“带有caron 的拉丁大写S”。同样,Code128 起始代码 \u0087graphics.DrawString 呈现为 “双匕首”,而不是其字符映射条形码字形。

失败的平台 = Windows.Forms、C#、.NET 4.5、Visual Studio 2013、Windows 8.1 最后一个已知的工作平台是 = Delphi 6 (VCL)/Nevrona RAVE, Windows Server 2003

我希望我只是缺少一个设置或一些简单的东西。

void On_PrintPage(object sender, PrintPageEventArgs ppea)
{
    string sCodeAStart = "\u0087";  // Code128A.ttf's glyph for Start A 103
    string sStopCode = "\u008A";    // Code128A.ttf's glyph for StopCode 106
    int iCheckDigit = MyCheckSumFunction(103, "500014630");
    string sBarcode = sCodeAStart + "500014630" 
                      + ((char)iCheckDigit).ToString() + sStopCode;
    Font fontBarcode = new Font("Code128A", 24, FontStyle.Regular);
    ppea.Graphics.DrawString(sBarcode, fontBarcode, Brushes.Black, 100, 100);
}

已选择停止字符的 Code128A.ttf 字符映射。

DrawString 未正确渲染开始和停止字形

应该是这个样子

【问题讨论】:

  • 添加了示例代码 sn-p。我试过ppea.Graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixel;之类的东西,但它只会改变角色的外观。也许代码页是问题所在。我只是在字符映射中查看字体中字形的索引。我希望 WYSIWYG 像所有其他字体以及它过去的工作方式一样。
  • 我通过将“\u008A”字符粘贴到记事本中测试了 Code128A.ttf 字体,效果很好。所以问题肯定出在 .NET 绘图实现中。我为 new Font(,,,) 参数尝试了六个 byte gdiCharSet 值,没有任何变化。该问题可能与代码页设置有关。如何更改 .NET 图形例程的代码页?如何确定哪个代码页将正确呈现我的 Code128A 字体?
  • System.Text.Encoding 提供了操作代码页和编码/解码字符、字节、字符串等的方法。在测试了几个代码页后,唯一的差异是在 7bit 和 8bit 之间。在 7 位代码页中,开始和停止代码被转换为 7 位并最终成为打印的条形码字符 - 只是不是正确的字符!我认为代码页不是问题;除非我只是不知道哪一个有效。有成千上万的代码页,所以反复试验对我不起作用!
  • 我发现问题是编码问题。 DrawString("‡...Š", ...) 工作! DrawString("\u0087....\u008A", ...)(以及像 \x0087 \u87 \x87 这样的变体)不起作用。我的问题的答案是如何使用 System.Text.Encoding 例程将 (char)135 转换为 "‡"。

标签: c# .net fonts drawstring


【解决方案1】:

这是一个相当神秘的问题。唯一真正的前导是 Unicode 代码点,\u0087 和 \u008A 是控制字符,没有字形。如果您在干净的机器上运行此代码,那么您会看到它们被渲染为矩形。换句话说,在这样的机器上没有一种字体具有它们的字形。

得到的内容,Š 和‡ 不是完全随机的,它们是code page 1252 中字符代码0x87 和0x8A 的字形。

这当然是非常奇怪的行为,Graphics.DrawString() 是一个纯 Unicode 函数,从不考虑像 cp1252 这样的 8 位编码。

唯一合乎逻辑的理论是 Windows 决定为这些控制字符寻找字形。你的机器有另一种字体,它定义了这些代码点。而且,由于某种原因,它比您的条形码字体更喜欢该字体。

因此,您要做的一件事就是寻找该字体并将其卸载。使用 Charmap.exe 应该很容易找到。而且一般怀疑是脏机问题,有一些注册表项会影响字体映射器,可能已经被修改了。

【讨论】:

    【解决方案2】:

    我相信你需要使用这样的字体

    PrivateFontCollection foo = new PrivateFontCollection();
    foo.AddFontFile("code128.ttf");
    // Some more code 
    Font fontBarcode = new Font((System.Drawing.FontFamily)foo.Families[0], 24, fs);
    g.DrawString(sBarcode, fontBarcode, System.Drawing.Brushes.Black, 100, 100);
    

    它创建了这样的图像

    而如果我将 sCodeAStart 和 sStopCode 更改为这样的 Hexa 值

    string sCodeAStart = "0x87"; 
    string sStopCode = "0x8A";  
    

    比输出是这样的

    我已尝试搜索 Code128A 但找不到。所以代码是为 Code128.ttf 编写的。希望这会有所帮助

    【讨论】:

    • 感谢您提供有关如何即时导入字体的出色示例。我的项目中仍然有同样糟糕的结果。我正在使用“c128att.ttf”Code128A 字体(1.0 版,1992 年 10 月 6 日,Rivers Edge)在我原来的问题中,我添加了一个图像,说明一个好的 Code128 条形码的外观。您提供的第二张图片没有显示停止代码(2331112 条/空间权重)。这可能只是由于特定字体文件将哪个字符/字形用于停止代码。您使用的是哪个“Code128.ttf”?
    • 我正在使用Code128 字体来创建这个程序。你可以使用这个。或者您可以使用Zen.Barcode 来创建条形码,以防万一您只是为了创建条形码。
    • 这只会将实际文本放在条形码周围...对于代码“500014630”,您最终会得到一个包含“0x875000146300x8A”的条形码
    【解决方案3】:

    答案很简单:字符映射 Unicode 字符使用“U+####”索引(字符映射应用程序窗口的左下方),而不是单字节字符索引。

    Code128A 中起始代码的 Unicode 字符串是“\u2021”=“‡”(您可以使用美式键盘键入 ALT+0135 来获取该字符串),而不是旧字符索引:“\u0087”、“\ x0087", (char)135 等

    问题是我的代码基于传统 (char)### 单字节字符序数,但是,DrawString 将其字符串处理为多字节字符 (Unicode)。我使用的 Code128A 字体中实际的“\u2021”开始字符和“\u0160”结束字符在其他条形码字体中可能会有所不同。

    换句话说,我对 Graphics.DrawString 的输入字符串不是与字体字符映射匹配的 Unicode。结果是旧的Garbage In = Garbage Out

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-01
      • 2018-12-03
      • 2020-12-06
      • 2020-09-21
      • 2012-02-24
      相关资源
      最近更新 更多