Fix Dymo label geometry: rotation and 300x600 dpi halving
Two bugs found on the bench, both from wrong assumptions about the LW450: 1. Orientation. I assumed the 57mm head meant the label feeds landscape. It doesn't -- the Dymo takes the SAME 24mm narrow-edge-first stock as the Urovo, so the landscape design needs the identical 90-degree rotation. Rendering 656 dots onto a ~288-dot label also silently clipped the price and QR off the right-hand edge. Now rotates by default, overridable per request via "rotate", and the daemon rejects an image wider than the head instead of clipping it. 2. Half-length labels. print_image() sent ESC i (300x600 Barcode/Graphics mode), where the head stays 300 dpi across but each raster line becomes 1/600" in the travel direction -- so a 650-line label printed at 27.5mm instead of 55mm, with the across-head dimension correct. Default is now ESC h (300x300), matching our square 300 dpi bitmap. graphics_mode=True remains available and now stretches the image 2x vertically so physical size stays correct. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
2727545ac7
commit
d254d16278
@ -152,8 +152,17 @@ def do_encode(body):
|
|||||||
def do_print_paper(body):
|
def do_print_paper(body):
|
||||||
"""Print the paper label on the Dymo LabelWriter 450 (raw USB, no CUPS driver)."""
|
"""Print the paper label on the Dymo LabelWriter 450 (raw USB, no CUPS driver)."""
|
||||||
prof = label.profile(body.get('size'), dpmm=label.DPMM_DYMO,
|
prof = label.profile(body.get('size'), dpmm=label.DPMM_DYMO,
|
||||||
art_mm=body.get('art_mm'), margin_mm=body.get('margin'))
|
web_mm=body.get('w'), pitch_mm=body.get('h'),
|
||||||
img = label.render(body, prof, rotate=False) # 57 mm head: no rotation needed
|
margin_mm=body.get('margin'))
|
||||||
|
# The Dymo takes the SAME 24 mm stock as the Urovo, fed narrow-edge-first, so the
|
||||||
|
# landscape design has to be rotated 90 degrees here too. (The 57 mm head is wider
|
||||||
|
# than the label; that does NOT mean the label feeds landscape.) Overridable per
|
||||||
|
# request via "rotate" in case a wider Dymo roll is loaded.
|
||||||
|
rotate = body.get('rotate', True)
|
||||||
|
img = label.render(body, prof, rotate=rotate)
|
||||||
|
if img.width > dymo_mod.HEAD_BYTES * 8:
|
||||||
|
return {'ok': False, 'error': 'label is %d dots wide; Dymo head is %d'
|
||||||
|
% (img.width, dymo_mod.HEAD_BYTES * 8)}
|
||||||
with LOCK, dymo_mod.Dymo() as d:
|
with LOCK, dymo_mod.Dymo() as d:
|
||||||
before = d.status()
|
before = d.status()
|
||||||
if before is not None and not before & 0x01:
|
if before is not None and not before & 0x01:
|
||||||
|
|||||||
12
mac/dymo.py
12
mac/dymo.py
@ -131,13 +131,23 @@ class Dymo(object):
|
|||||||
def form_feed(self):
|
def form_feed(self):
|
||||||
self.write(b'\x1bE')
|
self.write(b'\x1bE')
|
||||||
|
|
||||||
def print_image(self, img, density='normal', graphics_mode=True, feed=True):
|
def print_image(self, img, density='normal', graphics_mode=False, feed=True):
|
||||||
"""Send a 1-bit PIL image, already oriented for the head (width = across head).
|
"""Send a 1-bit PIL image, already oriented for the head (width = across head).
|
||||||
|
|
||||||
|
The bitmap is assumed to be 300 dpi in BOTH axes, so the default is `ESC h`
|
||||||
|
(300x300 Text mode). `ESC i` selects 300x600 Barcode/Graphics mode, where the
|
||||||
|
head is still 300 dpi across but each raster line becomes 1/600" in the travel
|
||||||
|
direction -- printing the label at HALF length unless the image is doubled up.
|
||||||
|
So when graphics_mode is on we stretch the image 2x vertically to keep the
|
||||||
|
physical size right.
|
||||||
|
|
||||||
Returns the number of raster lines sent.
|
Returns the number of raster lines sent.
|
||||||
"""
|
"""
|
||||||
if img.mode != '1':
|
if img.mode != '1':
|
||||||
img = img.convert('1')
|
img = img.convert('1')
|
||||||
|
if graphics_mode:
|
||||||
|
from PIL import Image as _I
|
||||||
|
img = img.resize((img.width, img.height * 2), _I.NEAREST)
|
||||||
if img.width > HEAD_BYTES * 8:
|
if img.width > HEAD_BYTES * 8:
|
||||||
raise DymoError('image is %d dots wide; head is %d'
|
raise DymoError('image is %d dots wide; head is %d'
|
||||||
% (img.width, HEAD_BYTES * 8))
|
% (img.width, HEAD_BYTES * 8))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user