[Twisted-Python] Lore with PIL

Cory Dodt corydodt at yahoo.com
Mon Nov 11 14:23:17 MST 2002


I'm in the process of adapting Lore for the documentation on my project. 
I've subclassed it, and attached my work.

I decided not to do this as a patch after all; the changes should be very
easy to drop into the lore core if this turns out to be useful.

What do this script and module do?

* Convert lore-html to latex (like html2latex and latex.py)

What does it do differently (see Advantages for the reasons why)?

1) Images are converted to png instead of eps before for use in the
\includegraphics command.  (Images that start as png are unchanged.)  
2) Images are automatically formatted to 6.5in wide, maintaining aspect
ratio.

What are the advantages?

1) Works anywhere PIL is available / eliminates dependency on pngtopnm
2) Because PIL supports so many formats, the subclass now supports a
boatload of image formats instead of just png.
3) Resulting image quality is better, although it can still improve more. 

4) Images don't flow outside the margins

Notes on Image Quality: I achieved the best quality by converting my
.dia's to .eps and including .eps directly.  Since these are vector
graphics, the quality is perfect, to the resolution of the pdf itself; but
when I did it this way, the fonts in the diagrams were mapped to different
fonts that overflowed their boxes and made the diagram unreadable.  Next
best was to convert dia=>eps=>png (using ImageMagick's convert utility in
the shell) then including the png.  This could improve if I could figure
out how to make includegraphics use a sensible DPI when it does its
conversion to dvi.   Worst was dia=>eps=>png=>eps, for reasons that are
not obvious to me.  Both png and eps are non-lossy, so the last two
conversion paths should have equal quality, but they don't.

What isn't right yet?

1) visitNode_img() always uses png as the target extension, and 
2) convert_any() assumes this.  convert_any() will fail for certain target
image formats because the mode ("""im.convert('RGB')...""") has to match
the target format.  This can be fixed with a simple exception handler
(TODO).
3) Images should be formatted to a width of
(pagewidth-leftmargin-rightmagin), instead of a hardcoded 6.5in (which
assumes, among other things, letter-sized paper).  I'm not latex guru
enough to make this work yet.

Other notes:
It looks like the .eps in Twisted doc isn't being generated from dia
during process-docs.  This is very easy to do in batch, even without an X
server; ask me if anyone wants to see my mklore script.

#------------
#pilhtml2latex.py
#----snip----
"""A replacement for html2latex which imports pillatex
if it exists."""
#
# Copyright (C) 2002 Fresno County Office of Education
#
# Adapted from html2latex, which is in Twisted (http://twistedmatrix.com).
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General
Public
# License as published by the Free Software Foundation.

import os
from twisted.lore import texi, docbook
import pillatex

from twisted.python import usage

class Options(usage.Options):

    optFlags = [['section', 's', 'Generate a section, not an article'],
                ['texi', 'i', 'Generate a Texinfo section'],
                ['docbook', 'c', 'Generate a Docbook section']]

    optParameters = [['dir', 'd', None, 'Directory relative to which
references'
                                        ' will be taken']]

    def parseArgs(self, *files):
        self['files'] = files

def run():
    opt = Options()
    opt.parseOptions()
    ext = ".tex"
    if opt['section']:
        klass = pillatex.SectionLatexSpitter
    elif opt['texi']:
        klass = texi.TexiSpitter
        ext = '.texinfo'
    elif opt['docbook']:
        klass = docbook.DocbookSpitter
        ext = '.xml'
    else:
        klass = pillatex.LatexSpitter
    for file in opt['files']:
        fout = open(os.path.splitext(file)[0]+ext, 'w')
        dir = opt['dir'] or os.path.dirname(file)
        spitter = klass(fout.write, dir, os.path.basename(file))
        pillatex.processFile(spitter, open(file))

if __name__ == '__main__':
  run()

#----snip----
pillatex.py
#----snip----
"""A substitute for twisted.lore.latex,
using PIL to convert instead of pngtopnm."""
#
# Copyright (C) 2002 Fresno County Office of Education
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of version 2.1 of the GNU Lesser General
Public
# License as published by the Free Software Foundation.

from twisted.lore import latex
from twisted.lore.latex import processFile
import os.path
from PIL import Image

class ImageConverter:
    def convert_any(self, src, target):
        im=Image.open(src)
        im.convert('RGB').save(target)

    convert_eps=convert_jpg=convert_jpeg=convert_bmp=convert_dib= \
                convert_ppm=convert_gif=convert_tif=convert_tiff= \
                convert_xpm=convert_xbm=convert_psd=convert_any

    def convert_png(self, src, target): pass

    def visitNode_img(self, node):
        fileName = os.path.join(self.currDir, node.getAttribute('src'))
        target, ext = os.path.splitext(fileName)
        m = getattr(self, 'convert_'+ext[1:], None)
        if not m:
            return
        target = os.path.join(self.currDir,
os.path.basename(target)+'.png')
        m(fileName, target)
        target = os.path.basename(target)
        self.writer('\\includegraphics[width=6.5in]{%s}\n' % target)


class LatexSpitter(ImageConverter, latex.LatexSpitter):
    pass

class SectionLatexSpitter(ImageConverter, latex.SectionLatexSpitter):
    pass


__________________________________________________
Do you Yahoo!?
U2 on LAUNCH - Exclusive greatest hits videos
http://launch.yahoo.com/u2




More information about the Twisted-Python mailing list