Skip to content

Commit

Permalink
Merge branch 'release/0.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
sam159 committed Dec 25, 2023
2 parents 285351e + 3897da3 commit d5fad70
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 12 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# 0.2.0

- Scaling barcode by 2x or 4x space permitting
- Centered text
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Brother QL Grocy Label Printer Service

![Example Label](example.png)
<img src="example.png" alt="Example Label" width="348" height="135">

This project is intended to be a webhook target for [Grocy](https://github.com/grocy/grocy) to print labels to a brother QL label printer. Datamatrix barcodes are used instead of QR or linear barcodes, this matches what Grocy uses by default.

Expand Down Expand Up @@ -65,13 +65,20 @@ This has been tested with python 3.10, newer may work fine.

You will need to install the `libdmtx` library for the barcodes to generate, see [pylibdmtx](https://pypi.org/project/pylibdmtx/) documentation on pypi.

Its advisable to run and install in a venv. For example:
Its advisable to run and install in a [venv](https://docs.python.org/3/library/venv.html). For example:

```
# Create and enter the venv
python -m venv .venv
source ./.venv/bin/activate
# Install packages
python -m pip install -U -r requirements
# exit with ./.venv/bin/deactivate
```

For development you can use `flask run --debug` to run the service on port 5000. Alternatively use `gunicorn -c gunicorn_conf.py app:app` to run the service on port 8000.

## TODO

- Endless Labels
Expand All @@ -81,9 +88,11 @@ Its advisable to run and install in a venv. For example:

A Dockerfile is included based on a python 3.10 alpine image. The default port is 8000.

Published to Dockerhub as [sam159/brotherql_grocylabels](https://hub.docker.com/r/sam159/brotherql_grocylabels)
Published to Dockerhub as [sam159/brotherql_grocylabels](https://hub.docker.com/r/sam159/brotherql_grocylabels) for architectures amd64, arm64, and armv7.

As an example, you can launch this with `docker run -d -p 8000:8000 -e PRINTER_MODEL=QL-500 -e PRINTER_PATH=file:///dev/usb/lp1 sam159/brotherql_grocylabels:latest`.

As an example, you can launch this with `docker run -d -p 8000:8000 -e PRINTER_MODEL="QL-500" -e PRINTER_PATH="file:///dev/usb/lp1" sam159/brotherql_grocylabels:latest`
An example `docker-compose.yml` file can be found [here](docker-compose.yml).

## Contributing

Expand Down
11 changes: 11 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: "3.8"

services:
printer:
image: sam159/brotherql_grocylabels:latest
restart: unless-stopped
environment:
- PRINTER_MODEL=QL-500
- PRINTER_PATH=file:///dev/usb/lp1
ports:
- 8000:8000
Binary file modified example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 26 additions & 8 deletions imaging.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,41 @@
from PIL import Image, ImageColor, ImageFont, ImageDraw

def createBarcode(text: str):
encoded = encode(text.encode('utf8'), "Ascii", "32x32")
encoded = encode(text.encode('utf8'), "Ascii", "ShapeAuto")
barcode = Image.frombytes('RGB', (encoded.width, encoded.height), encoded.pixels)
return barcode

def createLabelImage(labelSize : tuple, text : str, textFont : ImageFont, textMaxLines : int, barcode : Image, dueDate : str, dueDateFont : ImageFont):
# increase the size of the barcode if space permits
if (barcode.size[1] * 4) < labelSize[1]:
barcode = barcode.resize((barcode.size[0] * 4, barcode.size[1] * 4), Image.Resampling.NEAREST)
if (barcode.size[1] * 2) < labelSize[1]:
barcode = barcode.resize((barcode.size[0] * 2, barcode.size[1] * 2), Image.Resampling.NEAREST)

label = Image.new("RGB", labelSize, ImageColor.getrgb("#FFF"))
barcode_padding = [0, (int)((label.size[1] / 2) - (barcode.size[1] / 2))]
label.paste(barcode, barcode_padding)

draw = ImageDraw.Draw(label)

(nameText, nameTextWidth) = wrapText(text, textFont, label.size[0] - barcode.size[0], textMaxLines)
nameMaxWidth = label.size[0] - barcode.size[0]
nameLeftMargin = (nameMaxWidth - nameTextWidth) / 2

print((nameTextWidth, nameMaxWidth, nameLeftMargin))

draw.multiline_text(
[barcode.size[1], 0],
wrapText(text, textFont, label.size[0] - barcode.size[0], textMaxLines),
[barcode.size[0] + nameLeftMargin, 0],
nameText,
fill = ImageColor.getrgb("#000"),
font = textFont
font = textFont,
align = "center"
)

if dueDate:
(_, _, _, ddbottom) = dueDateFont.getbbox(dueDate)
(_, _, ddRight, ddBottom) = dueDateFont.getbbox(dueDate)
draw.text(
[barcode.size[1], label.size[1] - ddbottom],
[label.size[0] - ddRight, label.size[1] - ddBottom],
dueDate,
fill = ImageColor.getrgb("#000"),
font = dueDateFont
Expand All @@ -34,6 +48,7 @@ def wrapText(text : str, font : ImageFont, maxWidth : int, maxLines : int):
parts = text.split(" ")
parts.reverse()
lines = []
longestLine = 0

# break words that are too long for a single line
trimmedParts = []
Expand Down Expand Up @@ -65,10 +80,13 @@ def wrapText(text : str, font : ImageFont, maxWidth : int, maxLines : int):

# finished with the line
if len(nextLine) > 0:
lines.append(' '.join(nextLine));
lines.append(' '.join(nextLine))
lineLength = font.getlength(' '.join(nextLine))
if lineLength > longestLine:
longestLine = lineLength

if len(lines) > maxLines:
lines = lines[0:maxLines]
lines[-1] += '...'

return '\n'.join(lines)
return ('\n'.join(lines), longestLine)

0 comments on commit d5fad70

Please sign in to comment.