from reportlab.pdfgen import canvas from reportlab.lib.colors import black, gray, white, magenta, Color from reportlab.lib.pagesizes import A4 from reportlab.lib.styles import getSampleStyleSheet from reportlab.lib.units import cm, inch from reportlab.platypus import SimpleDocTemplate, Spacer, Paragraph from reportlab.platypus.flowables import Flowable import re class Alignment(Flowable): def __init__(self, x_words, y_words, alignment, x_font, y_font, ptsize, unit, scale=True, colours=None): self._x_words = x_words self._y_words = y_words self._alignment = alignment self._unit = unit*cm self._x_font = x_font self._y_font = y_font self._ptsize = ptsize self._scale = 1 self._do_scale = scale self._colours = colours if not colours: self._colours = {'S':black, 'P':gray, 'N':magenta} def wrap(self, rw, rh): xws = [self.canv.stringWidth(w, self._x_font, self._ptsize) for w in self._x_words] yws = [self.canv.stringWidth(w, self._y_font, self._ptsize) for w in self._y_words] width = (len(self._x_words) + 0.22)* self._unit + max(yws) height = (len(self._y_words) + 0.22)* self._unit + max(xws) if self._do_scale: self._scale = min(rw / width, 1.5) width *= self._scale height *= self._scale return (width, height) def draw(self): c = self.canv print c.getAvailableFonts() X=len(self._x_words) Y=len(self._y_words) c.saveState() c.scale(self._scale, self._scale) for (x, y), conf in self._alignment.items(): col = self._colours[conf] if isinstance(col, Color): c.setFillColor(col) c.rect((0.02 + x)*self._unit, (0.02+Y-y-1)*self._unit, self._unit, self._unit, 0, 1) else: bl = (x*self._unit, (Y-y-1)*self._unit) tl = (x*self._unit, (Y-y)*self._unit) tr = ((x+1)*self._unit, (Y-y)*self._unit) br = ((x+1)*self._unit, (Y-y-1)*self._unit) p = c.beginPath() p.moveTo(*br) p.lineTo(*tr) p.lineTo(*tl) c.setFillColor(col[0]) c.drawPath(p, fill=1) p = c.beginPath() p.moveTo(*br) p.lineTo(*bl) p.lineTo(*tl) c.setFillColor(col[1]) c.drawPath(p, fill=1) c.setStrokeColor(black) c.grid(map(lambda x: (0.02+x)*self._unit, range(X+1)), map(lambda y: (0.02+y)*self._unit, range(Y+1))) c.setFont(self._x_font, self._ptsize) c.setFillColor(black) for x, word in enumerate(self._x_words): c.saveState() c.translate((x+0.52)*self._unit, (Y+0.22)*self._unit) c.rotate(60) c.drawString(0, 0, word) c.restoreState() c.setFont(self._y_font, self._ptsize) for y, word in enumerate(self._y_words): c.drawString((X+0.22)*self._unit, (Y-y+0.42-1)*self._unit, word) c.restoreState() class Document: def __init__(self, filename): self._styles = getSampleStyleSheet() self._doc = SimpleDocTemplate(filename) self._story = [] def append(self, flowable): self._story.append(flowable) self._story.append(Spacer(1, 1*cm)) def render(self): self._doc.build(self._story[:-1]) class Canvas: def __init__(self, filename): self._filename = filename self._canvas = canvas.Canvas('.' + filename, A4) self._size = A4 self._body = None def append(self, flowable): if self._body: print >>sys.stderr, 'WARNING: replacing existing flowable' self._body = flowable def render(self): self._body.canv = self._canvas width, height = self._body.wrap(*self._size) width *= 1.02 height *= 1.02 self._canvas = canvas.Canvas(self._filename, (width, height)) self._body.canv = self._canvas self._body.draw() self._canvas.save()