add resource path to TEXINPUTS so images are included without symlink hacks
[librarian.git] / librarian / epub.py
index 10922d4..8dc11c7 100644 (file)
@@ -15,10 +15,11 @@ from lxml import etree
 import zipfile
 from tempfile import mkdtemp, NamedTemporaryFile
 from shutil import rmtree
 import zipfile
 from tempfile import mkdtemp, NamedTemporaryFile
 from shutil import rmtree
+from mimetypes import guess_type
 
 from librarian import RDFNS, WLNS, NCXNS, OPFNS, XHTMLNS, OutputFile
 
 from librarian import RDFNS, WLNS, NCXNS, OPFNS, XHTMLNS, OutputFile
-from librarian.cover import WLCover
-
+from librarian.cover import WLCover, FutureOfCopyrightCover
+from librarian.latex import LatexFragment
 from librarian import functions, get_resource
 
 functions.reg_person_name()
 from librarian import functions, get_resource
 
 functions.reg_person_name()
@@ -117,10 +118,10 @@ class Stanza(object):
     Slashes may only occur directly in the stanza. Any slashes in subelements
     will be ignored, and the subelements will be put inside verse elements.
 
     Slashes may only occur directly in the stanza. Any slashes in subelements
     will be ignored, and the subelements will be put inside verse elements.
 
-    >>> s = etree.fromstring("<strofa>a/\\nb<x>x/\\ny</x>c/ \\nd</strofa>")
+    >>> s = etree.fromstring("<strofa>a <b>c</b> <b>c</b>/\\nb<x>x/\\ny</x>c/ \\nd</strofa>")
     >>> Stanza(s).versify()
     >>> print etree.tostring(s)
     >>> Stanza(s).versify()
     >>> print etree.tostring(s)
-    <strofa><wers_normalny>a</wers_normalny><wers_normalny>b<x>x/
+    <strofa><wers_normalny>a <b>c</b> <b>c</b></wers_normalny><wers_normalny>b<x>x/
     y</x>c</wers_normalny><wers_normalny>d</wers_normalny></strofa>
     
     """
     y</x>c</wers_normalny><wers_normalny>d</wers_normalny></strofa>
     
     """
@@ -149,16 +150,16 @@ class Stanza(object):
         return self.open_verse
 
     def push_text(self, text):
         return self.open_verse
 
     def push_text(self, text):
-        if not text or not text.strip():
+        if not text:
             return
         for i, verse_text in enumerate(re.split(r"/\s*\n", text)):
             if i:
                 self.open_normal_verse()
             verse = self.get_open_verse()
             if len(verse):
             return
         for i, verse_text in enumerate(re.split(r"/\s*\n", text)):
             if i:
                 self.open_normal_verse()
             verse = self.get_open_verse()
             if len(verse):
-                verse[-1].tail = (verse[-1].tail or "") + verse_text.strip()
+                verse[-1].tail = (verse[-1].tail or "") + verse_text
             else:
             else:
-                verse.text = (verse.text or "") + verse_text.strip()
+                verse.text = (verse.text or "") + verse_text
 
     def push_elem(self, elem):
         if elem.tag.startswith("wers"):
 
     def push_elem(self, elem):
         if elem.tag.startswith("wers"):
@@ -329,9 +330,27 @@ def transform_chunk(chunk_xml, chunk_no, annotations, empty=False, _empty_html_s
     return output_html, toc, chars
 
 
     return output_html, toc, chars
 
 
+def render_latex(wldoc, prefix="latex"):
+    """
+    Renders <latex>CODE</latex> as images and returns
+    (changed_wldoc, [ (epub_filepath1, latexfragment_object1), ... ]
+"""
+    root = wldoc.edoc.getroot()
+    latex_nodes = root.findall(".//latex")
+    images = []
+    for ln in latex_nodes:
+        fragment = LatexFragment(ln.text, resize=40)
+        images.append((os.path.join(prefix, fragment.filename), fragment))
+        ln.tag = "img"
+        ln.text = os.path.join(prefix, fragment.filename)
+        
+    return wldoc, images
+        
+
 def transform(wldoc, verbose=False,
               style=None, html_toc=False,
 def transform(wldoc, verbose=False,
               style=None, html_toc=False,
-              sample=None, cover=None, flags=None):
+              sample=None, cover=None, flags=None, resources=None,
+              intro_file=None, cover_file=None):
     """ produces a EPUB file
 
     sample=n: generate sample e-book (with at least n paragraphs)
     """ produces a EPUB file
 
     sample=n: generate sample e-book (with at least n paragraphs)
@@ -355,7 +374,7 @@ def transform(wldoc, verbose=False,
             zip.writestr('OPS/title.html',
                  etree.tostring(html_tree, method="html", pretty_print=True))
             # add a title page TOC entry
             zip.writestr('OPS/title.html',
                  etree.tostring(html_tree, method="html", pretty_print=True))
             # add a title page TOC entry
-            toc.add(u"Strona tytułowa", "title.html")
+            toc.add(u"Tytuł", "title.html")
         elif wldoc.book_info.parts:
             # write title page for every parent
             if sample is not None and sample <= 0:
         elif wldoc.book_info.parts:
             # write title page for every parent
             if sample is not None and sample <= 0:
@@ -436,28 +455,48 @@ def transform(wldoc, verbose=False,
                        'media-type="application/oebps-package+xml" />' \
                        '</rootfiles></container>')
     zip.write(get_resource('res/wl-logo-small.png'), os.path.join('OPS', 'logo_wolnelektury.png'))
                        'media-type="application/oebps-package+xml" />' \
                        '</rootfiles></container>')
     zip.write(get_resource('res/wl-logo-small.png'), os.path.join('OPS', 'logo_wolnelektury.png'))
+    zip.write(get_resource('res/logo.png'), os.path.join('OPS', 'logo.png'))
     zip.write(get_resource('res/jedenprocent.png'), os.path.join('OPS', 'jedenprocent.png'))
     if not style:
         style = get_resource('epub/style.css')
     zip.write(style, os.path.join('OPS', 'style.css'))
 
     zip.write(get_resource('res/jedenprocent.png'), os.path.join('OPS', 'jedenprocent.png'))
     if not style:
         style = get_resource('epub/style.css')
     zip.write(style, os.path.join('OPS', 'style.css'))
 
+    document, latex_images = render_latex(document)
+    for image in latex_images:
+        zip.write(image[1].path, os.path.join('OPS', image[0]))
+        image[1].remove()
+
+    if resources:
+        if os.path.isdir(resources):
+            for dp, dirs, files in os.walk(resources):
+                for fname in files:
+                    fpath  = os.path.join(dp, fname)
+                    if os.path.isfile(fpath):
+                        zip.write(fpath, os.path.join('OPS', fname))
+                        manifest.append(etree.fromstring(
+                                '<item id="%s" href="%s" media-type="%s" />' % (os.path.splitext(fname)[0], fname, guess_type(fpath)[0])))
+
+        else:
+            print "resources path %s is not directory" % resources
+                
+
     if cover:
         if cover is True:
     if cover:
         if cover is True:
-            cover = WLCover
+            cover = FutureOfCopyrightCover
 
         cover_file = StringIO()
 
         cover_file = StringIO()
-        bound_cover = cover(document.book_info)
-        bound_cover.save(cover_file)
-        cover_name = 'cover.%s' % bound_cover.ext()
-        zip.writestr(os.path.join('OPS', cover_name), cover_file.getvalue())
+        c = cover(document.book_info)
+        c.save(cover_file)
+        c_name = 'cover.%s' % c.ext()
+        zip.writestr(os.path.join('OPS', c_name), cover_file.getvalue())
         del cover_file
 
         cover_tree = etree.parse(get_resource('epub/cover.html'))
         del cover_file
 
         cover_tree = etree.parse(get_resource('epub/cover.html'))
-        cover_tree.find('//' + XHTMLNS('img')).set('src', cover_name)
+        cover_tree.find('//' + XHTMLNS('img')).set('src', c_name)
         zip.writestr('OPS/cover.html', etree.tostring(
                         cover_tree, method="html", pretty_print=True))
 
         zip.writestr('OPS/cover.html', etree.tostring(
                         cover_tree, method="html", pretty_print=True))
 
-        if bound_cover.uses_dc_cover:
+        if c.uses_dc_cover:
             if document.book_info.cover_by:
                 document.edoc.getroot().set('data-cover-by', document.book_info.cover_by)
             if document.book_info.cover_source:
             if document.book_info.cover_by:
                 document.edoc.getroot().set('data-cover-by', document.book_info.cover_by)
             if document.book_info.cover_source:
@@ -466,11 +505,12 @@ def transform(wldoc, verbose=False,
         manifest.append(etree.fromstring(
             '<item id="cover" href="cover.html" media-type="application/xhtml+xml" />'))
         manifest.append(etree.fromstring(
         manifest.append(etree.fromstring(
             '<item id="cover" href="cover.html" media-type="application/xhtml+xml" />'))
         manifest.append(etree.fromstring(
-            '<item id="cover-image" href="%s" media-type="%s" />' % (cover_name, bound_cover.mime_type())))
+            '<item id="cover-image" href="%s" media-type="%s" />' % (c_name, c.mime_type())))
         spine.insert(0, etree.fromstring('<itemref idref="cover" linear="no" />'))
         opf.getroot()[0].append(etree.fromstring('<meta name="cover" content="cover-image"/>'))
         guide.append(etree.fromstring('<reference href="cover.html" type="cover" title="Okładka"/>'))
         spine.insert(0, etree.fromstring('<itemref idref="cover" linear="no" />'))
         opf.getroot()[0].append(etree.fromstring('<meta name="cover" content="cover-image"/>'))
         guide.append(etree.fromstring('<reference href="cover.html" type="cover" title="Okładka"/>'))
-
+    
+              
 
     annotations = etree.Element('annotations')
 
 
     annotations = etree.Element('annotations')
 
@@ -481,17 +521,36 @@ def transform(wldoc, verbose=False,
                                '</navMap></ncx>')
     nav_map = toc_file[-1]
 
                                '</navMap></ncx>')
     nav_map = toc_file[-1]
 
+    manifest.append(etree.fromstring(
+        '<item id="first" href="first.html" media-type="application/xhtml+xml" />'))
+    spine.append(etree.fromstring(
+        '<itemref idref="first" />'))
+    html_tree = xslt(document.edoc, get_resource('epub/xsltFirst.xsl'))
+#    chars.update(used_chars(html_tree.getroot()))
+    zip.writestr('OPS/first.html', etree.tostring(
+                        html_tree, method="html", pretty_print=True))
+
+    if intro_file:
+        manifest.append(etree.fromstring(
+                '<item id="intro" href="intro.html" media-type="application/xhtml+xml" />'))
+        spine.append(etree.fromstring(
+                '<itemref idref="intro" />'))
+        zip.writestr('OPS/intro.html', open(intro_file or get_resource('epub/intro.html')).read())
+
+
     if html_toc:
         manifest.append(etree.fromstring(
             '<item id="html_toc" href="toc.html" media-type="application/xhtml+xml" />'))
         spine.append(etree.fromstring(
             '<itemref idref="html_toc" />'))
     if html_toc:
         manifest.append(etree.fromstring(
             '<item id="html_toc" href="toc.html" media-type="application/xhtml+xml" />'))
         spine.append(etree.fromstring(
             '<itemref idref="html_toc" />'))
-        guide.append(etree.fromstring('<reference href="toc.html" type="toc" title="Spis treści"/>'))
+        guide.append(etree.fromstring('<reference href="toc.html" type="toc" title="Table of Contents"/>'))
 
     toc, chunk_counter, chars, sample = transform_file(document, sample=sample)
 
 
     toc, chunk_counter, chars, sample = transform_file(document, sample=sample)
 
+    toc.add("Informacje redakcyjne", "first.html", index=0)
+
     if len(toc.children) < 2:
     if len(toc.children) < 2:
-        toc.add(u"Początek utworu", "part1.html")
+        toc.add(u"Początek książki", "part1.html")
 
     # Last modifications in container files and EPUB creation
     if len(annotations) > 0:
 
     # Last modifications in container files and EPUB creation
     if len(annotations) > 0:
@@ -506,7 +565,16 @@ def transform(wldoc, verbose=False,
         zip.writestr('OPS/annotations.html', etree.tostring(
                             html_tree, method="html", pretty_print=True))
 
         zip.writestr('OPS/annotations.html', etree.tostring(
                             html_tree, method="html", pretty_print=True))
 
-    toc.add("Strona redakcyjna", "last.html")
+    # toc.add("Weprzyj Wolne Lektury", "support.html")
+    # manifest.append(etree.fromstring(
+    #     '<item id="support" href="support.html" media-type="application/xhtml+xml" />'))
+    # spine.append(etree.fromstring(
+    #     '<itemref idref="support" />'))
+    # html_string = open(get_resource('epub/support.html')).read()
+    # chars.update(used_chars(etree.fromstring(html_string)))
+    # zip.writestr('OPS/support.html', html_string)
+
+    toc.add("Informacje redakcyjne", "last.html")
     manifest.append(etree.fromstring(
         '<item id="last" href="last.html" media-type="application/xhtml+xml" />'))
     spine.append(etree.fromstring(
     manifest.append(etree.fromstring(
         '<item id="last" href="last.html" media-type="application/xhtml+xml" />'))
     spine.append(etree.fromstring(