Skip to main content

Ralsina.Me — Roberto Alsina's website

Posts about python (old posts, page 65)

PET: English Translation Issue 1 has a date

Be­cause it worked on­ce, let's do it again. I have just set a com­plete­ly ar­bi­trary, and prob­a­bly too ear­ly date for the re­lease of the first eng­lish Is­sue of "PET: Python En­tre To­dos" mag­a­zine.

The eng­lish ver­sion is called PET, which means "Python En­tre To­dos: Eng­lish Trans­la­tion".

It will have the same con­tents as the first span­ish Is­sue and... it will be the last Is­sue done like this.

From now on, both ver­sions will be pub­lished at the same time, if we can.

So, there will be a very short gap be­tween the eng­lish first Is­sue and the sec­ond one (less than a mon­th, we hope).

So, stay tuned

Things I learned publishing a magazine

To­day at 00:00:00 GMT-3 PET: Python en­tre to­dos was in­deed launched, in time (ar­bi­trary but forced) and in bud­get ($0).

So, what did I learn? I learned a lot!

  • The on­­ly thing you need to pub­­lish an e-­­mag is time and con­­ten­t.

  • Time can be con­vert­ed in­­­to con­­ten­t, but if you write ev­ery­thing your­­self it's a blog, not a mag­a­zine. Luck­­i­­ly, PET found great con­trib­u­­tors.

  • If you want util­i­­tar­i­an de­sign, rst2pdf can do the job

  • In fac­t, it can do it bet­ter than oth­­er tools in some ways

    • I can push a fixed ver­­­sion of the PDFs in 5 min­utes for all lay­out­s. How much would it take me us­ing Scribus or oth­­­er DT­P? In a mag­a­zine where cor­rec­t­­­ness mat­ter­s, that's a big deal.

    • TOCs are bet­ter than in most am­a­­­teur PDF mag­a­zines I've seen. The in­­­-­­­con­­ten­t-­­­TOC is click­­­able, and the PDF TOC is per­fec­t.

    • Page num­bers in the PDF TOC make sense (no, the cov­­­er is not page 1)

    • I am pro­­­duc­ing 6 PDF ver­­­sion­s: A4(b­w, colour), A5(b­w,­­­colour), Book­let(b­w, colour) and I could add any oth­­­er I want in a few min­utes.

  • I learned about PDF im­po­si­­tion!

Let's ex­plain the last one:

Sup­pose you want to print a small book­let, and you have 32 pages of con­tent. How do you do that?

The eas­i­est way is to print it 2-up dou­ble-sid­ed in A4 pa­per so that you can stack the pages, fold them down the mid­dle, sta­ple them, and get a nice A5 book­let.

The prob­lem is that the page or­der­ing is hard to get right. For ex­am­ple, for a 4-­page book­let, you need to print one A4 page with pages 4-1 on one side and 2-3 on the oth­er. For an 8 page book­let it's 8-1,2-7,3-6,4-5.

Lucklily there's a way to get this done au­to­mat­i­cal­ly:

1. In­stall pod­ofo 3. Get book­let-A4.­plan (see be­low) 2. Run this:

podofoimpose my-A5-pages.pdf my-booklet.pdf booklet-A4.plan lua

book­let-A4.­plan is this:

---Generic Booklet (A4)
---It is said generic as it will try to determine
---automatically how to fit the booklet onto A4
---paper sheets, scaling pages if necessary.
---it is well suited for office documents for
---which you do not care too much about resulting
---imposition artefacts since it manages to save
-- print("Booklet")
-- We output an A4 booklet
PageWidth = 595.27559
PageHeight = 841.88976


-- We assume that H > W
-- Argh, we now can do better since we have "if" ;-)
-- Scale = PageHeight / (2*SourceWidth)
if(SourceWidth <= SourceHeight)
--  If you A5 pages are not really A5, uncomment the next line
--  Scale = PageHeight / (2*SourceWidth)
    Scale = 1
    rot = 90
        xof = SourceHeight
        yofRA = 0
        yofRB = SourceWidth
        yofVA = 0
        yofVB = SourceWidth
--  If you A5 pages are not really A5, uncomment the next line
--  Scale = PageHeight / (2*SourceHeight)
    Scale = 1
    rot = 0
        xof = 0;
        yofRA = 0
        yofRB = SourceHeight
        yofVA = SourceHeight
        yofVB = 0

    rest = PageCount % 4
    totp = PageCount
    if rest ~= 0
        totp = totp + ( 4 - rest)
    inc = 0
    count = 0
    imax = totp/4
    while count < imax
--          We assume that podofoimpose will discard invalid records
--          such as those with source page greater than PageCount
--          print(totp, inc, rot, xof,yofRA, yofRA, yofVA, yofVB)
-- Recto
        PushRecord(totp - inc , inc + 1 , rot, xof , yofRA)
        PushRecord(inc + 1 , inc + 1 , rot, xof , yofRB)
-- Verso
        PushRecord(inc + 2 , inc + 2 , rot, xof , yofVA)
        PushRecord(totp-(inc + 1) , inc + 2 , rot, xof, yofVB)

        count = count + 1
        inc = inc + 2

That code is tak­en from here: http://www.oep-h.­com/im­pose/

And voilá, you get a scram­bled PDF with the pages in ex­act­ly the right or­der (and emp­ty pages added as need­ed).

Come see me in Bahía Blanca next weekend!

I will be speak­ing at the Jor­nadas del Sur in Bahía Blan­ca this week­end (Au­gust 14/15 and 16).

For a change, I will not be giv­ing my old tired talk­s, but a brand new one, called "The Am­a­teur", and prob­a­bly a light­ning talk or some­thing else.

The usu­al of­fer of free beer will not be pos­si­ble this year, so: If you men­tion this blog in the QA ses­sion, you get... free can­dy!

Af­ter that, I will be speak­ing at FM La Tribu on sat­ur­day Au­gust 21st in the Char­las Abier­tas 2010 where I will be speak­ing about a lot of things be­tween vir­tualenv and nose and tox and oth­er test­ing-re­lat­ed top­ic­s.

It's coming: PET - Python Entre Todos


I re­moved the count­down be­cause it was wrong (time­zone prob­lem). Check http://re­ for one that works :-)

I have been dragged in­to YAP (Yet An­oth­er Pro­jec­t) and in this case it's the first-is­sue-ev­er of PET - Python En­tre To­dos a python on­line mag­a­zine in span­ish.

This is an emer­gent out­put of PyAr the on­line Python com­mu­ni­ty of Ar­genti­na, and it may nev­er have a sec­ond is­sue un­less we get a lot of help, so pay at­ten­tion to the first one :-)

I have been do­ing web­mas­ter­ing, edit­ing and PDF pro­duc­tion, Emil­iano Dal­la Verde Mar­cozzi has been help­ing ev­ery­where and get­ting ar­ti­cles.

The first is­sue is some 45 A5 pages (or 23 A4 ones) in small type, so it's not ex­act­ly huge, but it has half a dozen ar­ti­cles aimed at dif­fer­ent python lev­el­s.

It has been a lot of fun so far, I hope it's well re­ceived!

Extending rst2pdf: easy and powerful

I do al­most all my busi­ness writ­ing (and my book) us­ing re­struc­tured tex­t. And when I want to pro­duce print­-qual­i­ty out­put, I tend to use my own tool, rst2pdf.

It's pop­u­lar, sure­ly my most pop­u­lar pro­gram, but very few know it's al­so ex­treme­ly easy to ex­tend (hat tip to Patrick Maupin, who wrote this part!). And not on­ly that, but you can make it do some amaz­ing stuff with a lit­tle ef­fort.

To show that, let's cre­ate the most daz­zling sec­tion head­ings known to man ( Let's see you do what this ba­by can do in La­TeX ;-).

First: de­fine the prob­lem.

The ti­tles rst2pdf can pro­duce are bor­ing. If you pull ev­ery lever and push ev­ery but­ton, you may end with the ti­tle tex­t, in a Com­ic San­s, right-aligned, in pink let­ter­ing, with av­o­cado-­green back­ground and a red bor­der.

And that's as far as the cus­tomiza­tion ca­pa­bil­i­ties go us­ing stylesheet­s. That's usu­al­ly enough, be­cause rst2pdf is not meant for brochures or some­thing like that (but I have done it).

The re­al prob­lem is that when you get all graph­ic-de­sign­er on rst2pdf, you lose doc­u­ment struc­ture, be­cause you are not be­ing se­man­tic.

Sec­ond: de­fine the goal.

So, imag­ine you want to make a head­ing that looks like this:


The im­age is tak­en from the li­brary of con­gress with some light (and bad) gimp­ing by me to leave that emp­ty space at the left, and the ti­tle was added us­ing Inkscape.

Can you do that with rst2pdf? Hell no you can't. Not with­out cod­ing. So let's code an ex­ten­sion that lets you cre­ate any head­ing you like with­in the lim­its of Inkscape!

First, we cre­ate a SVG tem­plate for the head­ings (it's a bit big be­cause it has the bit­map em­bed­ded).

Three: the im­age-­head­ing flow­able

Suppose you have an image of the heading just like the one above. How would you draw that in a PDF? In reportlab, you do that using flowables which are elements that compose the story that is your document. These flowables are arranged in pages, and that's your PDF.

If you are do­ing a head­ing, there's a bit more, in that you need to add a book­mark, so it ap­pears on the PDF ta­ble of con­tents.

So, here's a flowable that does just that. It's cobbled from pieces inside rst2pdf, and is basically an unholy mix of Heading and MyImage:

class FancyHeading(MyImage):
  '''This is a cross between the Heading flowable, that adds outline
  entries so you have a PDF TOC, and MyImage, that draws images'''

  def __init__(self, *args, **kwargs):
      # The inicialization is taken from rst2pdf.flowables.Heading
      self.stext = kwargs.pop('text')
      # Cleanup title text
      self.stext = re.sub(r'<[^>]*?>', '', unescape(self.stext))
      self.stext = self.stext.strip()

      # Stuff needed for the outline entry
      self.snum = kwargs.pop('snum')
      self.level = kwargs.pop('level')
      self.parent_id= kwargs.pop('parent_id')

      MyImage.__init__(self, *args, **kwargs)

  def drawOn(self,canv,x,y,_sW):

      ## These two lines are magic.
      #if isinstance(self.parent_id, tuple):

      # Add outline entry. This is copied from rst2pdf.flowables.heading

      if canv.firstSect:
          canv.sectName = self.stext
          if self.snum is not None:
              canv.sectNum = self.snum
              canv.sectNum = ""

                                int(self.level), False)

      # And let MyImage do all the drawing

And how do we tell rst2df to use that instead of a regular Heading? by overriding the TitleHandler class. Here's where the extension magic kicks in.

If you de­fine, in an ex­ten­sion, a class like this:

class FancyTitleHandler(genelements.HandleParagraph, docutils.nodes.title):

Then that class will handle all docutils nodes of class docutils.nodes.title. Here, I just took rst2pdf.genelements.HandleTitle and changed how it works for level-1 headings, making it generate a FancyHeading instead of a Heading... and that's all there is to it.

class FancyTitleHandler(genelements.HandleParagraph, docutils.nodes.title):
  This class will handle title nodes.

  It takes a "titletemplate.svg", replaces TITLEGOESHERE with
  the actual title text, and draws that using the FancyHeading flowable
  (see below).

  Since this class is defined in an extension, it
  effectively replaces rst2pdf.genelements.HandleTitle.

  def gather_elements(self, client, node, style):
      # This method is copied from the HandleTitle class
      # in rst2pdf.genelements.

      # Special cases: (Not sure this is right ;-)
      if isinstance(node.parent, docutils.nodes.document):
          #node.elements = [Paragraph(client.gen_pdftext(node),
          # The visible output is now done by the cover template
          node.elements = []
          client.doc_title = node.rawsource
          client.doc_title_clean = node.astext().strip()
      elif isinstance(node.parent, docutils.nodes.topic):
          node.elements = [Paragraph(client.gen_pdftext(node),
      elif isinstance(node.parent, docutils.nodes.Admonition):
          node.elements = [Paragraph(client.gen_pdftext(node),
      elif isinstance(node.parent, docutils.nodes.table):
          node.elements = [Paragraph(client.gen_pdftext(node),
      elif isinstance(node.parent, docutils.nodes.sidebar):
          node.elements = [Paragraph(client.gen_pdftext(node),
          # Section/Subsection/etc.
          text = client.gen_pdftext(node)
          fch = node.children[0]
          if isinstance(fch, docutils.nodes.generated) and \
              fch['classes'] == ['sectnum']:
              snum = fch.astext()
              snum = None
          key = node.get('refid')
          if reportlab.Version > '2.1':

          # The parent ID is the refid + an ID to make it unique for Sphinx
          parent_id=(node.parent.get('ids', [None]) or [None])[0]+u'-'+unicode(id(node))
          if client.depth > 1:
              node.elements = [ Heading(text,
                      client.styles['heading%d'%min(client.depth, maxdepth)],
          else: # This is an important title, do our magic ;-)
              # Hack the title template SVG
              tfile = open('titletemplate.svg')
              tdata =
              tfile = tempfile.NamedTemporaryFile(dir='.', delete=False, suffix='.svg')
              tfname =
              tfile.write(tdata.replace('TITLEGOESHERE', text))

              # Now tfname contains a SVG with the right title.
              # Make rst2pdf delete it later.

              e = FancyHeading(tfname, width=700, height=100,
                  client=client, snum=snum, parent_id=parent_id,
                  text=text, level=client.depth-1)

              node.elements = [e]

          if client.depth <= client.breaklevel:
              node.elements.insert(0, MyPageBreak(breakTo=client.breakside))
      return node.elements

The full ex­ten­sion is in SVN and you can try it this way:

[fancytitles]$ rst2pdf -e fancytitles -e inkscape demo.txt -b1

You need to en­able the Inkscape ex­ten­sion so the SVG will look nice. And here's the out­put:


You can over­ride how any el­e­ment is han­dled. That's be­ing ex­ten­si­ble :-)

Contents © 2000-2020 Roberto Alsina