日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

codesoft指定打印机打印_巧用win32print来控制windows系统打印机并推送打印任务

發布時間:2024/7/23 windows 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 codesoft指定打印机打印_巧用win32print来控制windows系统打印机并推送打印任务 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  小爬最近接到的一個需求是:將windows系統下的打印任務批量有序傳輸給網絡打印機,實現批量有序打印。

????用戶先從公司的OA(B/S模式)系統下 打印指定內容的表單以及表單中的附件內容。這個問題可以這樣分解:

1、抓包,得到OA對應的任務接口,然后利用python requests模擬post請求,獲取所有的表單的URL并進行必要的去重處理;

2、打印OA表單的過程,需要瀏覽器在前臺,這個時候可以結合selenium的driver.get(url)方法,打開每一個表單,同時解析網頁內容,拿到所有附件的相關信息(名稱、后綴、下載地址),利用requests再度保存這些附件至本地;

3、打開表單后,利用 win32api.keybd_event,模擬鍵盤快捷鍵“Ctrl + Shift + P”調出系統的打印窗口;

4、選中“PDF打印機”,需要電腦中有“Microsoft Print to Pdf”或者“Foxit Reader PDF Printer”等;

5、利用pywin32中的相關方法,驅動打印過程,將每個OA表單(網頁)打印成PDF文件并格式化命名&存儲,與前面的附件內容存儲到同一個文件夾;

6、附件文件和OA生成的PDF文件均格式化存儲,用OA單號作為文件名的一部分,將兩者關聯起來;

7、將本地對應文件夾的所有內容有序推送給打印機,指定打印機為某一臺網絡打印機。同時要確保打印過程中,不亂序;

針對步驟3,可以自定義函數來實現:

#鍵盤按下
def?key_down(keyname):
????win32api.keybd_event(vk_code[keyname],0,0,0)

#鍵盤抬起
def?key_up(key_name):
????win32api.keybd_event(vk_code[key_name],0,win32con.KEYEVENTF_KEYUP,0)

#按鍵組合操作
def?simulate_three_key(firstkey,sencondkey,lastkey):
????key_down(firstkey)
????key_down(sencondkey)
????key_down(lastkey)
????key_up(lastkey)
????key_up(sencondkey)
????key_up(firstkey)
#按鍵組合操作
def?simulate_two_key(firstkey,sencondkey):
????key_down(firstkey)
????key_down(sencondkey)
????key_up(sencondkey)
????key_up(firstkey)

????然后利用 simulate_three_key('ctrl',"shift",'p') 即可呼出系統的默認打印窗口:

  那么步驟4,也就是上圖的打印窗口,如何選中某一個打印機呢?直接利用win32gui.SendMessage

????來選中某個打印機是非常困難的。一種可行的方法是,利用pywin32下的win32print模塊,也就是本文的重點。

比如,用下面的代碼可以遍歷并獲取到當前計算機的所有打印機信息:

for?it?in?win32print.EnumPrinters(6):
????print(it[1])

????我們甚至可以知道某臺打印機的當前狀態,假定某臺打印機名為printerName,則可以這樣獲取打印機狀態:

hPrinter?=?win32print.OpenPrinter?(printerName)
dic?=?hex(win32print.GetPrinter(hPrinter,2)['Status'])
if?dic[-2]=="8":
????print("The?printer?is?offline.")
if?dic[-5]=="4":
???print("The?printer?is?out?of?toner.")
elif?dic[-5]=="2":
???print("The?printer?is?low?on?toner.")

Printer status name/value

Description

PRINTER_STATUS_BUSY

0x00000200

The printer is busy.

PRINTER_STATUS_DOOR_OPEN

0x00400000

The printer door is open.

PRINTER_STATUS_ERROR

0x00000002

The printer is in an error state.

PRINTER_STATUS_INITIALIZING

0x00008000

The printer is initializing.

PRINTER_STATUS_IO_ACTIVE

0x00000100

The printer is in an active input or output state.

PRINTER_STATUS_MANUAL_FEED

0x00000020

The printer is in a manual feed state.

PRINTER_STATUS_NOT_AVAILABLE

0x00001000

The printer is not available for printing.

PRINTER_STATUS_NO_TONER

0x00040000

The printer is out of toner.

PRINTER_STATUS_OFFLINE

0x00000080

The printer is offline.

PRINTER_STATUS_OUTPUT_BIN_FULL

0x00000800

The printer's output bin is full.

PRINTER_STATUS_OUT_OF_MEMORY

0x00200000

The printer has run out of memory.

PRINTER_STATUS_PAGE_PUNT

0x00080000

The printer cannot print the current page.

PRINTER_STATUS_PAPER_JAM

0x00000008

Paper is stuck in the printer.

PRINTER_STATUS_PAPER_OUT

0x00000010

The printer is out of paper.

PRINTER_STATUS_PAPER_PROBLEM

0x00000040

The printer has an unspecified paper problem.

PRINTER_STATUS_PAUSED

0x00000001

The printer is paused.

PRINTER_STATUS_PENDING_DELETION

0x00000004

The printer is being deleted as a result of a client's call to?RpcDeletePrinter. No new jobs can be submitted on existing printer objects for that printer.

PRINTER_STATUS_POWER_SAVE

0x01000000

The printer is in power-save mode.<182>

PRINTER_STATUS_PRINTING

0x00000400

The printer is printing.

PRINTER_STATUS_PROCESSING

0x00004000

The printer is processing a?print job.

PRINTER_STATUS_SERVER_OFFLINE

0x02000000

The printer is offline.<183>

PRINTER_STATUS_SERVER_UNKNOWN

0x00800000

The printer status is unknown.<184>

PRINTER_STATUS_TONER_LOW

0x00020000

The printer is low on toner.

PRINTER_STATUS_USER_INTERVENTION

0x00100000

The printer has an error that requires the user to do something.

PRINTER_STATUS_WAITING

0x00002000

The printer is waiting.

PRINTER_STATUS_WARMING_UP

0x00010000

The printer is warming up.

????????更多的打印機接口信息,可查詢微軟的開發文檔:https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/1625e9d9-29e4-48f4-b83d-3bd0fdaea787?redirectedfrom=MSDN

我們也可以得到當前默認的打印機,設置默認打印機:

currentPrinter=win32print.GetDefaultPrinterW()
win32print.SetDefaultPrinterW(printer)

????????我們利用上面兩個函數,可以先得到系統當前的打印機,用變量存儲后,再設置默認打印機至 PDF打印機,待執行完所有任務后,再設置默認打印機為用戶一開始的默認打印機,整個過程用戶不需要更多的干預;

  重點說步驟7:我們需要以OA表單+附件的形式,逐一給打印機分配任務,且不能亂序:

如果附件是圖片性質,我們可以結合Pillow庫來處理,示例代碼如下:

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

def?print_image(file_name):
?
????printer_name?=?win32print.GetDefaultPrinterW()?#?獲得默認打印機
????
????#
????#?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)
????#?bmp?=?bmp.rotate?(90)
????#?bmp.save("test1.png")
????if?bmp.size[0]?>?bmp.size[1]:
????????#?bmp?=?bmp.rotate?(90)
????????bmp=bmp.transpose(Image.ROTATE_90)
????
????ratios?=?[1.0?*?printable_area[0]?/?bmp.size[0],?1.0?*?printable_area[1]?/?bmp.size[1]]
????scale?=?min?(ratios)*0.85?#這個0.85的系數是不希望圖片被打印太大,缺少margin,不方便文檔的裝訂
????file_name=file_name.split("\\")[-1]?#這一步是為了提取fullpath中的filename部分
????
????#
????#?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?()

????????需要強調的是,如果我們對圖片進行后臺旋轉90度時,一定要用transpose(Image.ROTATE_90),不要使用 rotate (90),否則打印的圖片很有可能顯示不完整,且有黑邊;

具體的transpose用法見Pillow官網文檔:

????如果我們要打印的任務是PDF或者其他office類型的文檔,可以利用win32api.ShellExecute方法,示例如下:

def?printer_loading(filename):
????#?open?(filename,?"r")
????currentPrinter=win32print.GetDefaultPrinterW()
????win32api.ShellExecute?(0,"print",filename,'/d:"%s"'?%?currentPrinter,".",0)

  該方法有一個缺陷,win32api.ShellExecute 會在指令發出后,立即返回值,而不是等打印任務真正傳輸到打印機后再返回。這就意味著,附件中的圖片用win32ui的方法走后臺已經傳輸給打印機,而PDF等其他文件可能還沒及時發送給打印機,造成打印任務亂序。

????????可行的解決方法是,利用win32print.EnumJobs,定時獲取打印機當前的任務隊列,確保隊列中出現剛推送的任務后,再來推送下一個打印任務。示例如下:

handle?=?win32print.OpenPrinter(printer_name).handle
tasks=win32print.EnumJobs(handle,0,?-1,?1)
for?task?in?tasks:
????taskName=task["pDocument"]

????????由于打印任務是動態增減的,每次得到的tasks可能都不同,且由于打印機可能有很多人共同使用,不能保證某個用戶的某次打印任務一定會出現在打印隊列的最上方。所以要盡可能拿到所有的任務;

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

????????至此,這個項目中的難點都逐一有了解決方案,希望小爬以上的思路,對喜歡自動化的你,能有所借鑒~~

總結

以上是生活随笔為你收集整理的codesoft指定打印机打印_巧用win32print来控制windows系统打印机并推送打印任务的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。