Skip to content

Commit 687f99c

Browse files
committed
Added support for endless labels
For issue #2
1 parent 7d1c782 commit 687f99c

File tree

5 files changed

+52
-19
lines changed

5 files changed

+52
-19
lines changed

.github/workflows/docker-image.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: Dockerhub Publish
22

33
on:
44
push:
5-
branches: [ "main" ]
5+
branches: [ "main", "develop" ]
66
tags: [ "v*" ]
77
pull_request:
88
branches: [ "main" ]

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# next
2+
3+
- Added support for printing endless labels
4+
15
# 0.3.0
26

37
- Added support for using QR codes instead of Datamatrix

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ The label size and printer are configured via environmental variables. You can a
3838
| NAME_MAX_LINES | 4 | The maximum number of lines to use for the name |
3939
| DUE_DATE_FONT | NotoSerif-Regular.ttf | The file name of the font in the fonts directory |
4040
| DUE_DATE_FONT_SIZE | 30 | The size of that font |
41+
| ENDLESS_MARGIN | 10 | The top & bottom margin to add when using endless labels |
4142

4243
Included fonts are `NotoSans-Regular.ttf` and `NotoSerif-Regular.ttf`
4344

@@ -75,7 +76,7 @@ Its advisable to run and install in a [venv](https://docs.python.org/3/library/v
7576
python -m venv .venv
7677
source ./.venv/bin/activate
7778
# Install packages
78-
python -m pip install -U -r requirements
79+
python -m pip install -U -r requirements.txt
7980
8081
# exit with ./.venv/bin/deactivate
8182
```
@@ -84,7 +85,6 @@ For development you can use `flask run --debug` to run the service on port 5000.
8485

8586
## TODO
8687

87-
- Endless Labels
8888
- Some more formatting options
8989

9090
### Docker
@@ -101,4 +101,4 @@ An example `docker-compose.yml` file can be found [here](docker-compose.yml).
101101

102102
I'll try to keep on top of bugs but feature requests may go unfulfilled. Please use the issue tracking in Github.
103103

104-
PRs welcome!
104+
PRs are welcome!

app/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
NAME_MAX_LINES = int(getenv("NAME_MAX_LINES", "4"))
2020
DUE_DATE_FONT = getenv("NAME_FONT", "NotoSerif-Regular.ttf")
2121
DUE_DATE_FONT_SIZE = int(getenv("DUE_DATE_FONT_SIZE", "30"))
22+
ENDLESS_MARGIN = int(getenv("ENDLESS_MARGIN", "10"))
2223

2324
selected_backend = guess_backend(PRINTER_PATH)
2425
BACKEND_CLASS = backend_factory(selected_backend)['backend_class']
@@ -33,7 +34,7 @@
3334

3435
@app.route("/")
3536
def home_route():
36-
return "Label %s, Size %ix%i"%(label_spec.identifier, label_spec.dots_printable[0], label_spec.dots_printable[1])
37+
return "Label %s, %s"%(label_spec.identifier, label_spec.name)
3738

3839
def get_params():
3940
source = request.form if request.method == "POST" else request.args
@@ -57,7 +58,7 @@ def get_params():
5758
def print_route():
5859
(name, barcode, dueDate) = get_params();
5960

60-
label = createLabelImage(label_spec.dots_printable, name, nameFont, NAME_MAX_LINES, createBarcode(barcode, BARCODE_FORMAT), dueDate, ddFont)
61+
label = createLabelImage(label_spec.dots_printable, ENDLESS_MARGIN, name, nameFont, NAME_FONT_SIZE, NAME_MAX_LINES, createBarcode(barcode, BARCODE_FORMAT), dueDate, ddFont)
6162

6263
buf = BytesIO()
6364
label.save(buf, format="PNG")
@@ -70,7 +71,7 @@ def print_route():
7071
def test():
7172
(name, barcode, dueDate) = get_params();
7273

73-
img = createLabelImage(label_spec.dots_printable, name, nameFont, NAME_MAX_LINES, createBarcode(barcode, BARCODE_FORMAT), dueDate, ddFont)
74+
img = createLabelImage(label_spec.dots_printable, ENDLESS_MARGIN, name, nameFont, NAME_FONT_SIZE, NAME_MAX_LINES, createBarcode(barcode, BARCODE_FORMAT), dueDate, ddFont)
7475
buf = BytesIO()
7576
img.save(buf, format="PNG")
7677
buf.seek(0)
@@ -89,4 +90,3 @@ def sendToPrinter(image : Image):
8990
be = BACKEND_CLASS(PRINTER_PATH)
9091
be.write(bql.data)
9192
del be
92-

app/imaging.py

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,36 +19,62 @@ def createBarcode(text: str, type: str):
1919
case _:
2020
return createDatamatrix(text)
2121

22-
def createLabelImage(labelSize : tuple, text : str, textFont : ImageFont, textMaxLines : int, barcode : Image, dueDate : str, dueDateFont : ImageFont):
22+
def createLabelImage(labelSize : tuple, endlessMargin : int, text : str, textFont : ImageFont, textFontSize : int, textMaxLines : int, barcode : Image, dueDate : str, dueDateFont : ImageFont):
23+
(width, height) = labelSize
24+
# default line spacing used by multiline_text, doesn't seem to have an effect if changed though but we need to take into account
25+
lineSpacing = 4
26+
# margin to use for label
27+
marginTop = 0
28+
marginBottom = 0
29+
30+
# for endless labels with a height of zero
31+
if height == 0:
32+
# height should be text size + spacing x max lines + margin x 2
33+
height = (textFontSize + lineSpacing) * textMaxLines + endlessMargin * 2
34+
# negate the empty space above the text
35+
(_, tTop, _, _) = textFont.getbbox("testing")
36+
marginTop = endlessMargin - tTop
37+
# regular bottom margin
38+
marginBottom = endlessMargin
39+
# make space for the due date
40+
if dueDate:
41+
(_, _, _, ddBottom) = dueDateFont.getbbox(dueDate)
42+
height += ddBottom
43+
2344
# increase the size of the barcode if space permits
24-
if (barcode.size[1] * 4) < labelSize[1]:
45+
if (barcode.size[1] * 8) < height:
46+
barcode = barcode.resize((barcode.size[0] * 8, barcode.size[1] * 8), Image.Resampling.NEAREST)
47+
if (barcode.size[1] * 6) < height:
48+
barcode = barcode.resize((barcode.size[0] * 6, barcode.size[1] * 6), Image.Resampling.NEAREST)
49+
if (barcode.size[1] * 4) < height:
2550
barcode = barcode.resize((barcode.size[0] * 4, barcode.size[1] * 4), Image.Resampling.NEAREST)
26-
if (barcode.size[1] * 2) < labelSize[1]:
51+
if (barcode.size[1] * 2) < height:
2752
barcode = barcode.resize((barcode.size[0] * 2, barcode.size[1] * 2), Image.Resampling.NEAREST)
2853

29-
label = Image.new("RGB", labelSize, ImageColor.getrgb("#FFF"))
30-
# vertically align barcode
54+
label = Image.new("RGB", (width, height), ImageColor.getrgb("#FFF"))
55+
# vertically align barcode (ignoring margin)
3156
barcode_padding = [0, (int)((label.size[1] / 2) - (barcode.size[1] / 2))]
3257
label.paste(barcode, barcode_padding)
3358

3459
draw = ImageDraw.Draw(label)
3560

36-
(nameText, nameTextWidth) = wrapText(text, textFont, label.size[0] - barcode.size[0], textMaxLines)
37-
nameMaxWidth = label.size[0] - barcode.size[0]
61+
(nameText, nameTextWidth) = wrapText(text, textFont, width - barcode.size[0], textMaxLines)
62+
nameMaxWidth = width - barcode.size[0]
3863
nameLeftMargin = (nameMaxWidth - nameTextWidth) / 2
3964

4065
draw.multiline_text(
41-
[barcode.size[0] + nameLeftMargin, 0],
66+
[barcode.size[0] + nameLeftMargin, marginTop],
4267
nameText,
4368
fill = ImageColor.getrgb("#000"),
4469
font = textFont,
45-
align = "center"
70+
align = "center",
71+
spacing = lineSpacing
4672
)
4773

4874
if dueDate:
4975
(_, _, ddRight, ddBottom) = dueDateFont.getbbox(dueDate)
5076
draw.text(
51-
[label.size[0] - ddRight, label.size[1] - ddBottom],
77+
[label.size[0] - ddRight, label.size[1] - ddBottom - marginBottom],
5278
dueDate,
5379
fill = ImageColor.getrgb("#000"),
5480
font = dueDateFont
@@ -100,5 +126,8 @@ def wrapText(text : str, font : ImageFont, maxWidth : int, maxLines : int):
100126
if len(lines) > maxLines:
101127
lines = lines[0:maxLines]
102128
lines[-1] += '...'
129+
lineLength = font.getlength(lines[-1])
130+
if lineLength > longestLine:
131+
longestLine = lineLength
103132

104-
return ('\n'.join(lines), longestLine)
133+
return ('\n'.join(lines), longestLine)

0 commit comments

Comments
 (0)