2010-07-19

rst2pdf中图片的处理

一般情况下,使用 reStructuredText(ReST) 生成 PDF 格式的文件需要先转化成 LaTeX 格式。而 rst2pdf 通过调用 reportlab 工具包直接生成 PDF 文件。

配置文件

rst2pdf 会读取配置文件 (如果存在)/etc/rst2pdf.conf~/.rst2pdf/config ,也可以通过命令参数 --config=FILE 来设置配置文件的路径。配置文件的格式如下:
    [general]

    # Footnote backlinks enabled or not (default: enabled)
    footnote_backlinks=True

    # Show footnotes inline instead of at the end of the document
    inline_footnotes=False
配置文件的选项可以从 rst2pdf 命令选项中得到,从源代码 createpdf.py 文件 parse_commandline() 方法中就可以看出配置文件的作用是设定默认值:
def_footnote_backlinks = config.getValue("general",
        "footnote_backlinks", True)
parser.add_option('--no-footnote-backlinks', action='store_false',
        dest='footnote_backlinks', default=def_footnote_backlinks,
        help='Disable footnote backlinks.'\
        ' Default=%s' % str(not def_footnote_backlinks))

图片处理

rst2pdf 是通过 PIL (Python Imaging Library)来处理图片。图片宽和高的单位可以使用 em ex px in cm mm pt pc % 或者什么都不写,默认的单位是 pxrst2pdf 默认是300 dpi,但是可以通过命令选项 --default-dpi 或者在配置文件中设置。但是命令参数 --default-dpi 也并不是万能的,图片后缀的不同,图片的大小最后也不同。 --default-dpi 的值是通过 createpdf.py 文件传给了 style.py 文件中的类StyleSheet的属性def_dpi如下:
def_dpi = config.getValue("general", "default_dpi", 300)
parser.add_option('--default-dpi', dest='def_dpi', metavar='NUMBER',
           default=def_dpi,
           help='DPI for objects sized in pixels. Default=%d'%def_dpi)

......

self.styles = sty.StyleSheet(styleSheets,
                             self.font_path,
                             self.style_path,
                             def_dpi=self.def_dpi)
命令选项 --default-dpi 的值赋予xdpi,ydpi,但是根据图片后缀的不同又将进一步变化。
xdpi, ydpi = client.styles.def_dpi, client.styles.def_dpi   # 赋值
extension = imgname.split('.')[-1].lower()                  # 后缀 

if extension in ['svg','svgz'] and SVGImage.available():
      iw, ih = SVGImage(imgname, srcinfo=srcinfo).wrap(0, 0)
      iw = iw * xdpi / 72
      ih = ih * ydpi / 72
 elif extension in ["ai", "ccx", "cdr", "cgm", "cmx",
                   "sk1", "sk", "xml", "wmf", "fig"] and VectorImage.available():
      iw, ih = VectorImage(imgname, srcinfo=srcinfo).wrap(0, 0)
      iw = iw * xdpi / 72
      ih = ih * ydpi / 72

      ......

 else:
      keeptrying = True
      if LazyImports.PILImage:
         try:
            img = LazyImports.PILImage.open(imgname)
            img.load()
            iw, ih = img.size
            xdpi, ydpi = img.info.get('dpi', (xdpi, ydpi))
            keeptrying = False

  ......
图片处理中 ydpi xdpi 的值我们可以通过以下代码来验证,在 image.py 380行代码出加入 print xdpi,ydpi。如果图片后缀是 gif,则与 --default-dpi 相同,后缀是 png ,则返回 72,72
w = node.get('width')
h = node.get('height')
print xdpi,ydpi
以上代码中出现的iw,ih表示图片原宽和原高,w,h,scale是从ReST文档中得到的数值。
 iw = img.size().width()
 ih = img.size().height()

 w = node.get('width')
 h = node.get('height')
 scale = float(node.get('scale', 100))/100
最后图片通过以下几种情况的处理,就会得到最后的宽和高:
  • 如果 w,h 都为none,则 w = iw*inch/xdpi   h = ih*inch/ydpi。
  • 如果w,h 都不为 none, w = client.styles.adjustUnits(w, client.styles.tw,default_unit='px')    h = client.styles.adjustUnits(h, ih*inch/ydpi, default_unit='px')。
  • 如果 w,h 只有一个为 none,则会通过 iw/ih 来得到另一个。
  • scale的默认值为100%,最后的宽和高都会乘以scale,即w = w*scale    h = h*scale
不一致的图片处理方式,最终导致 PDF 中图片忽大忽小,而且和 HTML 的输出非常不一致。解决这个问题,参见博文《rst2pdf图片处理(续)》
blog comments powered by Disqus