需要一种可以驱动两台打印机的快速编程语言

发布于 2024-10-08 12:41:39 字数 1539 浏览 0 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

黯然#的苍凉 2024-10-15 12:41:39

作为一名 Python 程序员,我会使用类似 MSWinPrint.py 的东西,并直接使用Python。看起来它支持文本和图像,您可以轻松地通过名称选择系统中的任何打印机。

您需要:

  1. 安装Python
  2. 安装Python for Windows 扩展
  3. 安装 PIL
  4. 安装MSWinPrint

然后,您需要编写一个程序来进行打印。像下面这样的东西。

#python
import sys
import Image, ImageWin
import MSWinPrint

# workaround for PIL namespace change
MSWinPrint.ImageWin = ImageWin

def print_name(name, printer_name):
    doc = MSWinPrint.document(printer_name)
    doc.begin_document('nametag for %s' % name)
    # print the name at position 20,20
    text_pos = 20, 20
    doc.text(text_pos, name)
    # add an image for this person
    img_pos = 40, 40
    img_size = 100, 100
    doc.image(img_pos, get_image(), img_size)
    doc.end_document()

def get_image():
    image_filename = 'my image.jpg'
    return Image.open(image_filename)

if __name__ == '__main__':
    name, printer_name = sys.argv[1:]
    print_name(name, printer_name)

如果将其保存为 print_tag.py,则可以使用两个命令行参数(要打印的名称和图像文件名)执行它。

print_tag.py Sally "EPSON Artisan 810"

我运行了这段代码,效果很好。我不知道创建自定义打印作业会如此简单。

当然,您可以在任意数量的打印机上任意频繁地运行该程序。当然,您还可以做更多的事情来自定义打印作业的运行时间和方式。您可以自定义代码以始终运行并解释鼠标单击(为此您可能需要 wxPython),或者您可能有另一个只执行脚本的程序。

Being a Python programmer myself, I would use something like MSWinPrint.py, and render the documents directly using Python. It looks like it supports text and images, and you can easily select any printer in the system by name.

You would need to:

  1. Install Python.
  2. Install Python for Windows Extensions.
  3. Install PIL.
  4. Install MSWinPrint.

Then, you would need to write a program to do the printing. Something like the following.

#python
import sys
import Image, ImageWin
import MSWinPrint

# workaround for PIL namespace change
MSWinPrint.ImageWin = ImageWin

def print_name(name, printer_name):
    doc = MSWinPrint.document(printer_name)
    doc.begin_document('nametag for %s' % name)
    # print the name at position 20,20
    text_pos = 20, 20
    doc.text(text_pos, name)
    # add an image for this person
    img_pos = 40, 40
    img_size = 100, 100
    doc.image(img_pos, get_image(), img_size)
    doc.end_document()

def get_image():
    image_filename = 'my image.jpg'
    return Image.open(image_filename)

if __name__ == '__main__':
    name, printer_name = sys.argv[1:]
    print_name(name, printer_name)

If you save this as print_tag.py, then you can execute it with two command line arguments, the name to be printed and the image filename.

print_tag.py Sally "EPSON Artisan 810"

I ran this code and it worked great. I didn't know creating a custom print job could be so easy.

You can of course run the program as often as you like on as many printers as you would like. There's certainly more you can do to customize when an how the print job is run. You could customize the code to always run and interpret the mouse clicks (for that you might need wxPython), or you might have another program that just executes the script.

蓝海似她心 2024-10-15 12:41:39

正如其他人所说,编程语言不会产生太大的影响。然而(这是一个很大的问题),大多数脚本语言(例如 VBA 和 .NET)中内置的打印库要么只支持打印到系统默认打印机(最常见,并且不能通过同时打开两个实例来解决) ,因为系统默认打印机是全局设置)或要求您配置一个全局变量来指定活动打印机(这仅影响一个进程,因此可以使用两个实例来解决)。

相反,您必须直接调用 Windows API。它肯定允许直接打印到系统上的任何打印机。 以下是如何使用默认打印机的示例。 请注意,仅一行代码(调用 GetDefaultPrinter 函数)将其与默认打印机联系起来。向 CreateDC 提供不同的打印机名称将为您提供不同的打印机。

如果您改为调用 EnumPrinters 函数,您可以找到任何或所有打印机名称,而不仅仅是默认名称。或者让管理员预先配置要在注册表设置或文本文件中使用的打印机名称。

在任何情况下,您都可以同时打开所有打印机的设备上下文。当然,一旦获得打印机设备上下文,您就必须创建打印作业、发送内容并结束打印作业。 MSDN 上提供了大量信息

所有示例均以 C 语言编写,这使得 C++ 成为打印到非默认打印机的明显语言,但只要您知道如何从您的语言调用 WinAPI 函数,您就可以使用它。在 VBA 中,这需要声明 Function XYZ Lib "gdi32"(此处为参数)

As other have said, the programming language isn't going to make much difference. However (and this is a BIG however), the print libraries built into most scripting languages, such as VBA and .NET, either only support printing to the system default printer (most common, and cannot be worked around by having two instances open simultaneously, as the system default printer is a global setting) or require you to configure a global variable to specify the active printer (this only affects one process, so could be worked around using two instances).

Instead, you will have to invoke the windows API directly. It most certainly allows printing directly to any printer on the system. Here is an example of how to use the default printer. Note that only one line of code (calling the GetDefaultPrinter function) ties this to the default printer. Supplying a different printer name to CreateDC gets you a different printer.

If you instead call the EnumPrinters function, you can find out ANY or ALL of the printer names, not just the default. Or have the administrator preconfigure the printer names to use in a registry setting or text file.

In any case, you can have device contexts for all printers open simultaneously. Of course, once you have the printer device context, you have to create a print job, send your content, and end the print job. There's a great deal of information available on MSDN.

All the examples are in C, which makes C++ the obvious language for printing to non-default printers, but as long as you know how to call WinAPI functions from your language, you can use it instead. In VBA, that'd require Declare Function XYZ Lib "gdi32" (params here)

大海や 2024-10-15 12:41:39

这不是编程语言的问题,只是您所使用的打印机堆栈的限制。

我不确定 .NET 是否支持它(或 Windows)是否支持在线程上发送打印。您可以将每台打印机置于其自己的线程中,并阻止 UI 接受更多打印请求。

您还可以尝试为两台打印机打开后台打印。这将在本地渲染它并返回然后打印。

This is not a problem with the programming language, its just a limitation of the printer stack you are using.

I am not sure if .NET would support it (or Windows for that matter) would support sending printing on a thread. You could put each printer in its own thread and block the UI from accepting more print requests.

You could also try to turn on print spooling for both printers. That will render it locally and return then print.

十年九夏 2024-10-15 12:41:39

几年前,我写了一些东西(在 VB6 中,因此可能很容易移植到 VBA),绕过打印机驱动程序(必须设置打印机,但实际使用的驱动程序无关)并向打印机发送原始命令。根据您使用的打印机类型,这可能是也可能不是问题(有些使用复杂的转义序列)。如果您想打印图形,这可能会增加另一层复杂性 - 尽管如果您知道打印机支持哪些命令就可以完成。我设法在点阵打印机上打印位图,但这不是一个 5 分钟的任务。如果您对此感兴趣,我可以尝试挖掘代码吗?

代码如下:

Public Type DOCINFO
          pDocName As String
          pOutputFile As String
          pDatatype As String
      End Type

Declare Function ClosePrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long

Declare Function EndDocPrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long

Declare Function EndPagePrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long

Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal pPrinterName As String, phPrinter As Long, ByVal pDefault As Long) As Long

Declare Function StartDocPrinter Lib "winspool.drv" Alias "StartDocPrinterA" (ByVal hPrinter As Long, ByVal Level As Long, pDocInfo As DOCINFO) As Long

Declare Function StartPagePrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long

Declare Function WritePrinter Lib "winspool.drv" (ByVal hPrinter As Long, pBuf As Any, ByVal cdBuf As Long, pcWritten As Long) As Long

Public Function PrintRawData(ByVal sPrinter As String, ByVal sDocName As String, ByVal sData As String) As Boolean
On Error GoTo PrintErr:

          Dim lhPrinter As Long, lReturn As Long, lpcWritten As Long
          Dim lDoc As Long, sWrittenData As String
          Dim MyDocInfo As DOCINFO
          Dim pOutput As Printer
          Dim p As Printer

            For Each p In Printers
                If p.DeviceName = sPrinter Then
                    Set pOutput = p
                    GoTo StartPrinting
                End If
            Next p

            MsgBox "Unable to find the specified printer [" & sPrinter & _
            "] in the list of currently installed printers" & vbCrLf & _
            "Printing will be aborted", vbCritical
            Exit Function

StartPrinting:
          lReturn = OpenPrinter(pOutput.DeviceName, lhPrinter, 0)

          If lReturn = 0 Then
              MsgBox "Print was unsuccessful. Make sure there is a printer installed on the port you are trying to print to"
              Exit Function
          End If

          MyDocInfo.pDocName = sDocName
          MyDocInfo.pOutputFile = vbNullString
          MyDocInfo.pDatatype = vbNullString
          lDoc = StartDocPrinter(lhPrinter, 1, MyDocInfo)
          Call StartPagePrinter(lhPrinter)

          sWrittenData = sData

          lReturn = WritePrinter(lhPrinter, ByVal sWrittenData, Len(sWrittenData), lpcWritten)
          lReturn = EndPagePrinter(lhPrinter) 'need this??
          lReturn = EndDocPrinter(lhPrinter)
          lReturn = ClosePrinter(lhPrinter)

          Exit Function

PrintErr:
    MsgBox "Print was unsuccessful. Make sure there is a printer installed on the port you are trying to print to"
    Exit Function

End Function

要使用它,您需要使用任何驱动程序安装使用正确端口的打印机(我通常使用通用/仅文本驱动程序),然后按如下方式调用它,将 Hello 替换为您要发送的数据到打印机,包括控制字符等:

PrintRawData "Generic / Text Only", "My Document", "Hello"

I wrote something a few years ago (in VB6 so could probably be ported to VBA easily) that bypassed the printer driver (a printer must be set up but the actual driver used was irrelevant) and sent raw commands to the printer. Depending on what sort of printer you are using this may or may not be an issue (some use complex escape sequences). If you want to print graphics, this could add another layer of complication - although it can be done if you know what commands the printer supports. I managed to get bitmaps printing on a dot matrix printer, but it wasn't a 5 minute task. If this is something you are interested in I can try and dig out the code?

The Code is as follows:

Public Type DOCINFO
          pDocName As String
          pOutputFile As String
          pDatatype As String
      End Type

Declare Function ClosePrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long

Declare Function EndDocPrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long

Declare Function EndPagePrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long

Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal pPrinterName As String, phPrinter As Long, ByVal pDefault As Long) As Long

Declare Function StartDocPrinter Lib "winspool.drv" Alias "StartDocPrinterA" (ByVal hPrinter As Long, ByVal Level As Long, pDocInfo As DOCINFO) As Long

Declare Function StartPagePrinter Lib "winspool.drv" (ByVal hPrinter As Long) As Long

Declare Function WritePrinter Lib "winspool.drv" (ByVal hPrinter As Long, pBuf As Any, ByVal cdBuf As Long, pcWritten As Long) As Long

Public Function PrintRawData(ByVal sPrinter As String, ByVal sDocName As String, ByVal sData As String) As Boolean
On Error GoTo PrintErr:

          Dim lhPrinter As Long, lReturn As Long, lpcWritten As Long
          Dim lDoc As Long, sWrittenData As String
          Dim MyDocInfo As DOCINFO
          Dim pOutput As Printer
          Dim p As Printer

            For Each p In Printers
                If p.DeviceName = sPrinter Then
                    Set pOutput = p
                    GoTo StartPrinting
                End If
            Next p

            MsgBox "Unable to find the specified printer [" & sPrinter & _
            "] in the list of currently installed printers" & vbCrLf & _
            "Printing will be aborted", vbCritical
            Exit Function

StartPrinting:
          lReturn = OpenPrinter(pOutput.DeviceName, lhPrinter, 0)

          If lReturn = 0 Then
              MsgBox "Print was unsuccessful. Make sure there is a printer installed on the port you are trying to print to"
              Exit Function
          End If

          MyDocInfo.pDocName = sDocName
          MyDocInfo.pOutputFile = vbNullString
          MyDocInfo.pDatatype = vbNullString
          lDoc = StartDocPrinter(lhPrinter, 1, MyDocInfo)
          Call StartPagePrinter(lhPrinter)

          sWrittenData = sData

          lReturn = WritePrinter(lhPrinter, ByVal sWrittenData, Len(sWrittenData), lpcWritten)
          lReturn = EndPagePrinter(lhPrinter) 'need this??
          lReturn = EndDocPrinter(lhPrinter)
          lReturn = ClosePrinter(lhPrinter)

          Exit Function

PrintErr:
    MsgBox "Print was unsuccessful. Make sure there is a printer installed on the port you are trying to print to"
    Exit Function

End Function

To use it you need to install a printer that uses the correct port using any driver (I generally use the Generic / text Only Driver) and then call it as follows replacing the Hello with the data you want to send to the printer including control characters etc:

PrintRawData "Generic / Text Only", "My Document", "Hello"
夕色琉璃 2024-10-15 12:41:39

更新并彻底修改答案

Pete,您是否考虑过使用完全不同类型的打印机?设置、更改和发送 PostSCript 命令确实会花费大量时间。

您可能会称其为奇怪的解决方案,但我们的即时黑白激光 Brother 标签打印机只需按一下按钮即可立即打印出来。他们内部开发的专业坚如磐石的 P-Touch Editor 5.4 软件的创建方式是同时输出到多台打印机(!!),每台打印机打印相同或不同的标签(例如不同的序列号)数据库中的数字或日期)。

它很快:当放开返回按钮时,当我的手指到达按钮中半厘米时,已经 IIIIEEEUUUUUU(释放返回键后 1 秒)整个标签就出来了。尽管是黑白的。

除了标签之外,还有原始或第三方品牌生产的不带粘背的 102 毫米宽卷纸标签。

成本:每台 100 美元 ~ 400 美元,包括设计和定制与数据库连接的软件。

我知道这些即时打印机使用更少的基于 Windows 的驱动程序和更多的嵌入式技术,从而使系统免于标准化打印作业。

也许这可以解决您的问题或给您带来新的想法。

Updated and completely overhauled Answer :

Pete, have you considered an entirely different kind of printer? The setting, changing and sending PostSCript commands can take, indeed, a lot of time.

A strange solution you might call it, but our instant B/W laser Brother label printer prints out instantly on a press of the button. Their specialty rock solid in house developed P-Touch Editor 5.4 Software is created in such a way as to output to multiple printers simeltaneously(!!), each printing the same or different lables (for example different serial numbers or dates from a database).

Its snappy: when letting go of a return button, just when my finger has reached half a centimeter in the button already IIIIEEEUUUUUU (1 second after release of return key) the entire lable is out. Albeit in black and white.

Aside lables there are also paper lables without sticky backs 102mm wide rols by either original or third party brands makes.

Cost: 100$ ~ 400$ per unit incl software to design and customise connections with database.

I know that those instant printers use much less windows-based drivers and more embedded technologies, relieving the system from standardized print jobs.

Perhaps this solves your problem or brings you on a new idea.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文