Robinson Analytics Ltd. | ||||
Home | Python | Double-Byte | PDFgen | Doubletalk |
I intend to add the following features shortly:
def __init__(self,filename,pagesize=(595.27,841.89), bottomup = 1): """Creates a new document. Filename is mandatory. You can also set the page size (which defaults to A4), and whether you want a top-down coordinate system instead of bottom-up.""" def setAuthor(self, author): self._doc.setAuthor(author) def setTitle(self, title): "Embeds info in the PDF file" def setSubject(self, subject): "Embeds info in the PDF file" def showPage(self): """Ends the page and starts a new one. The graphics state is reset""" def getPageNumber(self): """Useful for numbering your documents as you go!""" return self._pageNumber def save(self): """Saves the file. If holding data, do a showPage() to save them having to.""" def setPageSize(self, size): """accepts a 2-tuple in points for paper size""" def saveState(self): """Saves the current grahics state so you can undo changes later""" def restoreState(self): """Restore to state of last saveState()"""
def getAvailableFonts(self): """Returns the list of PostScript font names available. Standard set now, but may grow in future with font embedding.""" def setFont(self, psfontname, size, leading = None): """Sets the font. If leading not specified, defaults to 1.2 x font size. Raises a readable exception if an illegal font is supplied. Font names are case-sensitive!""" def getCursor(self): """Returns current text position in user space""" def setTextOrigin(self, x, y): """Sets the text location, relative to the current graphics coordinate system""" def setTextTransform(self, a, b, c, d, e, f): "Like setTextOrigin, but does rotation, scaling etc." def stringWidth(self, text): "gets width of a string in the current font" def textOut(self, text): "prints string at current point, text cursor moves across" def textLine(self, text=''): """prints string at current point, text cursor moves down. Can work with no argument to simply move the cursor down.""" def textLines(self, stuff, trim=1): """prints multi-line or newlined strings, moving down. One comon use is to quote a multi-line block in your Python code; since this may be indented, by default it trims whitespace off each line of; set trim=0 to preserve whitespace.""" def setCharSpace(self, charSpace): """Adjusts inter-character spacing""" def setWordSpace(self, wordSpace): """Adjust inter-word spacing. This can be used to flush-justify text - you get the width of the words, and add some space between them.""" def setHorizScale(self, horizScale): "Stretches text out horizontally" def setLeading(self, leading): "How far to move down at the end of a line." def setTextRenderMode(self, mode): """Set the text rendering mode. 0 = Fill text 1 = Stroke text 2 = Fill then stroke 3 = Invisible 4 = Fill text and add to clipping path 5 = Stroke text and add to clipping path 6 = Fill then stroke and add to clipping path 7 = Add to clipping path""" def setRise(self, rise): "Move text baseline up or down to allow superscrip/subscripts"
def line(self, x1,y1, x2,y2): "As it says" def lines(self, linelist): """As line(), but slightly more efficient for lots of them - one stroke operation and one less function call""" def grid(self, xlist, ylist): """Lays out a grid in current line style. Suuply list of x an y positions.""" def bezier(self, x1, y1, x2, y2, x3, y3, x4, y4): "Bezier curve with the four given control points" def arc(self, x1,y1, x2,y2, startAng=0, extent=90): """Draw a partial ellipse inscribed within the rectangle x1,y1,x2,y2, starting at startAng degrees and covering extent degrees. Angles start with 0 to the right (+x) and increase counter-clockwise. These should have x1<x2 and y1<y2."""Note that bezier() is more efficient than arc(), as bezier curves are PDF primitives; PDFgen approximates an arc with up to four bezier curves, one for each quadrant.
def rect(self, x, y, width, height, stroke=1, fill=0): def ellipse(self, x1, y1, x2, y2, stroke=1, fill=0): def circle(self, x_cen, y_cen, r, stroke=1, fill=0): def wedge(self, x1,y1, x2,y2, startAng, extent, stroke=1, fill=0): """Like arc, but connects to the centre of the ellipse. Most useful for pie charts and PacMan!"""We should probably add roundRect(), with a radius for the corners. Other shapes may be made up in two ways: (1) using the above, together with coordinate transformations, or (2) using paths. Both are covered below.
class Canvas... def beginPath(self): """Returns a fresh path object""" def drawPath(self, aPath, stroke=1, fill=0): "Draw in the mode indicated" def clipPath(self, aPath, stroke=1, fill=0): "clip as well as drawing - subsequent drawing ops wil only appear if within the area of this path"As with the basic shapes, anything you build can be filled, stroked or both. Once you have a path, you can bild it up. It does not have to be a single closed shape; a series of squares making up a chequerboard is also a valid path. Here's an example of how they are used:
#draw a triangle p = canvas.beginPath() p.moveTo(x1, y1) p.lineTo(x2, y2) p.lineTo(x3, y3) p.close() #back to first point self.drawPath(p,stroke=1, fill=1) #draw and fillHere are the things you can do with paths. Basically, you can use moveTo, lineTo and curveTo to make your own shapes, or add ready made shapes.
class PDFPathObject: def moveTo(self, x, y): def lineTo(self, x, y): def curveTo(self, x1, y1, x2, y2, x3, y3): def arc(self, x1,y1, x2,y2, startAng=0, extent=90): def arcTo(self, x1,y1, x2,y2, startAng=0, extent=90): """Like arc, but draws a line from the current point to the start if the start is not the current point.""" def rect(self, x, y, width, height): def ellipse(self, x, y, width, height): def circle(self, x_cen, y_cen, r): def close(self): "draws a line back to where it started"Paths let you do almost any shape you want. But they also offer significant performance and reuse benefits. Internally, they accumulate a bunch of Postscript page-marking operators to draw your shape, and these are only added to the page stream when you call drawPath(). So you can make a path once, and then draw it many times. This saves some Python execution time, and a lot of typing time. If you compress pages, there's a chance that the compressor will pick up on the repetition and save you space too.
def drawInlineImage(self, image, x,y, width=None,height=None): """Draw a PIL Image into the specified rectangle. If width and height are omitted, they are calculated from the image size. Also allow file names as well as images. This allows a caching mechanism"""JPEG images are inlined directly in the file - PDF supports JPEG directly. Other formats are decoded to bitmap data by the Python Imaging Library and encoded in a special way. This can take some time (a couple of seconds for a scanned holiday photo, quite a pain for you whole photo album), so you can pass in a filename and the results will be cached in an intermediate file; subsequent builds of image-rich documents go as fast as the data can be read and written to disk. We're at work on some optional C extensions to make first-time image processing faster too. One key thing not yet done is to be able to include images ONCE at the beginning of the file, and reference them later. We'll probably have some special drawing routines which can only be called until Page 1 is written to disk; you will give an image a name, and use that to refer later. There is no challenge in adding this, just needs a spare evening :-)
def setLineWidth(self, width): def setLineCap(self, mode): def setLineJoin(self, mode): def setMiterLimit(self, limit): def setDash(self, array=[], phase=0): def setFillColorRGB(self, r, g, b): def setStrokeColorRGB(self, r, g, b):
def transform(self, a,b,c,d,e,f): "For mathematicians only; the next few call this" def translate(self, dx, dy): "Move axes accordingly" def scale(self, x, y): "stretch/squeeze horizontal and/or vertical axes" def rotate(self, theta): """theta is in degrees.""" def skew(self, alpha, beta): """Skew x and y axes by angle alpha and beta (degrees)"""While we are at it, we will reiterate two very important methods, which are used in tandem with the coordinate transformations:
def saveState(self): def restoreState(self):Right now, the only way to undo a coordinate change is saveing first then restoring after you draw. These save/restore ALL graphics state parameters. They cannot be used across multple page breaks.
def addLiteral(self, s, escaped=1): "Directly writes PDF operators to output. For experts only" def setPageTransition(self, effectname=None, duration=1, direction=0,dimension='H',motion='I'): """PDF allows page transition effects for use when giving presentations. There are six possible effects. You can just guive the effect name, or supply more advanced options to refine the way it works. There are three types of extra argument permitted, and here are the allowed values: direction_arg = [0,90,180,270] dimension_arg = ['H', 'V'] motion_arg = ['I','O'] (start at inside or outside) This table says which ones take which arguments: PageTransitionEffects = { 'Split': [direction_arg, motion_arg], 'Blinds': [dimension_arg], 'Box': [motion_arg], 'Wipe' : [direction_arg], 'Dissolve' : [], 'Glitter':[direction_arg] } Have fun!"""Robinson Analytics Ltd., Wimbledon, London. email mailto:andy@robanal.demon.co.uk