From 5986cfe9f145805866582806de3ad5230e6c5568 Mon Sep 17 00:00:00 2001 From: Aviv Eyal Date: Sun, 16 Apr 2017 14:47:13 -0700 Subject: [PATCH] Add demo: Print addresses from a CSV file This mostly includes the right specs for Avery 5160 sheet (Very common format) and CSV reading. --- README.md | 2 + demos/addresses.csv | 18 +++++++++ demos/addresses.py | 96 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 demos/addresses.csv create mode 100644 demos/addresses.py diff --git a/README.md b/README.md index 454a87f..5b89064 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,8 @@ The following examples are available in the demos directory: selection, and centred text. * [Image preview](demos/preview.py) - generates image previews of two of the pages from the nametags demo. +* [Addresses](demos/addresses.py) - print mailing labels (From a CSV file) on a + standard Avery 5160 label page. Demo fonts ========== diff --git a/demos/addresses.csv b/demos/addresses.csv new file mode 100644 index 0000000..2cd5df6 --- /dev/null +++ b/demos/addresses.csv @@ -0,0 +1,18 @@ +John Walker,ACME Cars,231 Stark Hollow Road,,Greeley,CO,12345 +Billy-Bob,ACME Cars,232 Stark Hollow Road,,Greeley,CO,12345 +Cindi Fry,ACME Cars,233 Stark Hollow Road,,Greeley,CO,12345 +Rafael Monaghan,ACME Cars,234 Stark Hollow Road,,Greeley,CO,12345 +Ernesto Maldanado,ACME Cars,235 Stark Hollow Road,,Greeley,CO,12345 +Elda Gurney,ACME Cars,236 Stark Hollow Road,,Greeley,CO,12345 +Eleanor Steller,ACME Cars,237 Stark Hollow Road,,Greeley,CO,12345 +Jean Mantle,ACME Cars,238 Stark Hollow Road,,Greeley,CO,12345 +Jude Wishon,ACME Cars,239 Stark Hollow Road,,Greeley,CO,12345 +Joselyn Viruet,ACME Cars,240 Stark Hollow Road,,Greeley,CO,12345 +Lesa Kindig,ACME Cars,241 Stark Hollow Road,,Greeley,CO,12345 +Lyn Klinger,ACME Cars,242 Stark Hollow Road,,Greeley,CO,12345 +Craig Huether,ACME Cars,243 Stark Hollow Road,,Greeley,CO,12345 +Tennie Otten,ACME Cars,244 Stark Hollow Road,,Greeley,CO,12345 +Cira Trowell,ACME Cars,245 Stark Hollow Road,,Greeley,CO,12345 +Madalene Raatz,ACME Cars,246 Stark Hollow Road,,Greeley,CO,12345 +Darleen Mccluskey,ACME Cars,274 Stark Hollow Road,,Greeley,CO,12345 +Ayesha Nevius ,ACME Cars,248 Stark Hollow Road,,Greeley,CO,12345 diff --git a/demos/addresses.py b/demos/addresses.py new file mode 100644 index 0000000..83b83b7 --- /dev/null +++ b/demos/addresses.py @@ -0,0 +1,96 @@ +# This file is part of pylabels, a Python library to create PDFs for printing +# labels. +# Copyright (C) 2012, 2013, 2014 Blair Bonnett +# +# pylabels is free software: you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# pylabels is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# pylabels. If not, see . + +from collections import namedtuple +import csv + +import labels +from reportlab.graphics import shapes + + +# Createa a labels page, matching Avery 5160, 8160, 6240, etc. + +PADDING = 1 +specs = labels.Specification( + 215.9, 279.4, 3, 10, 64, 25.4, corner_radius=2, + left_margin=5, right_margin=5, top_margin=13, + left_padding=PADDING, right_padding=PADDING, top_padding=PADDING, + bottom_padding=PADDING, + row_gap=0) + +Address = namedtuple( + 'Address', + ['name', 'name2', 'street1', 'street2', 'city', 'state', 'zip']) + + +def draw_address(label, width, height, address): + assert address.state, address + assert address.zip, address + + # The order is flipped, because we're painting from bottom to top. + # The Some of the lines get .upper(), because that's what the USPS likes. + lines = [ + ('%s %s %s' % (address.city, address.state, address.zip)).upper(), + address.street2.upper(), + address.street1.upper(), + address.name2, + address.name, + ] + + group = shapes.Group() + x, y = 0, 0 + for line in lines: + if not line: + continue + shape = shapes.String(x, y, line, textAnchor="start") + _, _, _, y = shape.getBounds() + # Some extra spacing between the lines, to make it easier to read + y += 3 + group.add(shape) + _, _, lx, ly = label.getBounds() + _, _, gx, gy = group.getBounds() + + # Make sure the label fits in a sticker + assert gx <= lx, (address, gx, lx) + assert gy <= ly, (address, gy, ly) + + # Move the content to the center of the sticker + dx = (lx - gx) / 2 + dy = (ly - gy) / 2 + group.translate(dx, dy) + + label.add(group) + + +sheet = labels.Sheet(specs, draw_address, border=False) + +filename = 'addresses.csv' +with open(filename, newline='') as csvfile: + reader = csv.DictReader(csvfile, Address._fields, quotechar='"') + for row in reader: + # Make sure we got all fields, and no extra fields. + assert None not in row, row['name'] + assert 'zip' in row, row['name'] + for k, v in row.items(): + row[k] = v.strip() + + address = Address(**row) + + sheet.add_label(address) + + +sheet.save('labels.pdf') +print("{0:d} label(s) output on {1:d} page(s).".format(sheet.label_count, sheet.page_count))