Skip to content

Instantly share code, notes, and snippets.

@Kamik
Forked from timrprobocom/AveryLabels.py
Created February 16, 2024 11:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kamik/bcd6bfcde4bcbfda02ff95deba6c0486 to your computer and use it in GitHub Desktop.
Save Kamik/bcd6bfcde4bcbfda02ff95deba6c0486 to your computer and use it in GitHub Desktop.
A class to manage printing on Avery labels with ReportLab
import os
from collections.abc import Iterator
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import LETTER, landscape
from reportlab.lib.units import inch
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
# Usage:
# label = AveryLabels.AveryLabel(5160)
# label.open( "labels5160.pdf" )
# label.render( RenderAddress, 30 )
# label.close()
#
# 'render' can either pass a callable, which receives the canvas object
# (with X,Y=0,0 at the lower right) or a string "form" name of a form
# previously created with canv.beginForm().
# labels across
# labels down
# label size w/h
# label gutter across/down
# page margins left/top
labelInfo = {
# 2.6 x 1 address labels
5160: ( 3, 10, (187, 72), (11, 0), (14, 36)),
5161: ( 2, 10, (288, 72), (0, 0), (18, 36)),
# 4 x 2 address labels
5163: ( 2, 5, (288, 144), (0, 0), (18, 36)),
# 1.75 x 0.5 return address labels
5167: ( 4, 20, (126, 36), (0, 0), (54, 36)),
# 3.5 x 2 business cards
5371: ( 2, 5, (252, 144), (0, 0), (54, 36)),
}
RETURN_ADDRESS = 5167
BUSINESS_CARDS = 5371
class AveryLabel:
def __init__(self, label, **kwargs):
data = labelInfo[label]
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.margins = data[4]
self.topDown = True
self.debug = False
self.pagesize = LETTER
self.position = 0
self.__dict__.update(kwargs)
def open(self, filename):
self.canvas = canvas.Canvas( filename, pagesize=self.pagesize )
if self.debug:
self.canvas.setPageCompression( 0 )
self.canvas.setLineJoin(1)
self.canvas.setLineCap(1)
def topLeft(self, x=None, y=None):
if x == None:
x = self.position
if y == None:
if self.topDown:
x,y = divmod(x, self.down)
else:
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]
)
def advance(self):
self.position += 1
if self.position == self.across * self.down:
self.canvas.showPage()
self.position = 0
def close(self):
if self.position:
self.canvas.showPage()
self.canvas.save()
self.canvas = None
# To render, you can either create a template and tell me
# "go draw N of these templates" or provide a callback.
# Callback receives canvas, width, height.
#
# Or, pass a callable and an iterator. We'll do one label
# per iteration of the iterator.
def render( self, thing, count, *args ):
assert callable(thing) or isinstance(thing, str)
if isinstance(count, Iterator):
return self.render_iterator( thing, count )
canv = self.canvas
for i in range(count):
canv.saveState()
canv.translate( *self.topLeft() )
if self.debug:
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 )
elif isinstance(thing, str):
canv.doForm(thing)
canv.restoreState()
self.advance()
def render_iterator( self, func, iterator ):
canv = self.canvas
for chunk in iterator:
canv.saveState()
canv.translate( *self.topLeft() )
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.restoreState()
self.advance()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment