batchprint/batchprint.pyw
2023-08-24 01:43:00 +02:00

266 lines
7.4 KiB
Python
Executable File

#!/usr/bin/env python3
# requires: pywin32, pillow, qtpy, a module compatible with qtpy (try pyqt5)
import sys
import ctypes
import traceback
import win32clipboard
oldexcepthook = sys.excepthook
def newexcepthook(type,value,tb):
excText = "".join(traceback.format_exception(type,value,tb))
try:
for window in windows:
try:
window.close()
except:
pass
except:
pass
output = ctypes.windll.user32.MessageBoxW(None, u"" + excText + "\nThe program must close. Copy exception to clipboard?", u"Unhandled exception - batchprint", 0x00000114)
if output == 6:
copyString(excText)
oldexcepthook(type,value,tb)
sys.excepthook = newexcepthook
def copyString(s):
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(s, win32clipboard.CF_UNICODETEXT)
win32clipboard.CloseClipboard()
import os
p = os.path.join
pUp = os.path.dirname
s = False
if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
s = os.path.realpath(sys.executable)
else:
s = os.path.realpath(__file__)
sp = pUp(s)
import winreg
import subprocess
import win32print
import win32ui
import PIL.Image
import PIL.ImageWin
import time
import qtpy
import qtpy.QtGui as QtGui
from qtpy.QtGui import *
from qtpy.QtWidgets import *
from qtpy.QtCore import *
# https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getdevicecaps
HORZRES = 8
VERTRES = 10
PHYSICALWIDTH = 110
PHYSICALHEIGHT = 111
PHYSICALOFFSETX = 112
PHYSICALOFFSETY = 113
def getPrinters():
hive = winreg.ConnectRegistry(None,winreg.HKEY_LOCAL_MACHINE)
key = winreg.OpenKey(hive,r"SYSTEM\CurrentControlSet\Control\Print\Printers")
printers = []
index = 0
while True:
try:
printers.append(winreg.EnumKey(key,index))
index += 1
except OSError:
break
winreg.CloseKey(key)
hive.Close()
return printers
def printerOpenProperties(printerName):
subprocess.Popen(["rundll32","printui.dll,PrintUIEntry","/e","/n" + printerName]).wait()
def printerOpenQueue(printerName):
subprocess.Popen(["rundll32","printui.dll,PrintUIEntry","/o","/n" + printerName])
class printerWindow(QMainWindow):
def __init__(self,printers,*args,**kwargs):
super().__init__(*args,**kwargs)
self.cTitle = "Choose a printer - batchprint"
self.setWindowTitle(self.cTitle)
self.cWidth = 320
self.cHeight = 82
self.resize(self.cWidth,self.cHeight)
self.cPrinters = printers
self.cCreateElements()
def cCreateElements(self):
self.cLabel = QLabel(self)
self.cLabel.setText("Choose a printer:")
self.cLabel.setAlignment(Qt.AlignCenter)
self.cDropdown = QComboBox(self)
self.cDropdown.addItems(self.cPrinters)
try:
with open(p(sp,"lastprinter.txt"),"r",encoding="utf-8") as f:
printer = f.read()
self.cDropdown.setCurrentIndex(self.cPrinters.index(printer))
except:
pass
self.cButton = QPushButton(self)
self.cButton.setText("OK")
self.cButton.clicked.connect(self.cOpenList)
self.cButtonSettings = QPushButton(self)
self.cButtonSettings.setText("Settings")
self.cButtonSettings.clicked.connect(self.cOpenSettings)
self.cResizeElements()
self.show()
def cResizeElements(self):
self.cLabel.move(0,5)
self.cLabel.resize(self.cWidth,15)
self.cDropdown.move(10,25)
self.cDropdown.resize(self.cWidth - 20,22)
self.cButton.move(self.cWidth - 64 - 5,self.cHeight - 22 - 5)
self.cButton.resize(64,22)
self.cButtonSettings.move(5,self.cHeight - 22 - 5)
self.cButtonSettings.resize(64,22)
def resizeEvent(self,event):
self.cWidth = self.width()
self.cHeight = self.height()
self.cResizeElements()
def closeEvent(self,event):
windows.remove(self)
def cOpenList(self):
printer = self.cDropdown.currentText()
try:
with open(p(sp,"lastprinter.txt"),"w",encoding="utf-8") as f:
f.write(printer)
except:
pass
self.close()
#printerOpenQueue(printer)
windows.append(queueWindow(printer))
def cOpenSettings(self):
printer = self.cDropdown.currentText()
self.hide()
printerOpenProperties(printer)
self.cOpenList()
class queueWindow(QMainWindow):
def __init__(self,printer,*args,**kwargs):
super().__init__(*args,**kwargs)
self.setAcceptDrops(True)
self.cWidth = 240
self.cHeight = 200
self.resize(self.cWidth,self.cHeight)
self.cPrinter = printer
self.cDC = win32ui.CreateDC()
self.cDC.CreatePrinterDC(printer)
self.cPrinterPhysicalSize = [self.cDC.GetDeviceCaps(PHYSICALWIDTH),self.cDC.GetDeviceCaps(PHYSICALHEIGHT)]
self.cPrinterPrintSize = [self.cDC.GetDeviceCaps(HORZRES),self.cDC.GetDeviceCaps(VERTRES)]
self.cPrinterPrintOffset = [self.cDC.GetDeviceCaps(PHYSICALOFFSETX),self.cDC.GetDeviceCaps(PHYSICALOFFSETY)]
self.cTitle = printer+ " (" +str(self.cPrinterPrintSize[0])+ "x" +str(self.cPrinterPrintSize[1])+ ") - batchprint"
self.setWindowTitle(self.cTitle)
self.cCreateElements()
def cCreateElements(self):
self.cLabel = QLabel(self)
self.cLabel.setText("Drag & Drop images here")
self.cLabel.setAlignment(Qt.AlignCenter)
self.cLabel.setWordWrap(True)
self.cTick = QCheckBox(self)
self.cTick.setText("Do not scale/rotate")
self.cTick.setChecked(False)
try:
with open(p(sp,"rawprint.txt"),encoding="utf-8") as f:
rawprint = int(f.read())
if rawprint: self.cTick.setChecked(True)
except:
pass
self.cResizeElements()
self.show()
def cResizeElements(self):
self.cLabel.move(0,0)
self.cLabel.resize(self.cWidth,self.cHeight)
self.cTick.move(5,0)
self.cTick.resize(self.cWidth - 10,22)
def resizeEvent(self,event):
self.cWidth = self.width()
self.cHeight = self.height()
self.cResizeElements()
def dragEnterEvent(self,event):
self.activateWindow()
if event.mimeData().hasUrls():
self.cLabel.setStyleSheet("font-weight: bold")
event.accept()
def dragLeaveEvent(self,event):
self.cLabel.setStyleSheet("")
def dropEvent(self,event):
self.cLabel.setStyleSheet("")
rawprint = self.cTick.isChecked()
for url in event.mimeData().urls():
path = str(url.toLocalFile()).replace("/",os.path.sep)
self.cLabel.setText(path.rsplit(os.path.sep,1)[-1]+ " ...")
self.repaint()
bmp = PIL.Image.open(path)
if not rawprint:
if bmp.size[1] > bmp.size[0]:
if self.cPrinterPrintSize[0] > self.cPrinterPrintSize[1]:
bmp = bmp.transpose(PIL.Image.ROTATE_90)
elif bmp.size[0] > bmp.size[1]:
if self.cPrinterPrintSize[1] > self.cPrinterPrintSize[0]:
bmp = bmp.transpose(PIL.Image.ROTATE_90)
imWidth = self.cPrinterPrintSize[0]
imHeight = self.cPrinterPrintSize[1]
else:
imWidth = bmp.size[0]
imHeight = bmp.size[1]
self.cDC.StartDoc(path)
self.cDC.StartPage()
dib = PIL.ImageWin.Dib(bmp)
dib.draw(self.cDC.GetHandleOutput(),(
self.cPrinterPrintOffset[0],self.cPrinterPrintOffset[1],
imWidth,imHeight
))
self.cDC.EndPage()
self.cDC.EndDoc()
self.cLabel.setText("Drag & Drop images here")
def closeEvent(self,event):
try:
with open(p(sp,"rawprint.txt"),"w",encoding="utf-8") as f:
if self.cTick.isChecked():
f.write("1")
else:
f.write("0")
except:
pass
self.cDC.DeleteDC()
windows.remove(self)
windows = []
printers = getPrinters()
app = QApplication(sys.argv)
windows.append(printerWindow(printers))
app.exec_()