Fix printing via a Brother QL
This commit is contained in:
128
src/printer.py
128
src/printer.py
@@ -20,10 +20,11 @@ import numpy as np
|
|||||||
# Importing the modules needed for each supported printer Type
|
# Importing the modules needed for each supported printer Type
|
||||||
import escpos.printer
|
import escpos.printer
|
||||||
from brother_ql.models import ModelsManager
|
from brother_ql.models import ModelsManager
|
||||||
from brother_ql.backends import backend_factory
|
from brother_ql.backends import backend_factory, guess_backend
|
||||||
from brother_ql.raster import BrotherQLRaster
|
from brother_ql.raster import BrotherQLRaster
|
||||||
from brother_ql.conversion import convert
|
from brother_ql.conversion import convert
|
||||||
from brother_ql.backends.helpers import send
|
from brother_ql.backends.helpers import send
|
||||||
|
from brother_ql import create_label
|
||||||
|
|
||||||
|
|
||||||
class PrinterType(Enum):
|
class PrinterType(Enum):
|
||||||
@@ -444,6 +445,7 @@ class BrotherPrinter(Printer):
|
|||||||
vendor_id=vendor_id,
|
vendor_id=vendor_id,
|
||||||
product_id=self.device_id,
|
product_id=self.device_id,
|
||||||
serial_number=serial_number,
|
serial_number=serial_number,
|
||||||
|
label_type="62",
|
||||||
)
|
)
|
||||||
self.app.logger.debug("Created a Brother printer !")
|
self.app.logger.debug("Created a Brother printer !")
|
||||||
self.ready = True
|
self.ready = True
|
||||||
@@ -462,86 +464,49 @@ class BrotherPrinter(Printer):
|
|||||||
"""
|
"""
|
||||||
Print a raster image via a Brother QL printer
|
Print a raster image via a Brother QL printer
|
||||||
"""
|
"""
|
||||||
# TODO : make this label type go in the configuration
|
self.ready = False
|
||||||
label_type = "62"
|
|
||||||
rotate = 0
|
|
||||||
dither = False
|
|
||||||
|
|
||||||
data = _process_image(self, path=data, max_width=720, max_height=720)
|
|
||||||
self.app.logger.debug("Printing image %s", data)
|
|
||||||
try:
|
try:
|
||||||
# Prepare the image for printing
|
selected_backend = guess_backend(self.printer_info.identifier)
|
||||||
qlr = BrotherQLRaster(self.printer_info["model"])
|
BACKEND_CLASS = backend_factory(selected_backend)['backend_class']
|
||||||
|
BACKEND_STRING_DESCR = self.printer_info.identifier
|
||||||
instructions = convert(
|
|
||||||
qlr=qlr,
|
|
||||||
images=[data],
|
|
||||||
label=label_type,
|
|
||||||
rotate=rotate,
|
|
||||||
threshold=70,
|
|
||||||
dither=dither,
|
|
||||||
compress=True,
|
|
||||||
red=False,
|
|
||||||
dpi_600=False,
|
|
||||||
hq=False,
|
|
||||||
cut=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Debug logging
|
|
||||||
if os.getenv("FLASK_DEBUG"):
|
|
||||||
self.app.logger.debug(f"""
|
|
||||||
Print parameters:
|
|
||||||
- Label type: {label_type}
|
|
||||||
- Rotate: {rotate}
|
|
||||||
- Dither: {dither}
|
|
||||||
- Model: {self.printer_info['model']}
|
|
||||||
- Backend: {self.printer_info['backend']}
|
|
||||||
- Identifier: {self.printer_info['identifier']}
|
|
||||||
""")
|
|
||||||
|
|
||||||
# Try to print using Python API
|
|
||||||
# send() = status = {
|
|
||||||
# 'instructions_sent': True, # The instructions were sent to the printer.
|
|
||||||
# 'outcome': 'unknown', # String description of the outcome of the sending operation like: 'unknown', 'sent', 'printed', 'error'
|
|
||||||
# 'printer_state': None, # If the selected backend supports reading back the printer state, this key will contain it.
|
|
||||||
# 'did_print': False, # If True, a print was produced. It defaults to False if the outcome is uncertain (due to a backend without read-back capability).
|
|
||||||
# 'ready_for_next_job': False, # If True, the printer is ready to receive the next instructions. It defaults to False if the state is unknown.
|
|
||||||
# }
|
|
||||||
status = send(
|
|
||||||
instructions=instructions,
|
|
||||||
printer_identifier=self.printer_info["identifier"],
|
|
||||||
backend_identifier="pyusb",
|
|
||||||
)
|
|
||||||
self.app.logger.debug("Status: " + str(status))
|
|
||||||
|
|
||||||
if (
|
|
||||||
not status["did_print"]
|
|
||||||
or status["outcome"] == "error"
|
|
||||||
or status["outcome"] == "unknown"
|
|
||||||
):
|
|
||||||
raise RuntimeError("Failed to print using Python API")
|
|
||||||
|
|
||||||
# if status["printer_state"]:
|
|
||||||
# self.ready = bool(status["printer_state"])
|
|
||||||
# self.app.logger.debug("Printer is borky : " + str(self.ready))
|
|
||||||
# else:
|
|
||||||
# self.ready = True
|
|
||||||
|
|
||||||
except usb.core.USBError as e:
|
|
||||||
# Treat timeout errors as successful since they often occur after print completion
|
|
||||||
if e.errno == 110: # Operation timed out
|
|
||||||
self.app.logger.debug(
|
|
||||||
"USB timeout occurred - this is normal and the print likely completed"
|
|
||||||
)
|
|
||||||
self.app.logger.debug("Print completed (timeout is normal)")
|
|
||||||
self.ready = True
|
|
||||||
|
|
||||||
self.app.logger.debug(f"USBError encountered: {e}")
|
|
||||||
raise RuntimeError from e
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.app.logger.debug(f"Unexpected error during printing: {str(e)}")
|
self.app.logger.error("Couldn't guess the backend to use from the printer string descriptor")
|
||||||
raise RuntimeError from e
|
|
||||||
|
try:
|
||||||
|
im = Image.open(data)
|
||||||
|
qlr = BrotherQLRaster(self.printer_info.model)
|
||||||
|
create_label(qlr, im, self.printer_info.label_type, threshold=70, cut=False, rotate=0)
|
||||||
|
|
||||||
|
# noinspection PyCallingNonCallable
|
||||||
|
be = BACKEND_CLASS(BACKEND_STRING_DESCR)
|
||||||
|
be.write(qlr.data)
|
||||||
|
be.dispose()
|
||||||
|
del be
|
||||||
|
except Exception as e:
|
||||||
|
raise e
|
||||||
|
|
||||||
|
def _cut(self):
|
||||||
|
self.ready = False
|
||||||
|
try:
|
||||||
|
selected_backend = guess_backend(self.printer_info.identifier)
|
||||||
|
BACKEND_CLASS = backend_factory(selected_backend)['backend_class']
|
||||||
|
BACKEND_STRING_DESCR = self.printer_info.identifier
|
||||||
|
except Exception as e:
|
||||||
|
self.app.logger.error("Couldn't guess the backend to use from the printer string descriptor")
|
||||||
|
|
||||||
|
data = "src/static/images/1x1.png"
|
||||||
|
try:
|
||||||
|
im = Image.open(data)
|
||||||
|
qlr = BrotherQLRaster(self.printer_info.model)
|
||||||
|
create_label(qlr, im, self.printer_info.label_type, threshold=70, cut=True, rotate=0)
|
||||||
|
|
||||||
|
# noinspection PyCallingNonCallable
|
||||||
|
be = BACKEND_CLASS(BACKEND_STRING_DESCR)
|
||||||
|
be.write(qlr.data)
|
||||||
|
be.dispose()
|
||||||
|
del be
|
||||||
|
except Exception as e:
|
||||||
|
raise e
|
||||||
|
|
||||||
def print_task(self, task_type, data):
|
def print_task(self, task_type, data):
|
||||||
"""Execute actual print based on task type"""
|
"""Execute actual print based on task type"""
|
||||||
@@ -551,9 +516,10 @@ class BrotherPrinter(Printer):
|
|||||||
match (task_type.value):
|
match (task_type.value):
|
||||||
case "image":
|
case "image":
|
||||||
self._print_img(data["img"])
|
self._print_img(data["img"])
|
||||||
|
self.ready = True
|
||||||
case "cut":
|
case "cut":
|
||||||
# The cut happens by default on Brother QL printers.
|
self._cut()
|
||||||
pass
|
self.ready = True
|
||||||
case "text":
|
case "text":
|
||||||
self._print_txt(data["txt"], signature=data["sign"])
|
self._print_txt(data["txt"], signature=data["sign"])
|
||||||
self.ready = True
|
self.ready = True
|
||||||
|
|||||||
@@ -159,6 +159,10 @@ class Printers:
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def printers_info(self):
|
||||||
|
"""Return the current list of printers"""
|
||||||
|
return self.printers
|
||||||
|
|
||||||
class _FindClass:
|
class _FindClass:
|
||||||
"""
|
"""
|
||||||
Use by usb.core to modify the way USB devices are found
|
Use by usb.core to modify the way USB devices are found
|
||||||
|
|||||||
Reference in New Issue
Block a user