1. 程式人生 > 程式設計 >python連線印表機實現列印文件、圖片、pdf檔案等功能

python連線印表機實現列印文件、圖片、pdf檔案等功能

引言

python連線印表機進行列印,可能根據需求的不同,使用不同的函式模組。

  1. 如果你只是簡單的想列印文件,比如office文件,你可以使用ShellExecute方法,對於微軟office的文件、pdf、txt等有用,你可以嘗試下;
  2. 如果你輸入某些資料,文字資訊,就想直接把它傳送給印表機列印,那麼可以嘗試使用win32print;
  3. 如果你有一張圖片,那麼你可以結合python的Python Imaging Library(PIL)win32ui模組進行列印;

普通列印

ShellExecute

  • 首先確保你電腦中的應用可以開啟你要列印的檔案;
  • 是一些標準的檔案型別
  • 不用管哪些印表機,也就是說和連線的印表機型號無關;
  • 你無控制設定列印屬性的許可權;
import tempfile
import win32api
import win32print

filename = tempfile.mktemp (".txt")
open (filename,"w").write ("This is a test")
win32api.ShellExecute (
 0,"print",filename,#
 # If this is None,the default printer will
 # be used anyway.
 #
 '/d:"%s"' % win32print.GetDefaultPrinter (),".",0
)

另一個版本

import tempfile
import win32api
import win32print

filename = tempfile.mktemp (".txt")
open (filename,"printto",'"%s"' % win32print.GetDefaultPrinter (),0
)

直接列印資料

win32print

  • 直接將資料扔給印表機;
  • 快速而且容易;
  • 而且可以定義選擇哪個印表機列印;
  • 但是要列印的資料必須是可列印的,例如字串等;
import os,sys
import win32print
printer_name = win32print.GetDefaultPrinter ()
#
# raw_data could equally be raw PCL/PS read from
# some print-to-file operation
#
if sys.version_info >= (3,):
 raw_data = bytes ("This is a test","utf-8")
else:
 raw_data = "This is a test"

hPrinter = win32print.OpenPrinter (printer_name)
try:
 hJob = win32print.StartDocPrinter (hPrinter,1,("test of raw data",None,"RAW"))
 try:
  win32print.StartPagePrinter (hPrinter)
  win32print.WritePrinter (hPrinter,raw_data)
  win32print.EndPagePrinter (hPrinter)
 finally:
  win32print.EndDocPrinter (hPrinter)
finally:
 win32print.ClosePrinter (hPrinter)

列印圖片

PIL win32ui

不使用額外的工具,在windows電腦上列印一張圖片是相當的困難,至少需要3種不同的且相關的裝置環境才可以。
還好,device-independent bitmap(DIB)和PIL可以幫助我們快速列印。下面的程式碼可以將圖片傳送至印表機列印儘可能大的尺寸且不失比例。

  • 還可以選擇使用哪個印表機
  • 選擇載入的圖片的格式等
  • 但是如果你電腦不是windows,那可能不是最好的方法;
import win32print
import win32ui
from PIL import Image,ImageWin

#
# Constants for GetDeviceCaps
#
#
# HORZRES / VERTRES = printable area
#
HORZRES = 8
VERTRES = 10
#
# LOGPIXELS = dots per inch
#
LOGPIXELSX = 88
LOGPIXELSY = 90
#
# PHYSICALWIDTH/HEIGHT = total area
#
PHYSICALWIDTH = 110
PHYSICALHEIGHT = 111
#
# PHYSICALOFFSETX/Y = left / top margin
#
PHYSICALOFFSETX = 112
PHYSICALOFFSETY = 113

printer_name = win32print.GetDefaultPrinter ()
file_name = "test.jpg"

#
# You can only write a Device-independent bitmap
# directly to a Windows device context; therefore
# we need (for ease) to use the Python Imaging
# Library to manipulate the image.
#
# Create a device context from a named printer
# and assess the printable size of the paper.
#
hDC = win32ui.CreateDC ()
hDC.CreatePrinterDC (printer_name)
printable_area = hDC.GetDeviceCaps (HORZRES),hDC.GetDeviceCaps (VERTRES)
printer_size = hDC.GetDeviceCaps (PHYSICALWIDTH),hDC.GetDeviceCaps (PHYSICALHEIGHT)
printer_margins = hDC.GetDeviceCaps (PHYSICALOFFSETX),hDC.GetDeviceCaps (PHYSICALOFFSETY)

#
# Open the image,rotate it if it's wider than
# it is high,and work out how much to multiply
# each pixel by to get it as big as possible on
# the page without distorting.
#
bmp = Image.open (file_name)
if bmp.size[0] > bmp.size[1]:
 bmp = bmp.rotate (90)

ratios = [1.0 * printable_area[0] / bmp.size[0],1.0 * printable_area[1] / bmp.size[1]]
scale = min (ratios)

#
# Start the print job,and draw the bitmap to
# the printer device at the scaled size.
#
hDC.StartDoc (file_name)
hDC.StartPage ()

dib = ImageWin.Dib (bmp)
scaled_width,scaled_height = [int (scale * i) for i in bmp.size]
x1 = int ((printer_size[0] - scaled_width) / 2)
y1 = int ((printer_size[1] - scaled_height) / 2)
x2 = x1 + scaled_width
y2 = y1 + scaled_height
dib.draw (hDC.GetHandleOutput (),(x1,y1,x2,y2))

hDC.EndPage ()
hDC.EndDoc ()
hDC.DeleteDC ()

實踐

從前臺傳來要列印的字元,後端生成二維碼,並作出相應處理後,連線印表機列印圖片。

# 列印二維碼
def print_barcode(request):
  import pyqrcode
  import random,string
  from PIL import Image,ImageDraw,ImageFont
  import numpy as np
  if request.is_ajax() and request.method == 'POST':
    result = {}
    bar_string = 'NaN'
    type = request.POST['type']

    if type == 'box':
      # 生成箱子碼
      # 格式:P190823-K91 [P][日期][-][A-Z][0-9][0-9]
      bar_string = 'P'+datetime.date.today().strftime('%y%m%d')+'-'+str(random.choice('ABCDEFGHIGKLMNOPQRSTUVWXYZ'))\
             + str(random.choice(range(10)))+ str(random.choice(range(10)))
    elif type == 'kuwei':
      # 生成庫位碼
      bar_string = request.POST['string']
    else:
      pass

    try:
      big_code = pyqrcode.create(bar_string,error='L',version=2,mode='binary')
      big_code.png('./code.png',scale=8)
      img_code = Image.open('code.png')

      size = img_code.size
      img_final = Image.new('RGB',(size[0],size[1]+35),color=(255,255,255))
      img_final.paste(img_code,(0,size[0],size[1]))

      draw = ImageDraw.Draw(img_final)
      font = ImageFont.truetype('AdobeGothicStd-Bold.otf',size=35)
      width,height = draw.textsize(bar_string,font=font)
      draw.text(((size[0]-width)/2,size[1]-15),bar_string,fill=(0,0),font=font)
      img_final.save('./code.png')

      # 然後連線印表機將其打印出來即可
      is_ok =[]
      if type == 'box':
        for i in range(4):
          temp = print_img('./code.png')
          is_ok.append(temp)
      else:
        temp = print_img('./code.png')
        is_ok.append(temp)
      # is_ok = True
      result['done'] = 'ok' if np.all(is_ok) else '連線印表機失敗'
    except Exception as e:
      result['done'] = e

    return JsonResponse(result)
 
 def print_img(img):
  import win32print
  import win32ui
  from PIL import Image,ImageWin
  # 參考 http://timgolden.me.uk/python/win32_how_do_i/print.html#win32print
  try:
    printer_name = win32print.GetDefaultPrinter()
    hDC = win32ui.CreateDC()
    hDC.CreatePrinterDC(printer_name)

    #printable_area = (300,270) # 列印紙尺寸
    #printer_size = (300,270)

    # 開啟圖片並縮放
    bmp = Image.open(img)
    if bmp.size[0] < bmp.size[1]:
      bmp = bmp.rotate(90)

    # ratios = [1.0 * printable_area[0] / bmp.size[1],1.0 * printable_area[1] / bmp.size[0]]
    # scale = min(ratios)
    scale = 1

    hDC.StartDoc(img)
    hDC.StartPage()

    dib = ImageWin.Dib(bmp)
    scaled_width,scaled_height = [int(scale * i) for i in bmp.size]

    x1 = 20 # 控制位置
    y1 = -30
    x2 = x1 + scaled_width
    y2 = y1 + scaled_height
    dib.draw(hDC.GetHandleOutput(),y2))

    hDC.EndPage()
    hDC.EndDoc()
    hDC.DeleteDC()

    return True
  except:
    return False

列印效果:

python連線印表機實現列印文件、圖片、pdf檔案等功能

以上內容為二賽君整理髮布,轉載請註明出處,謝謝。

參考

http://timgolden.me.uk/python/win32_how_do_i/print.htm