# -*- coding: utf-8 -*-
# See LICENSE.txt for licensing terms

import tempfile
import os

from reportlab.platypus import *
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfbase import pdfmetrics

from opt_imports import mathtext


from log import log

HAS_MATPLOTLIB = mathtext is not None

fonts = {}


class Math(Flowable):

    def __init__(self, s):
        self.s = s
        if HAS_MATPLOTLIB:
            self.parser = mathtext.MathTextParser("Pdf")
        else:
            log.error("Math support not available,"
                " some parts of this document will be rendered incorrectly."
                " Install matplotlib.")
        Flowable.__init__(self)

    def wrap(self, aW, aH):
        if HAS_MATPLOTLIB:
            width, height, descent, glyphs, \
            rects, used_characters = self.parser.parse(
                '$%s$' % self.s, 72)
            return width, height
        return 10, 10

    def drawOn(self, canv, x, y, _sW=0):
        if HAS_MATPLOTLIB:
            global fonts
            width, height, descent, glyphs, \
            rects, used_characters = self.parser.parse(
                '$%s$' % self.s, 72)
            canv.saveState()
            canv.translate(x, y)
            for ox, oy, fontname, fontsize, num, symbol_name in glyphs:
                if not fontname in fonts:
                    fonts[fontname] = fontname
                    pdfmetrics.registerFont(TTFont(fontname, fontname))
                canv.setFont(fontname, fontsize)
                canv.drawString(ox, oy, unichr(num))

            canv.setLineWidth(0)
            canv.setDash([])
            for ox, oy, width, height in rects:
                canv.rect(ox, oy+2*height, width, height, fill=1)
            canv.restoreState()
        else:
            canv.saveState()
            canv.drawString(x, y, self.s)
            canv.restoreState()

    def descent(self):
        """Return the descent of this flowable,
        useful to align it when used inline."""
        if HAS_MATPLOTLIB:
            width, height, descent, glyphs, rects, used_characters = \
            self.parser.parse('$%s$'%self.s, 72)
            return descent
        return 0

    def genImage(self):
        """Create a PNG from the contents of this flowable.

        Required so we can put inline math in paragraphs.
        Returns the file name.
        The file is caller's responsability.

        """

        dpi = 72
        scale = 10

        import Image
        import ImageFont
        import ImageDraw
        import ImageColor

        if not HAS_MATPLOTLIB:
            img = Image.new('L', (120, 120), ImageColor.getcolor("black", "L"))
        else:
            width, height, descent, glyphs,\
            rects, used_characters = self.parser.parse(
                '$%s$' % self.s, dpi)
            img = Image.new('L', (int(width*scale), int(height*scale)),
                ImageColor.getcolor("white", "L"))
            draw = ImageDraw.Draw(img)
            for ox, oy, fontname, fontsize, num, symbol_name in glyphs:
                font = ImageFont.truetype(fontname, int(fontsize*scale))
                tw, th = draw.textsize(unichr(num), font=font)
                # No, I don't understand why that 4 is there.
                # As we used to say in the pure math
                # department, that was a numerical solution.
                draw.text((ox*scale, (height - oy - fontsize + 4)*scale),
                           unichr(num), font=font)
            for ox, oy, w, h in rects:
                x1 = ox*scale
                x2 = x1 + w*scale
                y1 = (height - oy)*scale
                y2 = y1 + h*scale
                draw.rectangle([x1, y1, x2, y2],
                               fill=ImageColor.getcolor("black", "L"))

        fh, fn = tempfile.mkstemp(suffix=".png")
        os.close(fh)
        img.save(fn)
        return fn


if __name__ == "__main__":
    doc = SimpleDocTemplate("mathtest.pdf")
    Story = [Math(r'\mathcal{R}\prod_{i=\alpha\mathcal{B}}'\
                  r'^\infty a_i\sin(2 \pi f x_i)')]
    doc.build(Story)

@@ -727,32 +727,53 @@
 HAS_MATPLOTLIB:%0A
+            try:%0A    
             widt
@@ -794,32 +794,36 @@
 cent, glyphs, %5C%0A
+    
             rect
@@ -870,32 +870,36 @@
                 
+    
 '$%25s$' %25 self.s,
@@ -911,24 +911,28 @@
             
+   
+ 
 return width
@@ -940,16 +940,95 @@
  height%0A
+            except:%0A                pass%0A                # FIXME: report error%0A
         
@@ -1135,16 +1135,99 @@
 l fonts%0A
+            canv.saveState()%0A            canv.translate(x, y)%0A            try:%0A    
         
@@ -1256,32 +1256,36 @@
 cent, glyphs, %5C%0A
+    
             rect
@@ -1332,32 +1332,36 @@
                 
+ 
+   
 '$%25s$' %25 self.s,
@@ -1373,66 +1373,8 @@
     
-        canv.saveState()%0A            canv.translate(x, y)%0A
     
@@ -1453,24 +1453,28 @@
             
+  
+  
 if not fontn
@@ -1483,24 +1483,28 @@
 e in fonts:%0A
+    
             
@@ -1558,16 +1558,20 @@
         
+    
 pdfmetri
@@ -1622,32 +1622,36 @@
                 
+  
+  
 canv.setFont(fon
@@ -1667,16 +1667,20 @@
 ntsize)%0A
+    
         
@@ -1729,32 +1729,36 @@
 ))%0A%0A            
+ 
+   
 canv.setLineWidt
@@ -1766,32 +1766,36 @@
 (0)%0A            
+   
+ 
 canv.setDash(%5B%5D)
@@ -1795,16 +1795,20 @@
 ash(%5B%5D)%0A
+    
         
@@ -1859,24 +1859,28 @@
             
+ 
+   
 canv.rect(ox
@@ -1917,16 +1917,118 @@
 fill=1)%0A
+            except:%0A                # FIXME: report error%0A                canv.drawString(0,0,self.s)%0A
         

Make the math flowable more resistant to unsupported LaTeX