feat: add several options for customizing label placement
* --row-wise, for going left to right instead of top to bottom * --num-labels, for specifying how many labels to print * --pages, for specifying how many pages to print * --start-position, for continuing on sheets where some labels were already used Co-authored-by: Jan Christian Grünhage <jan.christian@gruenhage.xyz>
This commit is contained in:
parent
a6e8fadf72
commit
d5d9b7adad
13 changed files with 1990 additions and 10 deletions
19
.direnv/bin/nix-direnv-reload
Executable file
19
.direnv/bin/nix-direnv-reload
Executable file
|
|
@ -0,0 +1,19 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
if [[ ! -d "/home/khais/src/paperless-asn-qr-codes" ]]; then
|
||||||
|
echo "Cannot find source directory; Did you move it?"
|
||||||
|
echo "(Looking for "/home/khais/src/paperless-asn-qr-codes")"
|
||||||
|
echo 'Cannot force reload with this script - use "direnv reload" manually and then try again'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# rebuild the cache forcefully
|
||||||
|
_nix_direnv_force_reload=1 direnv exec "/home/khais/src/paperless-asn-qr-codes" true
|
||||||
|
|
||||||
|
# Update the mtime for .envrc.
|
||||||
|
# This will cause direnv to reload again - but without re-building.
|
||||||
|
touch "/home/khais/src/paperless-asn-qr-codes/.envrc"
|
||||||
|
|
||||||
|
# Also update the timestamp of whatever profile_rc we have.
|
||||||
|
# This makes sure that we know we are up to date.
|
||||||
|
touch -r "/home/khais/src/paperless-asn-qr-codes/.envrc" "/home/khais/src/paperless-asn-qr-codes/.direnv"/*.rc
|
||||||
1
.direnv/flake-inputs/52bigbj1vfhdkwzqg0yrh3fdawz0pflj-source
Symbolic link
1
.direnv/flake-inputs/52bigbj1vfhdkwzqg0yrh3fdawz0pflj-source
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/nix/store/52bigbj1vfhdkwzqg0yrh3fdawz0pflj-source
|
||||||
1
.direnv/flake-inputs/cnpq7gggc6ch7hvqy5xrnra8rz8ch8i2-source
Symbolic link
1
.direnv/flake-inputs/cnpq7gggc6ch7hvqy5xrnra8rz8ch8i2-source
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/nix/store/cnpq7gggc6ch7hvqy5xrnra8rz8ch8i2-source
|
||||||
1
.direnv/flake-inputs/d6533m6b80n3c9lia5kvaz59ad3fynwk-source
Symbolic link
1
.direnv/flake-inputs/d6533m6b80n3c9lia5kvaz59ad3fynwk-source
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/nix/store/d6533m6b80n3c9lia5kvaz59ad3fynwk-source
|
||||||
1
.direnv/flake-inputs/frdjqj92bbc99qzy1aa0xx19f40a2ar2-source
Symbolic link
1
.direnv/flake-inputs/frdjqj92bbc99qzy1aa0xx19f40a2ar2-source
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/nix/store/frdjqj92bbc99qzy1aa0xx19f40a2ar2-source
|
||||||
1
.direnv/flake-inputs/kqx126kbcqsdhrbm96j2m87drpd1s0y8-source
Symbolic link
1
.direnv/flake-inputs/kqx126kbcqsdhrbm96j2m87drpd1s0y8-source
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/nix/store/kqx126kbcqsdhrbm96j2m87drpd1s0y8-source
|
||||||
1
.direnv/flake-inputs/wafxi383ckrchp0aqil8rnq4vzkih320-source
Symbolic link
1
.direnv/flake-inputs/wafxi383ckrchp0aqil8rnq4vzkih320-source
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/nix/store/wafxi383ckrchp0aqil8rnq4vzkih320-source
|
||||||
1
.direnv/flake-profile-a5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa
Symbolic link
1
.direnv/flake-profile-a5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/nix/store/9hajvbjb10nnbbaclnly2fzkhkyj21jz-nix-shell-env
|
||||||
1881
.direnv/flake-profile-a5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa.rc
Normal file
1881
.direnv/flake-profile-a5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa.rc
Normal file
File diff suppressed because it is too large
Load diff
15
README.md
15
README.md
|
|
@ -13,7 +13,9 @@ pip install paperless-asn-qr-codes
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
usage: paperless-asn-qr-codes [-h] [--format {averyL4731,avery5160,avery5161,avery5163,avery5167,avery5371}] [--border] start_asn output_file
|
usage: paperless-asn-qr-codes [-h] [--format {averyL4731,avery5160,avery5161,avery5163,avery5167,avery5371}] [--digits DIGITS] [--border] [--row-wise] [--num-labels NUM_LABELS] [--pages PAGES]
|
||||||
|
[--start-position START_POSITION]
|
||||||
|
start_asn output_file
|
||||||
|
|
||||||
CLI Tool for generating paperless ASN labels with QR codes
|
CLI Tool for generating paperless ASN labels with QR codes
|
||||||
|
|
||||||
|
|
@ -27,6 +29,13 @@ options:
|
||||||
--digits DIGITS, -d DIGITS
|
--digits DIGITS, -d DIGITS
|
||||||
Number of digits in the ASN (default: 7, produces 'ASN0000001')
|
Number of digits in the ASN (default: 7, produces 'ASN0000001')
|
||||||
--border, -b Display borders around labels, useful for debugging the printer alignment
|
--border, -b Display borders around labels, useful for debugging the printer alignment
|
||||||
|
--row-wise, -r Increment the ASNs row-wise, go from left to right
|
||||||
|
--num-labels NUM_LABELS, -n NUM_LABELS
|
||||||
|
Number of labels to be printed on the sheet
|
||||||
|
--pages PAGES, -p PAGES
|
||||||
|
Number of pages to be printed, ignored if NUM_LABELS is set (default: 1)
|
||||||
|
--start-position START_POSITION, -s START_POSITION
|
||||||
|
Define the starting position on the sheet, eighter as ROW:COLUMN or COUNT, both starting from 1 (default: 1:1 or 1)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Mandatory arguments
|
### Mandatory arguments
|
||||||
|
|
@ -43,6 +52,10 @@ options:
|
||||||
- `-f`, `--format`: Selects the format of the output sheet (see [Supported Sheets](#supported-sheets))
|
- `-f`, `--format`: Selects the format of the output sheet (see [Supported Sheets](#supported-sheets))
|
||||||
- `-d`, `--digits`: Specifies the number of digits in the ASN (e.g. for the default number 7, the ASN will look like 'ASN0000001')
|
- `-d`, `--digits`: Specifies the number of digits in the ASN (e.g. for the default number 7, the ASN will look like 'ASN0000001')
|
||||||
- `-b`, `--border`: Generates the borders around the labels to help debug alignment issues (see [Tips & Tricks](#tips--tricks))
|
- `-b`, `--border`: Generates the borders around the labels to help debug alignment issues (see [Tips & Tricks](#tips--tricks))
|
||||||
|
- `-r`, `--row-wise`: Increments the labels from left to right instead of top to bottom
|
||||||
|
- `-n`, `--num-labels`: Number of lables to be printed on the sheet
|
||||||
|
- `-p`, `--pages`: Number of pages to be generated, ignored if -n is present.
|
||||||
|
- `-s`, `--start-position`: Positon of first label to be printed, eighter defined as ROW:COLUMN or NUMBER. Starting from 1 eg. to use the whole sheet it would be 1:1 or 1. Useful if you have a partly used sheet from using `-n`.
|
||||||
|
|
||||||
## Supported Sheets
|
## Supported Sheets
|
||||||
Some different sheet types are supported with the `-f`/`--format` argument, however, not all are tested.
|
Some different sheet types are supported with the `-f`/`--format` argument, however, not all are tested.
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,9 @@ BUSINESS_CARDS = 5371
|
||||||
|
|
||||||
|
|
||||||
class AveryLabel:
|
class AveryLabel:
|
||||||
def __init__(self, label, debug, **kwargs):
|
def __init__(self, label, debug,
|
||||||
|
topDown=True, start_pos=None,
|
||||||
|
**kwargs):
|
||||||
data = labelInfo[label]
|
data = labelInfo[label]
|
||||||
self.across = data.labels_horizontal
|
self.across = data.labels_horizontal
|
||||||
self.down = data.labels_vertical
|
self.down = data.labels_vertical
|
||||||
|
|
@ -99,10 +101,27 @@ class AveryLabel:
|
||||||
self.size[1] + data.gutter_size[1],
|
self.size[1] + data.gutter_size[1],
|
||||||
)
|
)
|
||||||
self.margins = data.margin
|
self.margins = data.margin
|
||||||
self.topDown = True
|
self.topDown = topDown
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
self.pagesize = data.pagesize
|
self.pagesize = data.pagesize
|
||||||
self.position = 0
|
|
||||||
|
#Calculate start offset
|
||||||
|
if isinstance(start_pos, tuple):
|
||||||
|
rows, columns = start_pos
|
||||||
|
# Minimum Value 1 for row/column
|
||||||
|
rows = max(rows, 1)
|
||||||
|
columns = max(columns, 1)
|
||||||
|
if self.topDown:
|
||||||
|
offset = (columns - 1) * self.down + rows - 1
|
||||||
|
else:
|
||||||
|
offset = (rows - 1) * self.across + columns - 1
|
||||||
|
elif start_pos:
|
||||||
|
offset = start_pos - 1
|
||||||
|
else:
|
||||||
|
offset = 0
|
||||||
|
# Limit start position to number of labels - 1
|
||||||
|
self.position = min(offset, self.across * self.down - 1)
|
||||||
|
|
||||||
self.__dict__.update(kwargs)
|
self.__dict__.update(kwargs)
|
||||||
|
|
||||||
def open(self, filename):
|
def open(self, filename):
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import argparse
|
import argparse
|
||||||
|
import re
|
||||||
|
|
||||||
from reportlab.lib.units import mm
|
from reportlab.lib.units import mm
|
||||||
from reportlab_qrcode import QRCodeImage
|
from reportlab_qrcode import QRCodeImage
|
||||||
|
|
@ -19,6 +20,15 @@ def render(c, x, y):
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
# Match the starting position parameter. Allow x:y or n
|
||||||
|
def _start_position(arg):
|
||||||
|
if mat := re.match(r"^(\d{1,2}):(\d{1,2})$", arg):
|
||||||
|
return (int(mat.group(1)), int(mat.group(2)))
|
||||||
|
elif mat := re.match(r"^\d+$", arg):
|
||||||
|
return int(arg)
|
||||||
|
else:
|
||||||
|
raise argparse.ArgumentTypeError("invalid value")
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
prog="paperless-asn-qr-codes",
|
prog="paperless-asn-qr-codes",
|
||||||
description="CLI Tool for generating paperless ASN labels with QR codes",
|
description="CLI Tool for generating paperless ASN labels with QR codes",
|
||||||
|
|
@ -46,17 +56,47 @@ def main():
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Display borders around labels, useful for debugging the printer alignment",
|
help="Display borders around labels, useful for debugging the printer alignment",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--row-wise",
|
||||||
|
"-r",
|
||||||
|
action="store_false",
|
||||||
|
help="Increment the ASNs row-wise, go from left to right",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--num-labels",
|
||||||
|
"-n",
|
||||||
|
type=int,
|
||||||
|
help="Number of labels to be printed on the sheet",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--pages",
|
||||||
|
"-p",
|
||||||
|
type=int,
|
||||||
|
default=1,
|
||||||
|
help="Number of pages to be printed, ignored if NUM_LABELS is set (default: 1)",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--start-position",
|
||||||
|
"-s",
|
||||||
|
type=_start_position,
|
||||||
|
help="Define the starting position on the sheet, eighter as ROW:COLUMN or COUNT, both starting from 1 (default: 1:1 or 1)",
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
global startASN
|
global startASN
|
||||||
global digits
|
global digits
|
||||||
startASN = int(args.start_asn)
|
startASN = int(args.start_asn)
|
||||||
digits = int(args.digits)
|
digits = int(args.digits)
|
||||||
label = avery_labels.AveryLabel(args.format, args.border)
|
label = avery_labels.AveryLabel(
|
||||||
label.open(args.output_file)
|
args.format, args.border, topDown=args.row_wise, start_pos=args.start_position
|
||||||
# by default, we render all labels possible on a single sheet
|
|
||||||
count = (
|
|
||||||
avery_labels.labelInfo[args.format].labels_horizontal
|
|
||||||
* avery_labels.labelInfo[args.format].labels_vertical
|
|
||||||
)
|
)
|
||||||
|
label.open(args.output_file)
|
||||||
|
|
||||||
|
# If defined use parameter for number of labels
|
||||||
|
if args.num_labels:
|
||||||
|
count = args.num_labels
|
||||||
|
else:
|
||||||
|
# Otherwise number of pages*labels - offset
|
||||||
|
count = args.pages * label.across * label.down - label.position
|
||||||
label.render(render, count)
|
label.render(render, count)
|
||||||
label.close()
|
label.close()
|
||||||
|
|
|
||||||
1
result
Symbolic link
1
result
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/nix/store/ssf3fxka9p8a8qyq0955qcxxj3lnx3cy-python3.11-paperless-asn-qr-codes-0.4.0
|
||||||
Loading…
Add table
Add a link
Reference in a new issue