Sunday, September 09, 2007

Using Python and ReportLab to create a facebook

Here's a program that we use to generate our facebooks for incoming classes. It parses a CSV file with information about the students and combines that with jpg images to create a nice booklet in PDF form.

The book looks like this:

  • Cover page
  • JD students in alphabetical order (already sorted in the input file)
  • LLM students
  • Transfer students
  • Visiting students
  • Exchange students

Each page has a header, footer and 16 photos, along with information about each student. The program relies upon the ReportLab library and the Python Imaging Library. Let me know if you have questions or comments about the code. I do not hold this out as any kind of example of great Python code!


"""

makephoto.py
Ben Chapman
Sept., 2007
Released under the GPL
version .6

The program processes a CSV file that looks like this:

First Name 0 *
MI 1 *
Last Name 2 *
City 3 *
State 4 *
Degree Sought 5
Undergraduate School 6 *
Undergrad Major 7 *
Second Undergrad Major 8 *
Grad school 9 *
Photo file name ending in jpg 10 *

* = will appear in output

"""

from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.lib.units import inch
import string
import time
import sys
# Depends on 2.4?
import csv

debug = 0

# Global data input
datafile = "./facebook10.csv"
# list of data items extracted from file
myoutput = []

# modify name as appropriate for this class year
outputpdf = "./facebook10.pdf"
studentinfo = []

# footer text - remove DRAFT when you go to production
footertext = "Emory Law Students - Fall, 2007"
myCanvas = canvas.Canvas(outputpdf, pagesize=letter,pageCompression=1)
myCanvas.setAuthor("Emory Law IT Department")
myCanvas.setSubject("Emory Law Student Photo Directory")
myCanvas.setTitle("Emory Law Student Photo Directory")
width, height = letter
vert=[8*inch,5.5*inch,3*inch,.5*inch]
horiz=(0*inch,2*inch,4*inch,6*inch)
myCanvas.translate(.75*inch,1*inch)
itemnumber = 0

def dataloader(datafile):
myfile = csv.reader(open(datafile))
# discard the header row
myfile.next()
# iterate through the list of lines
for i in myfile:
photo = ''
try:
if (len(i[10])>0):
photo = i[10]
except:
photo = "nophoto.jpg"
for j in range(len(i)):
i[j] = i[j].strip()
myoutput.append([i[0]+' ' + i[1] + ' ' +i[2],
i[3]+', '+i[4],
i[5],
i[6],
i[7],
i[8],
i[9],
photo])
return myoutput


def getdata(degree='JD'):
students = []
for i in myoutput:
if debug: print "Getdata:",i
if i[2].lower() == degree.lower():
students.append(i)
return students

def pagebody(itemnumber):
myCanvas.translate(.75*inch,1*inch)
for j in vert:
for i in horiz:
if (itemnumber < len(studentinfo)):
if debug: print "Item number: ",itemnumber," len(student info) ",len(studentinfo)
textobject = myCanvas.beginText()
textobject.setFont('Times-Roman',6)
textobject.setTextOrigin(i,j-(.1*inch))
for line in [0,1,3,4,5,6]:
if (len(studentinfo[itemnumber][line])>0):
textobject.textLine(studentinfo[itemnumber][line])
myCanvas.drawText(textobject)
if debug: print "IMAGE NAME",studentinfo[itemnumber][7]
try:
myCanvas.drawImage("./photos10/"+studentinfo[itemnumber][7],x=i,y=j,width=1.5*inch,height=1.7*inch)
if debug: print "/photos10/"+studentinfo[itemnumber][7]
except:
myCanvas.drawImage("./photos10/nophoto.jpg",x=i,y=j,width=1.5*inch,height=1.7*inch)
if debug: print "./photos10/"+studentinfo[itemnumber][7]
myCanvas.rect(x=i,y=j,width=1.5*inch,height=1.7*inch)
itemnumber = itemnumber + 1
return itemnumber

def footer():
myfooter = myCanvas.beginText()
#myfooter.setTextOrigin(4.5*inch,-.75*inch)
myfooter.setTextOrigin(1*inch,-.75*inch)
myfooter.setFont('Times-Italic',10)
curpage = int(myCanvas.getPageNumber()) - 1
myfooter.textLine(footertext + " DRAFT - NOT FOR DISTRIBUTION - Page %d" % curpage)
myCanvas.drawText(myfooter)

def header(degree="JD"):
myCanvas.drawCentredString(4.25*inch, 10.75*inch,degree + " Students")


def coverpage():
mytitle = myCanvas.beginText()
# comment out the following lines when you go to production
mytitle.setFont('Times-Roman',64)
mytitle.setTextOrigin(.5*inch,3*inch)
mytitle.textLine('DRAFT')
mytitle.textLine('INTERNAL ONLY')
# end draft lines
mytitle.setFont('Times-Roman',32)
mytitle.setTextOrigin(2*inch,6*inch)
mytitle.textLine("Emory Law School")
mytitle.setFont('Times-Roman',16)
mytitle.textLine("Student Photo Book")
mytitle.textLine("Fall - 2007")
myCanvas.drawText(mytitle)
# Generate a time stamp
mytimestamp = myCanvas.beginText()
mytimestamp.setFont('Times-Roman',8)
mytimestamp.setTextOrigin(.5*inch,.5*inch)
mytimestamp.textLine(timestamp())
myCanvas.drawText(mytimestamp)

def sectionpage(degree):
mytitle = myCanvas.beginText()
mytitle.setFont('Times-Roman',16)
mytitle.setTextOrigin(4*inch,8*inch)
mytitle.textLine(degree+" Students")
myCanvas.drawText(mytitle)

def bodypage(studentinfo,degree):
itemnumber=0
pages = len(studentinfo) / 16
for page in range(0,pages+1):
header(degree)
itemnumber = pagebody(itemnumber)
footer()
myCanvas.showPage()

def timestamp():
curtime = time.localtime()
return "Generated %02d-%02d-%02d at %02d:%02d" % (curtime[1],curtime[2],curtime[0],curtime[3],curtime[4])

##
# Main Program
##

if __name__ == '__main__':
# load data array from csv file
mydata = dataloader(datafile)
# draw cover page
coverpage()
myCanvas.showPage()
# create a separate section for each group at the law school
for degree in ("JD","LLM","Transfer","Visiting","Exchange"):
studentinfo = getdata(degree)
bodypage(studentinfo,degree)
# save the PDF file
myCanvas.save()




No comments: