Skip to content

Commit

Permalink
Update margins logic
Browse files Browse the repository at this point in the history
Discard margin handling in the printing driver, which used to add mental
load when trying to figure out the logic of how margins are implemented.
Having all margin handling in "userspace" of render engines (i.e. not in
the print driver abstraction level), will enable us to implement more
complicated logic in the future.
  • Loading branch information
Tomer Shalev committed Feb 4, 2024
1 parent 0681cbc commit 6924b9c
Show file tree
Hide file tree
Showing 10 changed files with 352 additions and 139 deletions.
39 changes: 17 additions & 22 deletions src/dymoprint/cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
DEFAULT_MARGIN_PX,
PIXELS_PER_MM,
USE_QR,
VERTICAL_PREVIEW_MARGIN_PX,
e_qrcode,
)
from dymoprint.lib.dymo_labeler import DymoLabeler
Expand All @@ -29,6 +28,8 @@
BarcodeWithTextRenderEngine,
HorizontallyCombinedRenderEngine,
PictureRenderEngine,
PrintPayloadRenderEngine,
PrintPreviewRenderEngine,
QrRenderEngine,
RenderContext,
TestPatternRenderEngine,
Expand Down Expand Up @@ -294,42 +295,36 @@ def run():
else None
)

render = HorizontallyCombinedRenderEngine(
render_engines,
min_payload_len_px=min_payload_len_px,
max_payload_len_px=max_payload_len_px,
render_engine = HorizontallyCombinedRenderEngine(render_engines)
render_kwargs = dict(
render_engine=render_engine,
justify=args.justify,
visible_horizontal_margin_px=margin_px,
labeler_margin_px=DymoLabeler.get_labeler_margin_px(),
max_width_px=max_payload_len_px,
min_width_px=min_payload_len_px,
)

dymo_labeler = DymoLabeler(
margin_px=margin_px,
tape_size_mm=args.tape_size_mm,
)
dymo_labeler = DymoLabeler(tape_size_mm=args.tape_size_mm)
render_context = RenderContext(height_px=dymo_labeler.height_px)
bitmap = render.render(render_context)

# print or show the label
if args.preview or args.preview_inverted or args.imagemagick or args.browser:
render = PrintPreviewRenderEngine(**render_kwargs)
bitmap = render.render(render_context)
LOG.debug("Demo mode: showing label..")
# fix size, adding print borders
expanded_bitmap = Image.new(
"1",
(
bitmap.width + margin_px * 2,
bitmap.height + VERTICAL_PREVIEW_MARGIN_PX * 2,
),
)
expanded_bitmap.paste(bitmap, (margin_px, VERTICAL_PREVIEW_MARGIN_PX))
if args.preview or args.preview_inverted:
label_rotated = expanded_bitmap.transpose(Image.ROTATE_270)
label_rotated = bitmap.transpose(Image.ROTATE_270)
print(image_to_unicode(label_rotated, invert=args.preview_inverted))
if args.imagemagick:
ImageOps.invert(expanded_bitmap).show()
ImageOps.invert(bitmap).show()
if args.browser:
with NamedTemporaryFile(suffix=".png", delete=False) as fp:
ImageOps.invert(expanded_bitmap).save(fp)
ImageOps.invert(bitmap).save(fp)
webbrowser.open(f"file://{fp.name}")
else:
render = PrintPayloadRenderEngine(**render_kwargs)
bitmap = render.render(render_context)
dymo_labeler.print(bitmap)


Expand Down
87 changes: 43 additions & 44 deletions src/dymoprint/gui/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
)

from dymoprint.gui.common import crash_msg_box
from dymoprint.lib.constants import DEFAULT_MARGIN_PX, ICON_DIR
from dymoprint.lib.constants import ICON_DIR
from dymoprint.lib.dymo_labeler import (
DymoLabeler,
DymoLabelerDetectError,
Expand All @@ -39,12 +39,12 @@ class DymoPrintWindow(QWidget):
SUPPORTED_TAPE_SIZE_MM = (19, 12, 9, 6)
DEFAULT_TAPE_SIZE_MM_INDEX = 1

label_bitmap: Optional[Image.Image]
print_label_bitmap: Optional[Image.Image]
dymo_labeler: DymoLabeler

def __init__(self):
super().__init__()
self.label_bitmap = None
self.print_label_bitmap = None
self.detected_device = None

self.window_layout = QVBoxLayout()
Expand All @@ -54,11 +54,11 @@ def __init__(self):
self.label_render = QLabel()
self.error_label = QLabel()
self.print_button = QPushButton()
self.margin_px = QSpinBox()
self.horizontal_margin_mm = QSpinBox()
self.tape_size_mm = QComboBox()
self.foreground_color = QComboBox()
self.background_color = QComboBox()
self.min_label_len_mm = QSpinBox()
self.min_label_width_mm = QSpinBox()
self.justify = QComboBox()
self.info_label = QLabel()
self.last_error = None
Expand All @@ -84,14 +84,15 @@ def init_elements(self):
shadow.setBlurRadius(15)
self.label_render.setGraphicsEffect(shadow)

self.margin_px.setMinimum(20)
self.margin_px.setMaximum(1000)
self.margin_px.setValue(DEFAULT_MARGIN_PX)
h_margins_mm = round(DymoLabeler.LABELER_HORIZONTAL_MARGIN_MM)
self.horizontal_margin_mm.setMinimum(h_margins_mm)
self.horizontal_margin_mm.setMaximum(100)
self.horizontal_margin_mm.setValue(h_margins_mm)
for tape_size_mm in self.SUPPORTED_TAPE_SIZE_MM:
self.tape_size_mm.addItem(str(tape_size_mm), tape_size_mm)
self.tape_size_mm.setCurrentIndex(self.DEFAULT_TAPE_SIZE_MM_INDEX)
self.min_label_len_mm.setMinimum(0)
self.min_label_len_mm.setMaximum(1000)
self.min_label_width_mm.setMinimum(h_margins_mm * 2)
self.min_label_width_mm.setMaximum(300)
self.justify.addItems(["center", "left", "right"])

self.foreground_color.addItems(
Expand All @@ -109,30 +110,31 @@ def init_timers(self):
self.check_status()
self.status_time = QTimer()
self.status_time.timeout.connect(self.check_status)
self.status_time.setInterval(2000)
self.status_time.start(2000)
self.status_time.setInterval(20000)
self.status_time.start(20000)

def init_connections(self):
self.margin_px.valueChanged.connect(self.label_list.render_label)
self.margin_px.valueChanged.connect(self.update_params)
self.horizontal_margin_mm.valueChanged.connect(self.label_list.render_label)
self.horizontal_margin_mm.valueChanged.connect(self.update_params)
self.tape_size_mm.currentTextChanged.connect(self.update_params)
self.min_label_len_mm.valueChanged.connect(self.update_params)
self.min_label_width_mm.valueChanged.connect(self.update_params)
self.justify.currentTextChanged.connect(self.update_params)
self.foreground_color.currentTextChanged.connect(self.label_list.render_label)
self.background_color.currentTextChanged.connect(self.label_list.render_label)
self.label_list.renderSignal.connect(self.update_label_render)
self.label_list.renderPrintPreviewSignal.connect(self.update_preview_render)
self.label_list.renderPrintPayloadSignal.connect(self.update_print_render)
self.print_button.clicked.connect(self.print_label)

def init_layout(self):
settings_widget = QToolBar(self)
settings_widget.addWidget(QLabel("Margin:"))
settings_widget.addWidget(self.margin_px)
settings_widget.addWidget(QLabel("Margin [mm]:"))
settings_widget.addWidget(self.horizontal_margin_mm)
settings_widget.addSeparator()
settings_widget.addWidget(QLabel("Tape Size:"))
settings_widget.addWidget(QLabel("Tape Size [mm]:"))
settings_widget.addWidget(self.tape_size_mm)
settings_widget.addSeparator()
settings_widget.addWidget(QLabel("Min Label Len [mm]:"))
settings_widget.addWidget(self.min_label_len_mm)
settings_widget.addWidget(QLabel("Min Label Length [mm]:"))
settings_widget.addWidget(self.min_label_width_mm)
settings_widget.addSeparator()
settings_widget.addWidget(QLabel("Justify:"))
settings_widget.addWidget(self.justify)
Expand Down Expand Up @@ -175,28 +177,24 @@ def init_layout(self):

def update_params(self):
justify: str = self.justify.currentText()
margin_px: int = self.margin_px.value()
min_label_mm_len: int = self.min_label_len_mm.value()
tape_size_mm: int = self.tape_size_mm.currentData()
horizontal_margin_mm: float = self.horizontal_margin_mm.value()
min_label_width_mm: float = self.min_label_width_mm.value()
tape_size_mm: float = self.tape_size_mm.currentData()

self.dymo_labeler.margin_px = margin_px
self.dymo_labeler.tape_size_mm = tape_size_mm
self.render_context.height_px = self.dymo_labeler.height_px
min_payload_len_px = max(0, (min_label_mm_len * 7) - margin_px * 2)
self.label_list.update_params(self.render_context, min_payload_len_px, justify)

def update_label_render(self, label_bitmap):
self.label_bitmap = label_bitmap
label_image = Image.new(
"L",
(
self.margin_px.value() + label_bitmap.width + self.margin_px.value(),
label_bitmap.height,
),

self.label_list.update_params(
h_margin_mm=horizontal_margin_mm,
min_label_width_mm=min_label_width_mm,
render_context=self.render_context,
justify=justify,
)
label_image.paste(label_bitmap, (self.margin_px.value(), 0))
label_image_inv = ImageOps.invert(label_image).copy()
qim = ImageQt.ImageQt(label_image_inv)

def update_preview_render(self, label_bitmap):
preview_label_image = label_bitmap.convert("L")
preview_label_image_inv = ImageOps.invert(preview_label_image).copy()
qim = ImageQt.ImageQt(preview_label_image_inv)
q_image = QPixmap.fromImage(qim)

mask = q_image.createMaskFromColor(
Expand All @@ -210,15 +208,16 @@ def update_label_render(self, label_bitmap):

self.label_render.setPixmap(q_image)
self.label_render.adjustSize()
self.info_label.setText(f"← {px_to_mm(label_image.size[0])} mm →")
self.info_label.setText(f"← {px_to_mm(label_bitmap.size[0])} mm →")

def update_print_render(self, print_label_bitmap):
self.print_label_bitmap = print_label_bitmap

def print_label(self):
try:
if self.label_bitmap is None:
if self.print_label_bitmap is None:
raise RuntimeError("No label to print! Call update_label_render first.")
self.dymo_labeler.print(
self.label_bitmap,
)
self.dymo_labeler.print(self.print_label_bitmap)
except DymoLabelerPrintError as err:
crash_msg_box(self, "Printing Failed!", err)

Expand Down
Loading

0 comments on commit 6924b9c

Please sign in to comment.