From e2bb5dfc9c638888bc03d8cd6065119f268bdb45 Mon Sep 17 00:00:00 2001 From: aborelis Date: Tue, 14 May 2024 01:23:51 +0200 Subject: [PATCH 01/13] Create pylint.yml --- .github/workflows/pylint.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/pylint.yml diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml new file mode 100644 index 0000000..c73e032 --- /dev/null +++ b/.github/workflows/pylint.yml @@ -0,0 +1,23 @@ +name: Pylint + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.8", "3.9", "3.10"] + steps: + - uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pylint + - name: Analysing the code with pylint + run: | + pylint $(git ls-files '*.py') From b8cdab0e4a9476139f031fa63a5930984269240a Mon Sep 17 00:00:00 2001 From: Aborelis Date: Tue, 14 May 2024 01:53:27 +0200 Subject: [PATCH 02/13] cleanup --- .gitignore | 5 + asn-gen.py | 299 +++++++++++++++++++++++++++-------------------------- out/empty | 0 3 files changed, 160 insertions(+), 144 deletions(-) create mode 100644 .gitignore create mode 100644 out/empty diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b544cd4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +__pycache__ +venv +.idea +/*.pdf +out/*.pdf \ No newline at end of file diff --git a/asn-gen.py b/asn-gen.py index 7c2fabe..2f99451 100755 --- a/asn-gen.py +++ b/asn-gen.py @@ -1,215 +1,226 @@ #!/usr/bin/env python3 -import os -import sys +from functools import partial import AveryLabels from AveryLabels import labelInfo from reportlab.lib.units import mm from reportlab.lib.units import toLength -from reportlab_qrcode import QRCodeImage from reportlab.pdfgen import canvas from reportlab.lib.colors import HexColor -#from reportlab.graphics import shapes +from reportlab_qrcode import QRCodeImage -from clize import ArgumentError, Parameter, run +# from reportlab.graphics import shapes + +from clize import run -from functools import partial -import inspect - -project_homepage = 'https://github.com/aborelis/ASN-Label-Generator' +project_homepage = "https://github.com/aborelis/ASN-Label-Generator" class LabelContext: - def __init__(self, data): - - self.label = 4731 - self.number =189 - numDigits = 6 - self.firstAsn = 1 + self.filename = None + + self.labeltype = 4731 + self.number = 189 + + self.num_digits = 6 + self.first_asn = 1 self.offset = 0 - self.fontSize=2*mm - self.qrSize = 0.9 - self.qrMargin = 1*mm + self.font_size = 2 * mm + self.qr_size = 0.9 + self.qr_margin = 1 * mm - self.subLabelsX = 1 - self.subLabelsY = 1 - - self.debug = False - self.positionHelper = False + self.sub_labels_x = 1 + self.sub_labels_y = 1 - + self.debug = False + self.position_helper = False - self.barWidth=0 - self.barColor= HexColor('#d2dede') - self.highlightBarWidth = 0 - self.highlightBarColor= HexColor('#d9a4a6') - self.prefix='ASN' + self.bar_width = 0 + self.bar_color = HexColor("#d2dede") + self.highlight_bar_width = 0 + self.highlight_bar_color = HexColor("#d9a4a6") + self.prefix = "ASN" - self.__dict__.update(data) - - self.currentASN = self.firstAsn - + self.__dict__.update(data) + + self.current_asn = self.first_asn def incASN(self): - self.currentASN = self.currentASN + 1 + self.current_asn = self.current_asn + 1 +def render(context: LabelContext, c: canvas.Canvas, width: float, height: float): + + sub_label_width = width / context.sub_labels_x + sub_labelheight = height / context.sub_labels_y + + for i in range(context.sub_labels_x): + for j in range(context.sub_labels_y - 1, -1, -1): # no idea why inverted... + sub_x = sub_label_width * i + sub_y = sub_labelheight * j + + c.saveState() + c.translate(sub_x, sub_y) + + # barcode_value = f"ASN{currentASN:06d}" + barcode_value = context.prefix + str(context.current_asn).zfill( + context.num_digits + ) + context.incASN() + + qr = QRCodeImage(barcode_value, size=sub_labelheight * context.qr_size) + qr.drawOn( + c, x=context.qr_margin, y=sub_labelheight * ((1 - context.qr_size) / 2) + ) + c.setFont("Helvetica", size=context.font_size) + c.drawString( + x=sub_labelheight, + y=(sub_labelheight - context.font_size) / 2, + text=barcode_value, + ) + + if context.bar_width > 0: + c.setFillColor(context.bar_color) + c.rect( + sub_label_width - context.bar_width, + 0, + context.bar_width, + sub_labelheight, + 0, + 1, + ) + if context.highlight_bar_width > 0: + c.setFillColor(context.highlight_bar_color) + c.rect( + sub_label_width - context.bar_width - context.highlight_bar_width, + 0, + context.highlight_bar_width, + sub_labelheight, + 0, + 1, + ) + + if context.position_helper: + r = 0.1 + d = 0 + if context.debug: + r = 0.5 + d = r + c.circle(x_cen=0 + d, y_cen=0 + d, r=r, stroke=1) + c.circle(x_cen=sub_label_width - d, y_cen=0 + d, r=r, stroke=1) + c.circle(x_cen=0 + d, y_cen=sub_labelheight - d, r=r, stroke=1) + c.circle( + x_cen=sub_label_width - d, y_cen=sub_labelheight - d, r=r, stroke=1 + ) + + c.restoreState() - -def render(context: LabelContext , c: canvas.Canvas, width: float, height: float): - - - subLabelWidth = width/context.subLabelsX - subLabelHeight = height/context.subLabelsY - - for i in range(context.subLabelsX): - for j in range(context.subLabelsY-1, -1, -1): # no idea why inverted... - subX = subLabelWidth*i - subY = subLabelHeight*j - - c.saveState() - c.translate(subX, subY) - - # barcode_value = f"ASN{currentASN:06d}" - barcode_value = context.prefix+str(context.currentASN).zfill(context.numDigits) - context.incASN() - - qr = QRCodeImage(barcode_value, size=subLabelHeight*context.qrSize) - qr.drawOn(c, x=context.qrMargin, y=subLabelHeight*((1-context.qrSize)/2)) - c.setFont("Helvetica", size=context.fontSize) - c.drawString(x=subLabelHeight, y=( - subLabelHeight-context.fontSize)/2, text=barcode_value) - - if context.barWidth > 0 : - c.setFillColor(context.barColor) - c.rect(subLabelWidth-context.barWidth, 0, context.barWidth, subLabelHeight,0, 1) - if context.highlightBarWidth > 0 : - c.setFillColor(context.highlightBarColor) - c.rect(subLabelWidth-context.barWidth-context.highlightBarWidth, 0, context.highlightBarWidth, subLabelHeight,0, 1) - - - - if context.positionHelper: - r = 0.1 - d = 0 - if context.debug: - r = 0.5 - d = r - c.circle(x_cen=0+d, y_cen=0+d, r=r, stroke=1) - c.circle(x_cen=subLabelWidth-d, y_cen=0+d, r=r, stroke=1) - c.circle(x_cen=0+d, y_cen=subLabelHeight-d, r=r, stroke=1) - c.circle(x_cen=subLabelWidth-d, - y_cen=subLabelHeight-d, r=r, stroke=1) - - c.restoreState() - - - - -def generate( filename = None, *, labeltype:'l' = '4731', - number:'n'= 189, - offset:'o' = 0, - numDigits:'d'= 6, - firstAsn:'s' = 1, - fontSize:'f' = '2mm', - qrSize:'q' = 0.9, - qrMargin:'m' = '1mm', - - subLabelsX:'lx' = 1, - subLabelsY:'ly' = 1, - - debug = False , - positionHelper = False, - - - - barWidth:'bw'=0, - barColor:'bc'= 'd2dede', - highlightBarWidth:'hw'= 0 , - highlightBarColor:'hc'= 'd9a4a6', - prefix:'p' = 'ASN' -): +def generate( + filename=None, + *, + labeltype: "l" = "4731", + number: "n" = 189, # type: ignore + offset: "o" = 0, # type: ignore + num_digits: "d" = 6, # type: ignore + first_asn: "s" = 1, # type: ignore + font_size: "f" = "2mm", # type: ignore + qr_size: "q" = 0.9, # type: ignore + qr_margin: "m" = "1mm", # type: ignore + sub_labels_x: "lx" = 1, # type: ignore + sub_labels_y: "ly" = 1, # type: ignore + debug=False, + position_helper=False, + bar_width: "bw" = 0, # type: ignore + bar_color: "bc" = "d2dede", # type: ignore + highlight_bar_width: "hw" = 0, # type: ignore + highlight_bar_color: "hc" = "d9a4a6", # type: ignore + prefix: "p" = "ASN", # type: ignore +): """ASN Label Generator - + :param filename: output filename of PDF file generated :param labeltype: Type of label, e.g. 4731, get a list of supported labels with --labels :param number: number of labels to generate :param offset: Number of labels to skip on the first sheet (e.g. already used) - :param numDigits: Number of digits for the ASN, e.g. 000001 - :param firstAsn: First ASN to use, e.g. 100001 - - - :param fontSize: Fontsize with a unit, e.g. 2mm, 0.4cm - :param qrSize: Size of the QR-Code as percentage of the label hight - :param qrMargin: Margin around the QR-Code with a unit, e.g. 1mm + :param num_digits: Number of digits for the ASN, e.g. 000001 + :param first_asn: First ASN to use, e.g. 100001 + + + :param font_size: Fontsize with a unit, e.g. 2mm, 0.4cm + :param qr_size: Size of the QR-Code as percentage of the label hight + :param qr_margin: Margin around the QR-Code with a unit, e.g. 1mm + + :param sub_labels_x: How many labels to put on a phyical label horizontally + :param sub_labels_y: How many labels to put on a phyical label vertically - :param subLabelsX: How many labels to put on a phyical label horizontally - :param subLabelsY: How many labels to put on a phyical label vertically - :param debug: enable debug mode - :param positionHelper: enable position helpers, e.g. as cutting guides when using sub labels + :param position_helper: enable position helpers, e.g. as cutting guides when using sub labels - - :param barWidth: Show a colored bar on the right of the label (0 = no bar) - :param barColor: Color of the bar, HEX notation - :param highlightBarWidth: add a colored highlight bar on the right of the label (0 = no bar) - :param highlightBarColor: Color of the highlight bar, HEX notation - + + :param bar_width: Show a colored bar on the right of the label (0 = no bar) + :param bar_color: Color of the bar, HEX notation + :param highlight_bar_width: add a colored highlight bar on the right of the label (0 = no bar) + :param highlight_bar_color: Color of the highlight bar, HEX notation + :param prefix: Prefix to the actual ASN number """ parm = locals() - parm['fontSize'] = toLength(parm['fontSize']) - parm['qrMargin'] = toLength(parm['qrMargin']) - parm['barColor'] = HexColor('#'+parm['barColor']) - parm['highlightBarColor'] = HexColor('#'+parm['highlightBarColor']) - parm['labeltype'] = int(parm['labeltype']) + parm["font_size"] = toLength(parm["font_size"]) + parm["qr_margin"] = toLength(parm["qr_margin"]) + parm["bar_color"] = HexColor("#" + parm["bar_color"]) + parm["highlight_bar_color"] = HexColor("#" + parm["highlight_bar_color"]) + parm["labeltype"] = int(parm["labeltype"]) - if parm['filename'] == None: - parm['filename']= 'label-'+str(parm['labeltype'])+'-'+parm['prefix']+'-'+str(parm['firstAsn']).zfill(parm['numDigits'])+'-'+str(parm['firstAsn']+parm['number']).zfill(parm['numDigits'])+'.pdf' + if parm["filename"] is None: + parm["filename"] = ( + "label-" + + str(parm["labeltype"])+ "-" + + parm["prefix"]+ "-" + + str(parm["first_asn"]).zfill(parm["num_digits"])+ "-" + + str(parm["first_asn"] + parm["number"]).zfill(parm["num_digits"]) + + ".pdf" + ) context = LabelContext(parm) - label = AveryLabels.AveryLabel(context.labeltype) label.debug = context.debug - + label.open(context.filename) render_func = partial(render, context) label.render(render_func, count=context.number, offset=context.offset) label.close() - print print(f"Output written to {context.filename}") - def labels(): - """ Shows a list of supported labels - """ - print('Supported Labels: '+', '.join(map(str,labelInfo.keys()))) + """Shows a list of supported labels""" + print("Supported Labels: " + ", ".join(map(str, labelInfo.keys()))) def version(): """Show the version""" - return 'ASN Label Generator - version 0.1 \n' + project_homepage + return "ASN Label Generator - version 0.1 \n" + project_homepage def main(): - run(generate, alt=[labels,version]) + run(generate, alt=[labels, version]) -if __name__ == '__main__': - main() \ No newline at end of file + +if __name__ == "__main__": + main() diff --git a/out/empty b/out/empty new file mode 100644 index 0000000..e69de29 From a9337407b7ae1e00b8d0db27306c870d1342869d Mon Sep 17 00:00:00 2001 From: Aborelis Date: Tue, 14 May 2024 02:06:55 +0200 Subject: [PATCH 03/13] cleanup --- AveryLabels.py | 77 ++++++++++++++++++++++++++------------------------ asn-gen.py | 12 +++++--- 2 files changed, 48 insertions(+), 41 deletions(-) diff --git a/AveryLabels.py b/AveryLabels.py index 1af13cd..fea8374 100644 --- a/AveryLabels.py +++ b/AveryLabels.py @@ -23,27 +23,25 @@ from reportlab.lib.units import mm, cm labelInfo = { # 22x 32mm x 10mm mini labels - 3044: ( 2, 11, (32, 10), (2,2), (1, 1), (66.5*mm, 120.5*mm)), - + 3044: (2, 11, (32, 10), (2, 2), (1, 1), (66.5 * mm, 120.5 * mm)), # 189x 25.4mm x 10mm mini labels - 4731: ( 7, 27, (25.4*mm, 10*mm), (2.5*mm, 0), (9*mm, 13.5*mm), A4), + 4731: (7, 27, (25.4 * mm, 10 * mm), (2.5 * mm, 0), (9 * mm, 13.5 * mm), A4), # 2.6 x 1 address labels - 5160: ( 3, 10, (187, 72), (11, 0), (14, 36), A4), - 5161: ( 2, 10, (288, 72), (0, 0), (18, 36), A4), + 5160: (3, 10, (187, 72), (11, 0), (14, 36), A4), + 5161: (2, 10, (288, 72), (0, 0), (18, 36), A4), # 4 x 2 address labels - 5163: ( 2, 5, (288, 144), (0, 0), (18, 36), A4), + 5163: (2, 5, (288, 144), (0, 0), (18, 36), A4), # 1.75 x 0.5 return address labels - 5167: ( 4, 20, (126, 36), (0, 0), (54, 36), A4), + 5167: (4, 20, (126, 36), (0, 0), (54, 36), A4), # 3.5 x 2 business cards - 5371: ( 2, 5, (252, 144), (0, 0), (54, 36), A4), - - # 48x 45.7x21.2mm - 4778: (4, 12, (45.7*mm, 21.2*mm), (0.25*cm, 0), (1.1*cm, 2*cm), A4), - - # APLI 100984 40x 52.5x29.7mm - 100984: (4, 10, (52.5*mm, 29.7*mm), (0, 0), (0, 0), A4), + 5371: (2, 5, (252, 144), (0, 0), (54, 36), A4), + # 48x 45.7x21.2mm + 4778: (4, 12, (45.7 * mm, 21.2 * mm), (0.25 * cm, 0), (1.1 * cm, 2 * cm), A4), + # APLI 100984 40x 52.5x29.7mm + 100984: (4, 10, (52.5 * mm, 29.7 * mm), (0, 0), (0, 0), A4), } + class AveryLabel: def __init__(self, label, **kwargs): @@ -51,42 +49,46 @@ class AveryLabel: self.across = data[0] self.down = data[1] self.size = data[2] - self.labelsep = self.size[0]+data[3][0], self.size[1]+data[3][1] + self.labelsep = self.size[0] + data[3][0], self.size[1] + data[3][1] self.margins = data[4] - self.topDown = True + self.top_down = True self.debug = False self.pagesize = data[5] self.position = 0 self.__dict__.update(kwargs) def open(self, filename): - self.canvas = canvas.Canvas( filename, pagesize=self.pagesize ) + """open a canvas for the file""" + self.canvas = canvas.Canvas(filename, pagesize=self.pagesize) if self.debug: - self.canvas.setPageCompression( 0 ) + self.canvas.setPageCompression(0) self.canvas.setLineJoin(1) self.canvas.setLineCap(1) - def topLeft(self, x=None, y=None): + def top_left(self, x=None, y=None): + """ return top left""" if x is None: x = self.position if y is None: - if self.topDown: - x,y = divmod(x, self.down) + if self.top_down: + x, y = divmod(x, self.down) else: - y,x = divmod(x, self.across) + y, x = divmod(x, self.across) return ( - self.margins[0]+x*self.labelsep[0], - self.pagesize[1] - self.margins[1] - (y+1)*self.labelsep[1] + self.margins[0] + x * self.labelsep[0], + self.pagesize[1] - self.margins[1] - (y + 1) * self.labelsep[1], ) def advance(self): + """ move to next position""" self.position += 1 if self.position == self.across * self.down: self.canvas.showPage() self.position = 0 def close(self): + """save and close canvas""" if self.position: self.canvas.showPage() self.canvas.save() @@ -99,35 +101,36 @@ class AveryLabel: # Or, pass a callable and an iterator. We'll do one label # per iteration of the iterator. - def render( self, thing, count, offset=0, *args ): + def render(self, thing, count, offset=0, *args): + """ render loop""" assert callable(thing) or isinstance(thing, str) if isinstance(count, Iterator): - return self.render_iterator( thing, count ) + return self.render_iterator(thing, count) canv = self.canvas - for i in range(offset+count): + for i in range(offset + count): if i >= offset: canv.saveState() - canv.translate( *self.topLeft() ) + canv.translate(*self.top_left()) if self.debug: - canv.setLineWidth( 0.25 ) - canv.rect( 0, 0, self.size[0], self.size[1] ) + canv.setLineWidth(0.25) + canv.rect(0, 0, self.size[0], self.size[1]) if callable(thing): - thing( canv, self.size[0], self.size[1], *args ) + thing(canv, self.size[0], self.size[1], *args) elif isinstance(thing, str): canv.doForm(thing) canv.restoreState() self.advance() - def render_iterator( self, func, iterator ): + def render_iterator(self, func, iterator): + """ render loop for iterator """ canv = self.canvas for chunk in iterator: canv.saveState() - canv.translate( *self.topLeft() ) + canv.translate(*self.top_left()) if self.debug: - canv.setLineWidth( 0.25 ) - canv.rect( 0, 0, self.size[0], self.size[1] ) - func( canv, self.size[0], self.size[1], chunk ) + canv.setLineWidth(0.25) + canv.rect(0, 0, self.size[0], self.size[1]) + func(canv, self.size[0], self.size[1], chunk) canv.restoreState() self.advance() - diff --git a/asn-gen.py b/asn-gen.py index 2f99451..f9c6aca 100755 --- a/asn-gen.py +++ b/asn-gen.py @@ -2,8 +2,7 @@ from functools import partial -import AveryLabels -from AveryLabels import labelInfo + from reportlab.lib.units import mm from reportlab.lib.units import toLength from reportlab.pdfgen import canvas @@ -14,8 +13,11 @@ from reportlab_qrcode import QRCodeImage from clize import run +import AveryLabels +from AveryLabels import labelInfo -project_homepage = "https://github.com/aborelis/ASN-Label-Generator" + +PROJECT_HOMEPAGE = "https://github.com/aborelis/ASN-Label-Generator" class LabelContext: @@ -57,6 +59,7 @@ class LabelContext: def render(context: LabelContext, c: canvas.Canvas, width: float, height: float): + """ renders one label onto the provided canvas. To be used with AveryLabel. """ sub_label_width = width / context.sub_labels_x sub_labelheight = height / context.sub_labels_y @@ -215,10 +218,11 @@ def labels(): def version(): """Show the version""" - return "ASN Label Generator - version 0.1 \n" + project_homepage + return "ASN Label Generator - version 0.1 \n" + PROJECT_HOMEPAGE def main(): + """Main function - entry point""" run(generate, alt=[labels, version]) From 26138614e3cc93798df29caa1324d6505818fa56 Mon Sep 17 00:00:00 2001 From: Aborelis Date: Tue, 14 May 2024 02:12:57 +0200 Subject: [PATCH 04/13] cleanp --- asn-gen.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/asn-gen.py b/asn-gen.py index f9c6aca..4eed0b9 100755 --- a/asn-gen.py +++ b/asn-gen.py @@ -21,7 +21,9 @@ PROJECT_HOMEPAGE = "https://github.com/aborelis/ASN-Label-Generator" class LabelContext: - + + # pylint: disable=too-many-instance-attributes + def __init__(self, data): self.filename = None @@ -54,7 +56,8 @@ class LabelContext: self.current_asn = self.first_asn - def incASN(self): + def inc_asn(self): + """increase current asn count """ self.current_asn = self.current_asn + 1 @@ -76,7 +79,7 @@ def render(context: LabelContext, c: canvas.Canvas, width: float, height: float) barcode_value = context.prefix + str(context.current_asn).zfill( context.num_digits ) - context.incASN() + context.inc_asn() qr = QRCodeImage(barcode_value, size=sub_labelheight * context.qr_size) qr.drawOn( @@ -126,6 +129,8 @@ def render(context: LabelContext, c: canvas.Canvas, width: float, height: float) c.restoreState() +# pylint: disable=too-many-locals + def generate( filename=None, *, From b3494b15f61da6ae3e6cb9e83fdf3d019c015c36 Mon Sep 17 00:00:00 2001 From: Aborelis Date: Tue, 14 May 2024 02:15:42 +0200 Subject: [PATCH 05/13] cleanp --- asn-gen.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/asn-gen.py b/asn-gen.py index 4eed0b9..038e484 100755 --- a/asn-gen.py +++ b/asn-gen.py @@ -129,7 +129,7 @@ def render(context: LabelContext, c: canvas.Canvas, width: float, height: float) c.restoreState() -# pylint: disable=too-many-locals + def generate( filename=None, @@ -151,7 +151,8 @@ def generate( highlight_bar_width: "hw" = 0, # type: ignore highlight_bar_color: "hc" = "d9a4a6", # type: ignore prefix: "p" = "ASN", # type: ignore -): +): # pylint: disable=too-many-locals + # pylint: disable=unused-argument """ASN Label Generator :param filename: output filename of PDF file generated From de48bf919a8019a9316fc4c5f304a5a08ba85b66 Mon Sep 17 00:00:00 2001 From: Aborelis Date: Wed, 15 May 2024 00:03:38 +0200 Subject: [PATCH 06/13] smaller improvements and inital Docker support --- AveryLabels.py | 3 ++- Dockerfile | 15 +++++++++++++++ README.md | 11 ++++++++--- asn-gen.py | 25 ++++++++++++++++--------- 4 files changed, 41 insertions(+), 13 deletions(-) create mode 100644 Dockerfile diff --git a/AveryLabels.py b/AveryLabels.py index fea8374..27c2b3d 100644 --- a/AveryLabels.py +++ b/AveryLabels.py @@ -105,7 +105,8 @@ class AveryLabel: """ render loop""" assert callable(thing) or isinstance(thing, str) if isinstance(count, Iterator): - return self.render_iterator(thing, count) + self.render_iterator(thing, count) + return canv = self.canvas for i in range(offset + count): diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c443dc3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM python:3 + +WORKDIR /asn-gen + +COPY requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +VOLUME ["/out"] + +CMD [ "python", "./asn-gen.py"] + + +# docker exec -it $(docker run -d --rm debian:unstable bash -c "apt-get update && apt-get upgrade -y && sleep 86400") bash diff --git a/README.md b/README.md index 8efb2c7..bf5e635 100644 --- a/README.md +++ b/README.md @@ -33,12 +33,12 @@ Besides generating ASN labels with a QR Code the tool can also ![Label with highlight bar](docs/label-with-hbar.png) -### Example usage of ASN with colors: +### Example usage of ASN labels with colors: | number ranges | Meaning | Color | | ------------ | --------------------------------------- | ---------- | | 000000 | Me - normal docs (shorter term storage) | blue | -| 100000 | Me - imporatant / (long term storage) | blue/red | +| 100000 | Me - imporatant (long term storage) | blue/red | | 200000 | Wife - normal | green | | 300000 | Wife - important | green/red | | 400000 | Child 1 - normal | yellow | @@ -62,6 +62,7 @@ Other Avery (or competitor's) label sizes can be added to `labelInfo` in `AveryL ``` +$ ./asn-gen.py -h Usage: asn-gen.py [OPTIONS] [filename] ASN Label Generator @@ -100,7 +101,7 @@ _**Recommendation:** do test prints on normal paper before printing to the actua _**Note**: Make sure to set print size to 100%, not fit to page or similar._ -### Running the program +### Running the program from CLI Depending on your configuration either use `` ./asn-gen.py ... `` @@ -109,6 +110,10 @@ or `` python3 asn-gen.py ... `` +### Running the program from Docker + + + ### Output Filename If the filename is omitted the output defaults to diff --git a/asn-gen.py b/asn-gen.py index 038e484..9a2edd6 100755 --- a/asn-gen.py +++ b/asn-gen.py @@ -2,6 +2,7 @@ from functools import partial +import os from reportlab.lib.units import mm from reportlab.lib.units import toLength @@ -21,6 +22,8 @@ PROJECT_HOMEPAGE = "https://github.com/aborelis/ASN-Label-Generator" class LabelContext: + + """helper class to store context """ # pylint: disable=too-many-instance-attributes @@ -129,6 +132,13 @@ def render(context: LabelContext, c: canvas.Canvas, width: float, height: float) c.restoreState() +def gen_filename(parm): + """generates filename from parameters""" + return '-'.join(['label', + str(parm["labeltype"]), parm["prefix"], + str(parm["first_asn"]).zfill(parm["num_digits"]), + str(parm["first_asn"] + parm["number"]).zfill(parm["num_digits"]) + ])+'.pdf' def generate( @@ -155,7 +165,7 @@ def generate( # pylint: disable=unused-argument """ASN Label Generator - :param filename: output filename of PDF file generated + :param filename: output filename of PDF file generated, if .pdf extension is missing the string will be used as directory :param labeltype: Type of label, e.g. 4731, get a list of supported labels with --labels :param number: number of labels to generate @@ -193,14 +203,11 @@ def generate( parm["labeltype"] = int(parm["labeltype"]) if parm["filename"] is None: - parm["filename"] = ( - "label-" - + str(parm["labeltype"])+ "-" - + parm["prefix"]+ "-" - + str(parm["first_asn"]).zfill(parm["num_digits"])+ "-" - + str(parm["first_asn"] + parm["number"]).zfill(parm["num_digits"]) - + ".pdf" - ) + parm["filename"] = gen_filename(parm) + elif not parm["filename"].endswith(".pdf"): + parm["filename"] = os.path.join(parm["filename"], gen_filename(parm)) + + context = LabelContext(parm) From e9e64e95f59df2ab814ca48562af31487770bbf3 Mon Sep 17 00:00:00 2001 From: Aborelis Date: Wed, 15 May 2024 01:56:04 +0200 Subject: [PATCH 07/13] Docker support --- README.md | 34 +++++++++++++++++++++++----------- ag-docker.sh | 4 ++++ 2 files changed, 27 insertions(+), 11 deletions(-) create mode 100755 ag-docker.sh diff --git a/README.md b/README.md index bf5e635..329c21f 100644 --- a/README.md +++ b/README.md @@ -48,18 +48,14 @@ Besides generating ASN labels with a QR Code the tool can also # Getting started -You'll need Python 3 on your system. - -To install all dependencies use - -`` pip install -r requirements.txt `` - -# Usage +## Usage This tool is hightly flexible, almost all parameters can be controlled from the command line. Other Avery (or competitor's) label sizes can be added to `labelInfo` in `AveryLabels.py`. +You can install Python all dependencies yourself or use Docker. + ``` $ ./asn-gen.py -h @@ -101,7 +97,15 @@ _**Recommendation:** do test prints on normal paper before printing to the actua _**Note**: Make sure to set print size to 100%, not fit to page or similar._ -### Running the program from CLI + +## Running the program from CLI + +You'll need Python 3 on your system. + +To install all dependencies use + +`` pip install -r requirements.txt `` + Depending on your configuration either use `` ./asn-gen.py ... `` @@ -110,11 +114,19 @@ or `` python3 asn-gen.py ... `` -### Running the program from Docker +## Running the program from Docker + +If you don't want to install python and the dependencies on your machine you can use Docker. +There is a handy bash script : + +`` ./ag-docker.sh [normal parameters to asn-gen.py] `` + +e.g. `` ./ag-docker.sh $(pwd)/out -s 500001 `` + +_Note: when using docker you cannot specify the output filename. Instead the default scheme will be used._ - -### Output Filename +## Output Filename Scheme If the filename is omitted the output defaults to `` label----.pdf `` diff --git a/ag-docker.sh b/ag-docker.sh new file mode 100755 index 0000000..ae1d16c --- /dev/null +++ b/ag-docker.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +path="$1"; shift +docker run --rm -v $path:/out ghcr.io/aborelis/asn-gen:latest ./asn-gen.py $@ /out/ \ No newline at end of file From c10b5f2bdd55176bba429a333750d0779455e4fc Mon Sep 17 00:00:00 2001 From: Aborelis Date: Wed, 15 May 2024 02:00:14 +0200 Subject: [PATCH 08/13] docs update --- README.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 329c21f..b5c66a7 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This is a tool to create ASN Labels to use for document management systems such This Python based CLI tool outputs a PDF for printing on the label sheets. -# Features +## Features Besides generating ASN labels with a QR Code the tool can also @@ -46,9 +46,9 @@ Besides generating ASN labels with a QR Code the tool can also | ... | ... | ... | -# Getting started +## Getting started -## Usage +### Usage This tool is hightly flexible, almost all parameters can be controlled from the command line. @@ -91,14 +91,14 @@ Other actions: --version Show the version ``` -### Testing your printer settings +#### Testing your printer settings Use ``--debug`` and ``--position-helper`` to test your printer settings. _**Recommendation:** do test prints on normal paper before printing to the actual label sheets._ _**Note**: Make sure to set print size to 100%, not fit to page or similar._ -## Running the program from CLI +### Running the program from CLI You'll need Python 3 on your system. @@ -114,7 +114,7 @@ or `` python3 asn-gen.py ... `` -## Running the program from Docker +### Running the program from Docker If you don't want to install python and the dependencies on your machine you can use Docker. There is a handy bash script : @@ -126,7 +126,7 @@ e.g. `` ./ag-docker.sh $(pwd)/out -s 500001 `` _Note: when using docker you cannot specify the output filename. Instead the default scheme will be used._ -## Output Filename Scheme +### Output Filename Scheme If the filename is omitted the output defaults to `` label----.pdf `` @@ -137,8 +137,7 @@ e.g. - -# Examples +## Examples ### List supported labels @@ -179,6 +178,6 @@ _Output filename: label-5161-ASN-000001-000021.pdf_ -# Credits +## Credits This project is based on [work by gitolicious](https://github.com/gitolicious/avery-asn/tree/main) but was heavily modified to support CLI and some additional features. That project itself is based on the [work from timrprobocom](https://gist.github.com/timrprobocom/3946aca8ab75df8267bbf892a427a1b7) \ No newline at end of file From 59d3d1fa8a07f5e4bc9bf42157c5904a3530abd9 Mon Sep 17 00:00:00 2001 From: Aborelis Date: Wed, 15 May 2024 02:01:26 +0200 Subject: [PATCH 09/13] docs update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b5c66a7..fb47ee3 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ This tool is hightly flexible, almost all parameters can be controlled from the Other Avery (or competitor's) label sizes can be added to `labelInfo` in `AveryLabels.py`. -You can install Python all dependencies yourself or use Docker. +You can install Python and all dependencies yourself or use Docker. ``` From cf486c94166bdee815733ea18ff03625694c31d1 Mon Sep 17 00:00:00 2001 From: Aborelis Date: Wed, 15 May 2024 11:15:12 +0200 Subject: [PATCH 10/13] docs update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fb47ee3..7268009 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Besides generating ASN labels with a QR Code the tool can also _This is helpful for small label sizes even though your physical label cutout sizes are bigger._ * support custom number ranges - _This can be useful if you want to use different folders and number ranges for yourself (ASN**0**0001), your partner ASN**2**0001, your kids (ASN**4**0001), etc._ + _This can be useful if you want to use different folders and number ranges for yourself (e.g. ASN**0**0001), your partner (ASN**2**0001), your kids (ASN**4**0001), etc._ * add a color bar to the side of the labels to allow easier visual identification where the label belongs to _I use expandable folders with different colors to store the physical documents for me, my wife and the kids, i.e. one color per person_ From 9137595e229e9346d4363b2734f735c375c9870f Mon Sep 17 00:00:00 2001 From: Aborelis Date: Wed, 15 May 2024 11:28:22 +0200 Subject: [PATCH 11/13] docs update --- README.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 7268009..894d3bd 100644 --- a/README.md +++ b/README.md @@ -37,14 +37,15 @@ Besides generating ASN labels with a QR Code the tool can also | number ranges | Meaning | Color | | ------------ | --------------------------------------- | ---------- | -| 000000 | Me - normal docs (shorter term storage) | blue | -| 100000 | Me - imporatant (long term storage) | blue/red | -| 200000 | Wife - normal | green | -| 300000 | Wife - important | green/red | -| 400000 | Child 1 - normal | yellow | -| 500000 | Child 1 - important | yellow/red | +| 000000 | Person 1 - normal docs (shorter term storage) | blue | +| 100000 | Person 1 - important (long term storage) | blue/red | +| 200000 | Person 2 - normal | green | +| 300000 | Person 2 - important | green/red | +| 400000 | Person 3 - normal | yellow | +| 500000 | Person 3 - important | yellow/red | | ... | ... | ... | +Colors give a nice visual hint on where a document belongs to. ## Getting started @@ -98,7 +99,7 @@ _**Recommendation:** do test prints on normal paper before printing to the actua _**Note**: Make sure to set print size to 100%, not fit to page or similar._ -### Running the program from CLI +### Running from CLI You'll need Python 3 on your system. @@ -114,14 +115,14 @@ or `` python3 asn-gen.py ... `` -### Running the program from Docker +### Running with Docker If you don't want to install python and the dependencies on your machine you can use Docker. There is a handy bash script : `` ./ag-docker.sh [normal parameters to asn-gen.py] `` -e.g. `` ./ag-docker.sh $(pwd)/out -s 500001 `` +e.g. `` ./ag-docker.sh $(pwd)/out -s 500001 `` or `` ./ag-docker.sh ./ -s 500001 `` _Note: when using docker you cannot specify the output filename. Instead the default scheme will be used._ From 55f9f91b55fe21adeae492bd70e91687280f6a54 Mon Sep 17 00:00:00 2001 From: OliverFriedrich Date: Fri, 28 Mar 2025 00:43:38 +0100 Subject: [PATCH 12/13] * options to handle invalid vertical and/or horizontal printer alignment * remove additional padding from qr code * use qr code margin option also as minimum spacing to upper and lower label border * fix positioning of ASN number * Add Avery L7871 label definition (it's a clone of 4731) --- AveryLabels.py | 12 ++++++++---- asn-gen.py | 22 ++++++++++++++++------ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/AveryLabels.py b/AveryLabels.py index 27c2b3d..7b083ad 100644 --- a/AveryLabels.py +++ b/AveryLabels.py @@ -26,6 +26,7 @@ labelInfo = { 3044: (2, 11, (32, 10), (2, 2), (1, 1), (66.5 * mm, 120.5 * mm)), # 189x 25.4mm x 10mm mini labels 4731: (7, 27, (25.4 * mm, 10 * mm), (2.5 * mm, 0), (9 * mm, 13.5 * mm), A4), + 7871: (7, 27, (25.4 * mm, 10 * mm), (2.5 * mm, 0), (9 * mm, 13.5 * mm), A4), # 2.6 x 1 address labels 5160: (3, 10, (187, 72), (11, 0), (14, 36), A4), 5161: (2, 10, (288, 72), (0, 0), (18, 36), A4), @@ -44,7 +45,7 @@ labelInfo = { class AveryLabel: - def __init__(self, label, **kwargs): + def __init__(self, label, pageoffset, **kwargs): data = labelInfo[label] self.across = data[0] self.down = data[1] @@ -55,6 +56,8 @@ class AveryLabel: self.debug = False self.pagesize = data[5] self.position = 0 + self.pageoffset = pageoffset + self.__dict__.update(kwargs) def open(self, filename): @@ -76,8 +79,8 @@ class AveryLabel: y, x = divmod(x, self.across) return ( - self.margins[0] + x * self.labelsep[0], - self.pagesize[1] - self.margins[1] - (y + 1) * self.labelsep[1], + self.margins[0] + x * self.labelsep[0] + self.pageoffset[0], + self.pagesize[1] - self.margins[1] - (y + 1) * self.labelsep[1] - self.pageoffset[1], ) def advance(self): @@ -101,7 +104,7 @@ class AveryLabel: # Or, pass a callable and an iterator. We'll do one label # per iteration of the iterator. - def render(self, thing, count, offset=0, *args): + def render(self, thing, count, offset=0, pageshift=(0 * mm, 0 * mm), *args): """ render loop""" assert callable(thing) or isinstance(thing, str) if isinstance(count, Iterator): @@ -128,6 +131,7 @@ class AveryLabel: canv = self.canvas for chunk in iterator: canv.saveState() + canv.translate(*self.top_left()) if self.debug: canv.setLineWidth(0.25) diff --git a/asn-gen.py b/asn-gen.py index 9a2edd6..ce7a21b 100755 --- a/asn-gen.py +++ b/asn-gen.py @@ -55,6 +55,9 @@ class LabelContext: self.highlight_bar_color = HexColor("#d9a4a6") self.prefix = "ASN" + self.page_offset_x = 0 * mm + self.page_offset_y = 0 * mm + self.__dict__.update(data) self.current_asn = self.first_asn @@ -84,13 +87,14 @@ def render(context: LabelContext, c: canvas.Canvas, width: float, height: float) ) context.inc_asn() - qr = QRCodeImage(barcode_value, size=sub_labelheight * context.qr_size) + qr_width = min(sub_labelheight * context.qr_size, sub_labelheight - 2 * context.qr_margin) + qr = QRCodeImage(barcode_value, size=qr_width, border=0) qr.drawOn( - c, x=context.qr_margin, y=sub_labelheight * ((1 - context.qr_size) / 2) + c, x=context.qr_margin, y=(sub_labelheight - qr_width) / 2 ) c.setFont("Helvetica", size=context.font_size) c.drawString( - x=sub_labelheight, + x= qr_width + 2 * context.qr_margin, y=(sub_labelheight - context.font_size) / 2, text=barcode_value, ) @@ -161,6 +165,8 @@ def generate( highlight_bar_width: "hw" = 0, # type: ignore highlight_bar_color: "hc" = "d9a4a6", # type: ignore prefix: "p" = "ASN", # type: ignore + page_offset_x: "dx" = "0mm", # type: ignore + page_offset_y: "dy" = "0mm", # type: ignore ): # pylint: disable=too-many-locals # pylint: disable=unused-argument """ASN Label Generator @@ -193,6 +199,9 @@ def generate( :param prefix: Prefix to the actual ASN number + :param page_offset_x: Print offset of the labels on the page to handle horizontal printer alignment with unit (e.g. -2mm) + :param page_offset_y: Print offset of the labels on the page to handle vertical printer alignment with unit (e.g. -1.5mm) + """ parm = locals() @@ -201,6 +210,8 @@ def generate( parm["bar_color"] = HexColor("#" + parm["bar_color"]) parm["highlight_bar_color"] = HexColor("#" + parm["highlight_bar_color"]) parm["labeltype"] = int(parm["labeltype"]) + parm["page_offset_x"] = toLength(parm["page_offset_x"]) + parm["page_offset_y"] = toLength(parm["page_offset_y"]) if parm["filename"] is None: parm["filename"] = gen_filename(parm) @@ -211,7 +222,7 @@ def generate( context = LabelContext(parm) - label = AveryLabels.AveryLabel(context.labeltype) + label = AveryLabels.AveryLabel(context.labeltype, (context.page_offset_x, context.page_offset_y)) label.debug = context.debug @@ -226,8 +237,7 @@ def generate( def labels(): """Shows a list of supported labels""" - print("Supported Labels: " + ", ".join(map(str, labelInfo.keys()))) - + print("Supported Labels: " + ", ".join(map(str, sorted(labelInfo.keys())))) def version(): """Show the version""" From be654118bb386fab3bc1edf3b4dc2ed2abd285d7 Mon Sep 17 00:00:00 2001 From: OliverFriedrich Date: Fri, 28 Mar 2025 19:57:11 +0100 Subject: [PATCH 13/13] * updated README.md --- README.md | 51 +++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 894d3bd..f7a301f 100644 --- a/README.md +++ b/README.md @@ -65,31 +65,38 @@ Usage: asn-gen.py [OPTIONS] [filename] ASN Label Generator Arguments: - filename output filename of PDF file generated + filename output filename of PDF file generated, if .pdf extension is missing the string will be used + as directory Options: - -l, --labeltype=STR Type of label, e.g. 4731, get a list of supported labels with --labels (default: 4731) - -n, --number=INT number of labels to generate (default: 189) - -o, --offset=INT Number of labels to skip on the first sheet (e.g. already used) (default: 0) - -d, --num-digits=INT Number of digits for the ASN, e.g. 000001 (default: 6) - -s, --first-asn=INT First ASN to use, e.g. 100001 (default: 1) - -f, --font-size=STR Fontsize with a unit, e.g. 2mm, 0.4cm (default: 2mm) - -q, --qr-size=FLOAT Size of the QR-Code as percentage of the label hight (default: 0.9) - -m, --qr-margin=STR Margin around the QR-Code with a unit, e.g. 1mm (default: 1mm) - --sub-labels-x, --lx=INT How many labels to put on a phyical label horizontally (default: 1) - --sub-labels-y, --ly=INT How many labels to put on a phyical label vertically (default: 1) - --debug enable debug mode - --position-helper enable position helpers, e.g. as cutting guides when using sub labels - --bar-width, --bw=INT Show a colored bar on the right of the label (0 = no bar) (default: 0) - --bar-color, --bc=STR Color of the bar, HEX notation (default: d2dede) - --highlight-bar-width, --hw=INT add a colored highlight bar on the right of the label (0 = no bar) (default: 0) - --highlight-bar-color, --hc=STR Color of the highlight bar, HEX notation (default: d9a4a6) - -p, --prefix=STR Prefix to the actual ASN number (default: ASN) + -l, --labeltype=STR Type of label, e.g. 4731, get a list of supported labels with --labels (default: 4731) + -n, --number=INT number of labels to generate (default: 189) + -o, --offset=INT Number of labels to skip on the first sheet (e.g. already used) (default: 0) + -d, --num-digits=INT Number of digits for the ASN, e.g. 000001 (default: 6) + -s, --first-asn=INT First ASN to use, e.g. 100001 (default: 1) + -f, --font-size=STR Fontsize with a unit, e.g. 2mm, 0.4cm (default: 2mm) + -q, --qr-size=FLOAT Size of the QR-Code as percentage of the label hight (default: 0.9) + -m, --qr-margin=STR Margin around the QR-Code with a unit, e.g. 1mm (default: 1mm) + --sub-labels-x, --lx=INT How many labels to put on a phyical label horizontally (default: 1) + --sub-labels-y, --ly=INT How many labels to put on a phyical label vertically (default: 1) + --debug enable debug mode + --position-helper enable position helpers, e.g. as cutting guides when using sub labels + --bar-width, --bw=INT Show a colored bar on the right of the label (0 = no bar) (default: 0) + --bar-color, --bc=STR Color of the bar, HEX notation (default: d2dede) + --highlight-bar-width, --hw=INT + add a colored highlight bar on the right of the label (0 = no bar) (default: 0) + --highlight-bar-color, --hc=STR + Color of the highlight bar, HEX notation (default: d9a4a6) + -p, --prefix=STR Prefix to the actual ASN number (default: ASN) + --page-offset-x, --dx=STR Print offset of the labels on the page to handle horizontal printer alignment with unit + (e.g. -2mm) (default: 0mm) + --page-offset-y, --dy=STR Print offset of the labels on the page to handle vertical printer alignment with unit (e.g. + -1.5mm) (default: 0mm) Other actions: - -h, --help Show the help - --labels Shows a list of supported labels - --version Show the version + -h, --help Show the help + --labels Shows a list of supported labels + --version Show the version ``` #### Testing your printer settings @@ -181,4 +188,4 @@ _Output filename: label-5161-ASN-000001-000021.pdf_ ## Credits -This project is based on [work by gitolicious](https://github.com/gitolicious/avery-asn/tree/main) but was heavily modified to support CLI and some additional features. That project itself is based on the [work from timrprobocom](https://gist.github.com/timrprobocom/3946aca8ab75df8267bbf892a427a1b7) \ No newline at end of file +This project is based on [work by gitolicious](https://github.com/gitolicious/avery-asn/tree/main) but was heavily modified to support CLI and some additional features. That project itself is based on the [work from timrprobocom](https://gist.github.com/timrprobocom/3946aca8ab75df8267bbf892a427a1b7)