1

许多打印机都有“进纸和剪切”或“剪纸”命令(我说的是 POS - 这里的打印机)。

由于使用 POS.NET 并不总是可行(可怕的驱动程序不兼容),而 GDI 可以做的更多,我们希望在使用 GDI 打印时也使用切纸机。

有没有办法这样做?可能在发出 EndDocument() 时?

或者甚至可能来自.NET?

4

1 回答 1

2

GDI 甚至抽象的 Windows 打印模型在这里都可能对您没有帮助。您将不得不以打印机通常期望接收数据的语言向打印机发送进纸和剪切命令。

例如,Epson TM-T88III 热敏收据打印机本机使用 ESC/POS 语言,而不是 GDI 或 PCL 命令序列。但是,这些打印机中的大多数都带有打印机驱动程序,使 Windows 将它们视为常规 GDI 打印机。这些驱动程序通常的工作方式是将所有 GDI 命令光栅化为软件中的一个大位图,然后通过其本地语言“打印位图”命令将位图分配给打印机进行打印。这通常会产生不太理想的效果:

  • 与打印机知道如何解释的二进制命令序列相比,将大量位图数据发送到打印机的效率要低得多(从所需时间和传输数据的角度来看)。(您更愿意发送要打印的文本图像,还是仅发送实际文本和字体大小规范?HTML/CSS 与文本图像的类比。)
  • 这些打印机通常具有低分辨率并且是单色的(即全黑或全白,没有灰度或彩色)。它们的预加载字体旨在在这些限制下很好地工作,以实现清晰的渲染。通过光栅化为位图,我们失去了这种精心的设计,因为像素被捕捉并从网格四舍五入,导致实际打印输出上呈现锯齿状的文本。如果您尝试绘制对这种舍入非常敏感的东西,例如条形码,那么您就是 SOL,除非您在使用 GDI 时煞费苦心地记住打印机设备上下文的 DPI。

例如,这是我通常不相关的博客上一个广泛示例的代码片段。您可以在接近尾声时看到我如何BinaryWriter在我们的 Epson 热敏收据打印机上填充必要的字节序列,该序列等于“进纸并剪切”命令(AsciiControlChars只是一个带有常量的静态类):

        using (var ms = new MemoryStream())
        using (var bw = new BinaryWriter(ms))
        {
            // Reset the printer bws (NV images are not cleared)
            bw.Write(AsciiControlChars.Escape);
            bw.Write('@');

            // Render the logo
            RenderLogo(bw);

            // Feed 3 vertical motion units and cut the paper with a 1 point cut
            bw.Write(AsciiControlChars.GroupSeparator);
            bw.Write('V');
            bw.Write((byte)66);
            bw.Write((byte)3);

            bw.Flush();

            return ms.ToArray();
        }

然后,您可以直接将字节作为 RAW 文档发送到打印机,或者使用文章末尾的代码,它适用于各种 Win32 打印机功能,或者使用 Microsoft 的RawPrinterHelper 类

您需要查找特定于您的打印机的命令。很可能它与您在这里看到的没有太大区别:POS 语言开始标准化,但这也就像说 SQL 是一种标准——人类可以相互理解,但如果不进行一些调整就不能真正实现互操作。

如果您仍然想使用 GDI,您可以以通常的方式将 GDI 文档打印到打印机(再次假设存在 GDI 打印机驱动程序,它可能确实存在),然后发出第二个小的 RAW 文档到包含本机进纸和剪切命令的打印机。(或者,一些 GDI 打印机驱动程序允许您在打印机控制面板中指定“打印文档后始终剪切”——但祝您以编程方式以有据可查的方式访问该驱动程序功能!)

希望这有助于描绘 GDI 与 POS 打印机的关系。

于 2010-09-08T02:32:23.260 回答