Skip to content

Commit 0af2949

Browse files
authored
Merge pull request #55 from maresb/improve-sample-pattern
Improve sample pattern
2 parents af7f3af + c70d8a3 commit 0af2949

20 files changed

+347
-48
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ Labelle is not affiliated with DYMO. Please see the [disclaimer](#disclaimers) b
4545

4646
For more information about experimental device support, see [#4](https://github.com/labelle-org/labelle/issues/4).
4747

48+
If you have a device or tape size that we do not yet support, the first step is
49+
to try and get it to print. In some cases this is as simple as
50+
[adding the device id](src/labelle/lib/constants.py). Once you can print,
51+
you can help us determine the print head size and margins for your tape sizes
52+
by following [these instructions](doc/margin-calibration-howto.md).
53+
4854
## Installation
4955

5056
It is recommended to install Labelle with

doc/dirty-print-head.png

675 KB
Loading

doc/margin-calibration-howto.md

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# How to calibrate the label margins of DYMO printers
2+
3+
Calibration can be used to determine:
4+
5+
* Is the print head clean?
6+
* If the printer or tape has not yet been measured and recorded in Labelle, then:
7+
* How many pixels and what resolution does the print head have?
8+
* For a given tape, which pixels correspond to which part of the tape?
9+
10+
Since most Labelle contributors have only a single printer and tape,
11+
we rely on the community to provide the necessary information to support
12+
other devices and tape sizes. You do not need to understand the entire process
13+
to contribute; we are happy to help you interpret the results. Please see
14+
[submitting calibration data](#submitting-calibration-data) for a detailed summary
15+
of the process.
16+
17+
We track the status of supported devices
18+
[here](https://github.com/labelle-org/labelle/issues/4).
19+
20+
## General information
21+
22+
Each model of DYMO printer has a stationary print head of some fixed height.
23+
Calibration consists of printing a sample pattern of that same height.
24+
(If the height of the print head is unknown, see
25+
[determining the height of the print head](#determining-the-height-of-the-print-head).)
26+
27+
Many DYMO printers have a print head that is 64 pixels high, and such a
28+
sample pattern can be printed with the command
29+
30+
```shell
31+
labelle --sample-pattern 64
32+
```
33+
34+
resulting in a pattern like this:
35+
36+
<!-- markdownlint-disable MD033 -->
37+
<img src="sample-pattern-64.png" alt="64 pixel pattern"
38+
style="width:909px;height:273px;image-rendering:pixelated">
39+
<!-- markdownlint-enable MD033 -->
40+
41+
Here is this pattern printed on 12mm tape with a DYMO LabelManager PnP:
42+
43+
![printed 64-pixel pattern 12mm tape](sample-pattern-64-12mm-labelwriter-pnp.png)
44+
45+
### Counting rows
46+
47+
The numbering of printable rows increases from bottom to top.
48+
To make counting more human-friendly, we start counting with 1.
49+
Thus in the example above, the bottom row is 1 and the top row is 64.
50+
Groups of 16 pixels in alternating colors are indicated by the numbers.
51+
The 48th row is the topmost row within the black block marked as 48.
52+
The dyadic checkerboard to the left of the numbers is designed to help with
53+
counting individual rows of pixels.
54+
It consists of alternating groups of 8, 4, 2, and 1 pixels.
55+
56+
Around each of the four corners of the pattern are groups of four
57+
staggered horizontal lines.
58+
These are helpful for checking whether or not the topmost and bottommost
59+
pixels are printed correctly.
60+
61+
### Tape sizes
62+
63+
Many DYMO printers support 6mm, 9mm, and 12mm D1 tapes
64+
and have a 64 pixel print head with a 9mm printable height.
65+
66+
The LabelManager PC II has a 128 pixel print head with an 18mm printable height.
67+
This makes it practical for use with the larger 19mm and 24mm D1 tapes.
68+
An unofficial list of DYMO printers and compatible tape sizes
69+
can be found [here](https://www.labelcity.com/dymo-d1-label-tape-compatibility-guide).
70+
71+
When the tape is shorter than the printable height, the tape occupies
72+
some range of pixels near the middle of the print head.
73+
74+
The procedure to determine the pixel range of a tape is described in
75+
[determining the pixel range of a tape](#determining-the-pixel-range-of-a-tape).
76+
77+
## Checking the cleanliness of the print head
78+
79+
When the print head is dirty, some rows will print inconsistently, faintly,
80+
or not at all. In the following example we see several problematic rows
81+
along the bottom.
82+
83+
![dirty print head](dirty-print-head.png)
84+
85+
Many DYMO printers come with a yellow brush for cleaning the print head, as
86+
illustrated in [this video](https://www.youtube.com/watch?v=tu3jLmO06zE).
87+
88+
After gently cleaning the print head, the sample pattern should print sharply,
89+
similarly to the other photos in this document.
90+
91+
## Determining the height of the print head
92+
93+
The height of the print head can be determined by printing a sample
94+
pattern of very large height.
95+
(In order to achieve conclusive results, the tape size must be larger than
96+
the print head.)
97+
Simply print a sample pattern that is very large and it will be
98+
truncated at the top.
99+
The height of the print head is the topmost row that is printed, assuming
100+
that there is a margin at the top of the tape.
101+
102+
For example, on the DYMO LabelManager PnP, the command
103+
104+
```shell
105+
labelle --sample-pattern 512
106+
```
107+
108+
prints the following label, from which we conclude that the print head
109+
is 64 pixels high:
110+
111+
![sample-pattern-256-12mm-labelwriter-pnp](sample-pattern-256-12mm-labelwriter-pnp.png)
112+
113+
## Determining the pixel range of a tape
114+
115+
Some [tapes](#tape-sizes) may not span the full printable height of the print head.
116+
For such tapes, we want to [identify which pixel rows](#counting-rows) correspond
117+
to the tape's bottom and top edges.
118+
119+
We can identify the precise range of pixels by means of
120+
a sample pattern of a given height.
121+
122+
![9mm tape](sample-pattern-64-9mm-labelwriter-pnp.png)
123+
124+
In this example, the bottom row is 2 and the top row is 64. The easiest way to
125+
see this is that the top corners have all four pairs of staggered lines, while
126+
along the bottom corners the bottommost line is missing.
127+
128+
Alternatively, it is possible to use the dyadic checkerboard to count down
129+
from the top of the 16-block to obtain 2 at the bottom. It is similarly
130+
possible to count up from the top of the 48-block to obtain 64 at the top.
131+
132+
Note that it is possible that the tape shifts up or down by a pixel depending
133+
on how the cartridge is inserted into the printer. It is also possible that rows
134+
along the top or bottom edges are faded, as shown here:
135+
136+
![zoom of faded 9mm tape](sample-pattern-64-9mm-labelwriter-pnp-zoomed.png)
137+
138+
## Submitting calibration data
139+
140+
Thank you for taking the time to submit calibration data!
141+
142+
The developers of Labelle are grateful for any information you can provide,
143+
and will help you to interpret the calibration results.
144+
Please report the results in a
145+
[new issue](https://github.com/labelle-org/labelle/issues/new).
146+
147+
Ideally the results should include one or more photos of the printed sample patterns.
148+
The photos should be high enough resolution to show the individual pixels.
149+
150+
If the device is not yet supported, then the first step is to determine the height
151+
of the print head. See
152+
[determining the height of the print head](#determining-the-height-of-the-print-head).
153+
154+
Please also measure the height in mm of the sample pattern so that we can determine
155+
the resolution of the print head.
156+
Please also measure the top and bottom margins in mm.
157+
158+
It may be necessary to
159+
[clean the print head](#checking-the-cleanliness-of-the-print-head) to ensure
160+
accurate results.
161+
162+
If you have alternate tape sizes, please provide photos that
163+
[show the pixel range of the tape](#determining-the-pixel-range-of-a-tape).
164+
165+
Checklist:
166+
167+
* The height of the print head in pixels is determined if not previously known.
168+
* The height of the sample pattern in mm is measured if not previously known.
169+
* The print head is clean.
170+
* For each tape size that you have:
171+
* A photo of the sample pattern is provided.
172+
* Measurements in mm of the top and bottom margins if the sample pattern doesn't
173+
extend to the edges of the tape.
174+
* This information is submitted in a new GitHub issue.
175+
176+
Example: See [#60](https://github.com/labelle-org/labelle/issues/60)
475 KB
Loading
863 KB
Loading
92.7 KB
Loading
954 KB
Loading

doc/sample-pattern-64.png

1.25 KB
Loading

src/labelle/cli/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ def default(
161161
] = Direction.LEFT,
162162
sample_pattern: Annotated[
163163
Optional[int],
164-
typer.Option(help="Prints test pattern of a desired dot width"),
164+
typer.Option(help="Prints test pattern of a desired dot height [px]"),
165165
] = None,
166166
min_length: Annotated[
167167
Optional[float],

src/labelle/lib/render_engines/horizontally_combined.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,16 @@
1010

1111

1212
class HorizontallyCombinedRenderEngine(RenderEngine):
13-
PADDING = 4
13+
padding: int
1414

1515
def __init__(
1616
self,
1717
render_engines: Sequence[RenderEngine],
18+
padding: int = 4,
1819
):
1920
super().__init__()
2021
self.render_engines = render_engines
22+
self.padding = padding
2123

2224
def render(self, context: RenderContext) -> Image.Image:
2325
render_engines = self.render_engines or [EmptyRenderEngine()]
@@ -27,17 +29,24 @@ def render(self, context: RenderContext) -> Image.Image:
2729
merged_bitmap = bitmaps[0]
2830
else:
2931
label_height = max(b.height for b in bitmaps)
30-
merged_bitmap = Image.new(
31-
"1",
32-
(
33-
sum(b.width for b in bitmaps) + self.PADDING * (len(bitmaps) - 1),
34-
label_height,
35-
),
36-
)
32+
total_width = _compute_total_width(bitmaps, self.padding)
33+
merged_bitmap = Image.new("1", (total_width, label_height))
3734
x_offset = 0
3835
for bitmap in bitmaps:
39-
y_offset = (label_height - bitmap.size[1]) // 2
36+
y_offset = (label_height - bitmap.height) // 2
4037
merged_bitmap.paste(bitmap, box=(x_offset, y_offset))
41-
x_offset += bitmap.width + self.PADDING
38+
x_offset += bitmap.width + self.padding
4239

4340
return merged_bitmap
41+
42+
43+
def _compute_total_width(bitmaps: Sequence[Image.Image], padding: int) -> int:
44+
number_of_bitmaps = len(bitmaps)
45+
width_of_bitmaps = sum(b.width for b in bitmaps)
46+
47+
# We alternate bitmaps and padding, and have bitmaps on each end.
48+
number_of_paddings = number_of_bitmaps - 1
49+
width_of_paddings = number_of_paddings * padding
50+
51+
total_width = width_of_bitmaps + width_of_paddings
52+
return total_width

0 commit comments

Comments
 (0)