new cover scheme; Cover accepts BookInfo now; e-books include cover attribution,...
authorRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Mon, 12 Dec 2011 10:25:15 +0000 (11:25 +0100)
committerRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Mon, 12 Dec 2011 10:25:15 +0000 (11:25 +0100)
14 files changed:
librarian/__init__.py
librarian/cover.py
librarian/dcparser.py
librarian/epub.py
librarian/epub/xsltLast.xsl
librarian/mobi.py
librarian/packagers.py
librarian/pdf.py
librarian/pdf/wl.cls
librarian/pdf/wl2tex.xslt
scripts/book2cover [new file with mode: 0755]
scripts/book2epub
scripts/book2pdf
setup.py

index 32a3af0..2e515dd 100644 (file)
@@ -150,7 +150,6 @@ class DirDocProvider(DocProvider):
     def __init__(self, dir_):
         self.dir = dir_
         self.files = {}
     def __init__(self, dir_):
         self.dir = dir_
         self.files = {}
-        return super(DirDocProvider, self).__init__()
 
     def by_slug_and_lang(self, slug, lang=None):
         fname = WLURI.from_slug_and_lang(slug, lang).filename_stem() + '.xml'
 
     def by_slug_and_lang(self, slug, lang=None):
         fname = WLURI.from_slug_and_lang(slug, lang).filename_stem() + '.xml'
index f7d8f7d..f93e709 100644 (file)
@@ -7,7 +7,79 @@ import Image, ImageFont, ImageDraw, ImageFilter
 from librarian import get_resource
 
 
 from librarian import get_resource
 
 
+class TextBox(object):
+    """Creates an Image with a series of centered strings."""
+
+    SHADOW_X = 3
+    SHADOW_Y = 3
+    SHADOW_BLUR = 3
+
+    def __init__(self, max_width, max_height, padding_x=None, padding_y=None):
+        if padding_x is None:
+            padding_x = self.SHADOW_X + self.SHADOW_BLUR
+        if padding_y is None:
+            padding_y = self.SHADOW_Y + self.SHADOW_BLUR
+
+        self.max_width = max_width
+        self.max_text_width = max_width - 2 * padding_x
+        self.padding_y = padding_y
+        self.height = padding_y
+        self.img = Image.new('RGBA', (max_width, max_height))
+        self.draw = ImageDraw.Draw(self.img)
+        self.shadow_img = None
+        self.shadow_draw = None
+
+    def skip(self, height):
+        """Skips some vertical space."""
+        self.height += height
+
+    def text(self, text, color='#000', font=None, line_height=20, 
+             shadow_color=None):
+        """Writes some centered text."""
+        if shadow_color:
+            if not self.shadow_img:
+                self.shadow_img = Image.new('RGBA', self.img.size)
+                self.shadow_draw = ImageDraw.Draw(self.shadow_img)
+        while text:
+            line = text
+            line_width = self.draw.textsize(line, font=font)[0]
+            while line_width > self.max_text_width:
+                parts = line.rsplit(' ', 1)
+                if len(parts) == 1:
+                    line_width = self.max_text_width
+                    break
+                line = parts[0]
+                line_width = self.draw.textsize(line, font=font)[0]
+            line = line.strip() + ' '
+
+            pos_x = (self.max_width - line_width) / 2
+
+            if shadow_color:
+                self.shadow_draw.text(
+                        (pos_x + self.SHADOW_X, self.height + self.SHADOW_Y),
+                        line, font=font, fill=shadow_color
+                )
+
+            self.draw.text((pos_x, self.height), line, font=font, fill=color)
+            self.height += line_height
+            # go to next line
+            text = text[len(line):]
+
+    def image(self):
+        """Creates the actual Image object."""
+        image = Image.new('RGBA', (self.max_width,
+                                   self.height + self.padding_y))
+        if self.shadow_img:
+            shadow = self.shadow_img.filter(ImageFilter.BLUR)
+            image.paste(shadow, (0, 0), shadow)
+            image.paste(self.img, (0, 0), self.img)
+        else:
+            image.paste(self.img, (0, 0))
+        return image
+
+
 class Cover(object):
 class Cover(object):
+    """Abstract base class for cover images generator."""
     width = 600
     height = 800
     background_color = '#fff'
     width = 600
     height = 800
     background_color = '#fff'
@@ -31,10 +103,10 @@ class Cover(object):
 
     logo_bottom = None
     logo_width = None
 
     logo_bottom = None
     logo_width = None
+    uses_dc_cover = False
 
     format = 'JPEG'
 
 
     format = 'JPEG'
 
-
     exts = {
         'JPEG': 'jpg',
         'PNG': 'png',
     exts = {
         'JPEG': 'jpg',
         'PNG': 'png',
@@ -45,42 +117,16 @@ class Cover(object):
         'PNG': 'image/png',
         }
 
         'PNG': 'image/png',
         }
 
-
-    @staticmethod
-    def draw_centered_text(text, img, font, margin_left, width, pos_y, lineskip, color, shadow_color):
-        if shadow_color:
-            shadow_img = Image.new('RGBA', img.size)
-            shadow_draw = ImageDraw.Draw(shadow_img)
-        text_img = Image.new('RGBA', img.size)
-        text_draw = ImageDraw.Draw(text_img)
-        while text:
-            line = text
-            while text_draw.textsize(line, font=font)[0] > width:
-                try:
-                    line, ext = line.rsplit(' ', 1)
-                except:
-                    break
-            pos_x = margin_left + (width - text_draw.textsize(line, font=font)[0]) / 2
-            if shadow_color:
-                shadow_draw.text((pos_x + 3, pos_y + 3), line, font=font, fill=shadow_color)
-            text_draw.text((pos_x, pos_y), line, font=font, fill=color)
-            pos_y += lineskip
-            text = text[len(line)+1:]
-        if shadow_color:
-            shadow_img = shadow_img.filter(ImageFilter.BLUR)
-            img.paste(shadow_img, None, shadow_img)
-        img.paste(text_img, None, text_img)
-        return pos_y
-
-
-    def __init__(self, author='', title=''):
-        self.author = author
-        self.title = title
+    def __init__(self, book_info):
+        self.author = book_info.author.readable()
+        self.title = book_info.title
 
     def pretty_author(self):
 
     def pretty_author(self):
+        """Allows for decorating author's name."""
         return self.author
 
     def pretty_title(self):
         return self.author
 
     def pretty_title(self):
+        """Allows for decorating title."""
         return self.title
 
     def image(self):
         return self.title
 
     def image(self):
@@ -97,14 +143,29 @@ class Cover(object):
             logo = logo.resize((self.logo_width, logo.size[1] * self.logo_width / logo.size[0]))
             img.paste(logo, ((self.width - self.logo_width) / 2, img.size[1] - logo.size[1] - self.logo_bottom))
 
             logo = logo.resize((self.logo_width, logo.size[1] * self.logo_width / logo.size[0]))
             img.paste(logo, ((self.width - self.logo_width) / 2, img.size[1] - logo.size[1] - self.logo_bottom))
 
-        author_font = self.author_font or ImageFont.truetype(get_resource('fonts/DejaVuSerif.ttf'), 30)
-        title_y = self.draw_centered_text(self.pretty_author(), img, author_font,
-                    self.author_margin_left, self.width - self.author_margin_left - self.author_margin_right, self.author_top,
-                    self.author_lineskip, self.author_color, self.author_shadow) + self.title_top
-        title_font = self.title_font or ImageFont.truetype(get_resource('fonts/DejaVuSerif.ttf'), 40)
-        self.draw_centered_text(self.pretty_title(), img, title_font,
-                    self.title_margin_left, self.width - self.title_margin_left - self.title_margin_right, title_y,
-                    self.title_lineskip, self.title_color, self.title_shadow)
+        top = self.author_top
+        tbox = TextBox(
+            self.width - self.author_margin_left - self.author_margin_right,
+            self.height - top,
+            )
+        author_font = self.author_font or ImageFont.truetype(
+            get_resource('fonts/DejaVuSerif.ttf'), 30)
+        tbox.text(self.pretty_author(), self.author_color, author_font,
+            self.author_lineskip, self.author_shadow)
+        text_img = tbox.image()
+        img.paste(text_img, (self.author_margin_left, top), text_img)
+        
+        top += text_img.size[1] + self.title_top
+        tbox = TextBox(
+            self.width - self.title_margin_left - self.title_margin_right,
+            self.height - top,
+            )
+        title_font = self.author_font or ImageFont.truetype(
+            get_resource('fonts/DejaVuSerif.ttf'), 40)
+        tbox.text(self.pretty_title(), self.title_color, title_font,
+            self.title_lineskip, self.title_shadow)
+        text_img = tbox.image()
+        img.paste(text_img, (self.title_margin_left, top), text_img)
 
         return img
 
 
         return img
 
@@ -119,10 +180,122 @@ class Cover(object):
 
 
 class WLCover(Cover):
 
 
 class WLCover(Cover):
-    author_font = ImageFont.truetype(get_resource('fonts/JunicodeWL-Italic.ttf'), 40)
-    title_font = ImageFont.truetype(get_resource('fonts/JunicodeWL-Italic.ttf'), 50)
-    logo_width = 250
-    logo_bottom = 20
+    """Default Wolne Lektury cover generator."""
+    uses_dc_cover = True
+    author_font = ImageFont.truetype(
+        get_resource('fonts/JunicodeWL-Regular.ttf'), 20)
+    author_lineskip = 30
+    title_font = ImageFont.truetype(
+        get_resource('fonts/DejaVuSerif-Bold.ttf'), 30)
+    title_lineskip = 40
+    title_box_width = 350
+    bar_width = 35
+    background_color = '#444'
+    author_color = '#444'
+
+    epochs = {
+        u'Starożytność': 0,
+        u'Średniowiecze': 30,
+        u'Renesans': 60,
+        u'Barok': 90,
+        u'Oświecenie': 120,
+        u'Romantyzm': 150,
+        u'Pozytywizm': 180,
+        u'Modernizm': 210,
+        u'Dwudziestolecie międzywojenne': 240,
+        u'Współczesność': 270,
+    }
+
+    def __init__(self, book_info):
+        super(WLCover, self).__init__(book_info)
+        self.kind = book_info.kind
+        self.epoch = book_info.epoch
+        if book_info.cover_url:
+            from urllib2 import urlopen
+            from StringIO import StringIO
+
+            bg_src = urlopen(book_info.cover_url)
+            self.background_img = StringIO(bg_src.read())
+            bg_src.close()
+
+    def pretty_author(self):
+        return self.author.upper()
+
+    def image(self):
+        from colorsys import hsv_to_rgb
+
+        img = Image.new('RGB', (self.width, self.height), self.background_color)
+        draw = ImageDraw.Draw(img)
+
+        if self.epoch in self.epochs:
+            epoch_color = tuple(int(255 * c) for c in hsv_to_rgb(
+                    float(self.epochs[self.epoch]) / 360, .7, .7))
+        else:
+            epoch_color = '#000'
+        draw.rectangle((0, 0, self.bar_width, self.height), fill=epoch_color)
+
+        if self.background_img:
+            src = Image.open(self.background_img)
+            trg_size = (self.width - self.bar_width, self.height)
+            if src.size[0] * trg_size[1] < src.size[1] * trg_size[0]:
+                resized = (
+                    trg_size[0],
+                    src.size[1] * trg_size[0] / src.size[0]
+                )
+                cut = (resized[1] - trg_size[1]) / 2
+                src = src.resize(resized)
+                src = src.crop((0, cut, src.size[0], src.size[1] - cut))
+            else:
+                resized = (
+                    src.size[0] * trg_size[1] / src.size[1],
+                    trg_size[1],
+                )
+                cut = (resized[0] - trg_size[0]) / 2
+                src = src.resize(resized)
+                src = src.crop((cut, 0, src.size[0] - cut, src.size[1]))
+            
+            img.paste(src, (self.bar_width, 0))
+            del src
+
+        box = TextBox(self.title_box_width, self.height, padding_y=20)
+        box.text(self.pretty_author(), 
+                 font=self.author_font,
+                 line_height=self.author_lineskip,
+                 color=self.author_color,
+                 shadow_color=self.author_shadow,
+                )
+
+        box.skip(10)
+        box.draw.line((75, box.height, 275, box.height), 
+                fill=self.author_color, width=2)
+        box.skip(15)
+
+        box.text(self.pretty_title(),
+                 line_height=self.title_lineskip,
+                 font=self.title_font,
+                 color=epoch_color,
+                 shadow_color=self.title_shadow,
+                )
+        box_img = box.image()
+
+        if self.kind == 'Liryka':
+            # top
+            box_top = 100
+        elif self.kind == 'Epika':
+            # bottom
+            box_top = self.height - 100 - box_img.size[1]
+        else:
+            # center
+            box_top = (self.height - box_img.size[1]) / 2
+
+        box_left = self.bar_width + (self.width - self.bar_width - 
+                        box_img.size[0]) / 2
+        draw.rectangle((box_left, box_top, 
+            box_left + box_img.size[0], box_top + box_img.size[1]),
+            fill='#fff')
+        img.paste(box_img, (box_left, box_top), box_img)
+
+        return img
 
 
 
 
 
 
index 992029e..57308c6 100644 (file)
@@ -147,6 +147,9 @@ class BookInfo(object):
         Field( DCNS('rights'), 'license_description'),
         Field( DCNS('language'), 'language'),
         Field( DCNS('description'), 'description', required=False),
         Field( DCNS('rights'), 'license_description'),
         Field( DCNS('language'), 'language'),
         Field( DCNS('description'), 'description', required=False),
+        Field( DCNS('relation.cover_image.url'), 'cover_url', required=False),
+        Field( DCNS('relation.cover_image.attribution'), 'cover_by', required=False),
+        Field( DCNS('relation.cover_image.source'), 'cover_source', required=False),
     )
 
     @classmethod
     )
 
     @classmethod
index b063380..80941eb 100644 (file)
@@ -16,6 +16,7 @@ from tempfile import mkdtemp, NamedTemporaryFile
 from shutil import rmtree
 
 from librarian import RDFNS, WLNS, NCXNS, OPFNS, XHTMLNS, OutputFile
 from shutil import rmtree
 
 from librarian import RDFNS, WLNS, NCXNS, OPFNS, XHTMLNS, OutputFile
+from librarian.cover import WLCover
 
 from librarian import functions, get_resource
 
 
 from librarian import functions, get_resource
 
@@ -290,7 +291,7 @@ def transform(wldoc, verbose=False,
     """ 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)
-    cover: a cover.Cover object
+    cover: a cover.Cover object or True for default
     flags: less-advertising, without-fonts
     """
 
     flags: less-advertising, without-fonts
     """
 
@@ -392,10 +393,17 @@ def transform(wldoc, verbose=False,
         style = get_resource('epub/style.css')
     zip.write(style, os.path.join('OPS', 'style.css'))
 
         style = get_resource('epub/style.css')
     zip.write(style, os.path.join('OPS', 'style.css'))
 
-
     if cover:
     if cover:
+        if cover is True:
+            cover = WLCover
+        if cover.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:
+                document.edoc.getroot().set('data-cover-source', document.book_info.cover_source)
+
         cover_file = StringIO()
         cover_file = StringIO()
-        c = cover(document.book_info.author.readable(), document.book_info.title)
+        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())
         c.save(cover_file)
         c_name = 'cover.%s' % c.ext()
         zip.writestr(os.path.join('OPS', c_name), cover_file.getvalue())
index 67f6b0e..751f97a 100644 (file)
@@ -9,7 +9,7 @@
   <xsl:output doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" />
   <xsl:output doctype-public="-//W3C//DTD XHTML 1.1//EN" />
 
   <xsl:output doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd" />
   <xsl:output doctype-public="-//W3C//DTD XHTML 1.1//EN" />
 
-  <xsl:template match="/">
+  <xsl:template match="utwor">
     <html>
       <head>
         <link rel="stylesheet" href="style.css" type="text/css" />
     <html>
       <head>
         <link rel="stylesheet" href="style.css" type="text/css" />
 
           <xsl:call-template name="editors" />
 
 
           <xsl:call-template name="editors" />
 
+          <xsl:if test="@data-cover-by">
+            <p class="info">Okładka na podstawie: 
+            <xsl:choose>
+            <xsl:when test="@data-cover-source">
+                <a>
+                <xsl:attribute name="href">
+                  <xsl:value-of select="@data-cover-source" />
+                </xsl:attribute>
+                <xsl:value-of select="@data-cover-by" />
+                </a>
+            </xsl:when>
+            <xsl:otherwise>
+                <xsl:value-of select="@data-cover-by" />
+            </xsl:otherwise>
+            </xsl:choose>
+            </p>
+          </xsl:if>
+
           <div class="info">
           <img src="jedenprocent.png" alt="Logo 1%" />
           <div>Przekaż 1% podatku na rozwój Wolnych Lektur.</div>
           <div class="info">
           <img src="jedenprocent.png" alt="Logo 1%" />
           <div>Przekaż 1% podatku na rozwój Wolnych Lektur.</div>
index a93315e..1e7569b 100755 (executable)
@@ -3,6 +3,7 @@
 # This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
 # This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
+from copy import deepcopy
 import os
 import subprocess
 from tempfile import NamedTemporaryFile
 import os
 import subprocess
 from tempfile import NamedTemporaryFile
@@ -22,19 +23,27 @@ def transform(wldoc, verbose=False,
     flags: less-advertising,
     """
 
     flags: less-advertising,
     """
 
-    book_info = wldoc.book_info
+    document = deepcopy(wldoc)
+    del wldoc
+    book_info = document.book_info
 
     # provide a cover by default
     if not cover:
         cover = WLCover
     cover_file = NamedTemporaryFile(suffix='.png', delete=False)
 
     # provide a cover by default
     if not cover:
         cover = WLCover
     cover_file = NamedTemporaryFile(suffix='.png', delete=False)
-    c = cover(book_info.author.readable(), book_info.title)
+    c = cover(book_info)
     c.save(cover_file)
 
     c.save(cover_file)
 
+    if cover.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:
+            document.edoc.getroot().set('data-cover-source', document.book_info.cover_source)
+
     if not flags:
         flags = []
     flags = list(flags) + ['without-fonts']
     if not flags:
         flags = []
     flags = list(flags) + ['without-fonts']
-    epub = wldoc.as_epub(verbose=verbose, sample=sample, html_toc=True,
+    epub = document.as_epub(verbose=verbose, sample=sample, html_toc=True,
             flags=flags, style=get_resource('mobi/style.css'))
 
     if verbose:
             flags=flags, style=get_resource('mobi/style.css'))
 
     if verbose:
index ebeb5b3..36a7b60 100644 (file)
@@ -130,10 +130,7 @@ class VirtualoEpubPackager(Packager):
                 product_elem[4][0][1].text = cls.utf_trunc(info.author.last_name, 100)
                 xml.append(product_elem)
 
                 product_elem[4][0][1].text = cls.utf_trunc(info.author.last_name, 100)
                 xml.append(product_elem)
 
-                cover.VirtualoCover(
-                    u' '.join(info.author.first_names + (info.author.last_name,)),
-                    info.title
-                    ).save(os.path.join(outfile_dir, slug+'.jpg'))
+                cover.VirtualoCover(info).save(os.path.join(outfile_dir, slug+'.jpg'))
                 outfile = os.path.join(outfile_dir, '1.epub')
                 outfile_sample = os.path.join(outfile_dir, '1.sample.epub')
                 doc.save_output_file(epub.transform(doc),
                 outfile = os.path.join(outfile_dir, '1.epub')
                 outfile_sample = os.path.join(outfile_dir, '1.sample.epub')
                 doc.save_output_file(epub.transform(doc),
index 02438a6..bcf8d9a 100644 (file)
@@ -21,6 +21,7 @@ from librarian.dcparser import Person
 from librarian.parser import WLDocument
 from librarian import ParseError, DCNS, get_resource, OutputFile
 from librarian import functions
 from librarian.parser import WLDocument
 from librarian import ParseError, DCNS, get_resource, OutputFile
 from librarian import functions
+from librarian.cover import WLCover
 
 
 functions.reg_substitute_entities()
 
 
 functions.reg_substitute_entities()
@@ -189,8 +190,15 @@ def transform(wldoc, verbose=False, save_tex=None, morefloats=None,
         document = load_including_children(wldoc)
 
         if cover:
         document = load_including_children(wldoc)
 
         if cover:
+            if cover is True:
+                cover = WLCover
             document.edoc.getroot().set('data-cover-width', str(cover.width))
             document.edoc.getroot().set('data-cover-height', str(cover.height))
             document.edoc.getroot().set('data-cover-width', str(cover.width))
             document.edoc.getroot().set('data-cover-height', str(cover.height))
+            if cover.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:
+                    document.edoc.getroot().set('data-cover-source', document.book_info.cover_source)
         if flags:
             for flag in flags:
                 document.edoc.getroot().set('flag-' + flag, 'yes')
         if flags:
             for flag in flags:
                 document.edoc.getroot().set('flag-' + flag, 'yes')
@@ -222,7 +230,7 @@ def transform(wldoc, verbose=False, save_tex=None, morefloats=None,
         temp = mkdtemp('-wl2pdf')
 
         if cover:
         temp = mkdtemp('-wl2pdf')
 
         if cover:
-            c = cover(document.book_info.author.readable(), document.book_info.title)
+            c = cover(document.book_info)
             with open(os.path.join(temp, 'cover.png'), 'w') as f:
                 c.save(f)
 
             with open(os.path.join(temp, 'cover.png'), 'w') as f:
                 c.save(f)
 
index 37d1d24..c9305ca 100644 (file)
@@ -244,6 +244,9 @@ Letters={SmallCaps,UppercaseSmallCaps}
 
     \editors
 
 
     \editors
 
+    \vspace{.6em}
+    \coverby
+
     \color{black}
   }
   \end{figure}
     \color{black}
   }
   \end{figure}
index 25d76d9..1a675ba 100644 (file)
             </parm></cmd>
             <xsl:apply-templates select="powiesc|opowiadanie|liryka_l|liryka_lp|dramat_wierszowany_l|dramat_wierszowany_lp|dramat_wspolczesny" />
             <xsl:apply-templates select="utwor" mode="part" />
             </parm></cmd>
             <xsl:apply-templates select="powiesc|opowiadanie|liryka_l|liryka_lp|dramat_wierszowany_l|dramat_wierszowany_lp|dramat_wspolczesny" />
             <xsl:apply-templates select="utwor" mode="part" />
+
+            <TeXML escape="0">
+                \def\coverby{
+                <xsl:if test="@data-cover-by">Okładka na podstawie: 
+                    <xsl:choose>
+                    <xsl:when test="@data-cover-source">
+                        \href{\datacoversource}{\datacoverby}
+                    </xsl:when>
+                    <xsl:otherwise>
+                        \datacoverby{}
+                    </xsl:otherwise>
+                    </xsl:choose>
+                </xsl:if>
+                }
+            </TeXML>
+
             <cmd name="editorialsection" />
         </env>
     </TeXML>
             <cmd name="editorialsection" />
         </env>
     </TeXML>
diff --git a/scripts/book2cover b/scripts/book2cover
new file mode 100755 (executable)
index 0000000..d2befc3
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+import os
+import optparse
+
+from librarian import ParseError
+from librarian.parser import WLDocument
+from librarian.cover import WLCover
+
+
+if __name__ == '__main__':
+    # Parse commandline arguments
+    usage = """Usage: %prog [options] SOURCE [SOURCE...]
+    Create cover images for SOURCE files."""
+
+    parser = optparse.OptionParser(usage=usage)
+
+    parser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False,
+        help='print status messages to stdout')
+
+    options, input_filenames = parser.parse_args()
+
+    if len(input_filenames) < 1:
+        parser.print_help()
+        exit(1)
+
+    # Do some real work
+    for input_filename in input_filenames:
+        if options.verbose:
+            print input_filename
+
+        output_filename = os.path.splitext(input_filename)[0] + '.png'
+
+        doc = WLDocument.from_file(input_filename)
+        WLCover(doc.book_info).save(output_filename)
index 9af3692..bdb5ac6 100755 (executable)
@@ -20,6 +20,8 @@ if __name__ == '__main__':
 
     parser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False,
         help='print status messages to stdout')
 
     parser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False,
         help='print status messages to stdout')
+    parser.add_option('-c', '--with-cover', action='store_true', dest='with_cover', default=False,
+                      help='create default cover')
     parser.add_option('-d', '--make-dir', action='store_true', dest='make_dir', default=False,
                       help='create a directory for author and put the PDF in it')
     parser.add_option('-o', '--output-file', dest='output_file', metavar='FILE',
     parser.add_option('-d', '--make-dir', action='store_true', dest='make_dir', default=False,
                       help='create a directory for author and put the PDF in it')
     parser.add_option('-o', '--output-file', dest='output_file', metavar='FILE',
@@ -47,7 +49,7 @@ if __name__ == '__main__':
                 output_file = None
 
             doc = WLDocument.from_file(main_input, provider=provider)
                 output_file = None
 
             doc = WLDocument.from_file(main_input, provider=provider)
-            epub = doc.as_epub()
+            epub = doc.as_epub(cover=options.with_cover)
 
             doc.save_output_file(epub,
                 output_file, options.output_dir, options.make_dir, 'epub')
 
             doc.save_output_file(epub,
                 output_file, options.output_dir, options.make_dir, 'epub')
index 171264b..258c20d 100755 (executable)
@@ -18,6 +18,8 @@ if __name__ == '__main__':
     parser = OptionParser(usage)
     parser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False,
                       help='make lots of noise and revert to default interaction in LaTeX')
     parser = OptionParser(usage)
     parser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False,
                       help='make lots of noise and revert to default interaction in LaTeX')
+    parser.add_option('-c', '--with-cover', action='store_true', dest='with_cover', default=False,
+                      help='create default cover')
     parser.add_option('-d', '--make-dir', action='store_true', dest='make_dir', default=False,
                       help='create a directory for author and put the PDF in it')
     parser.add_option('-t', '--save-tex', dest='save_tex', metavar='FILE',
     parser.add_option('-d', '--make-dir', action='store_true', dest='make_dir', default=False,
                       help='create a directory for author and put the PDF in it')
     parser.add_option('-t', '--save-tex', dest='save_tex', metavar='FILE',
@@ -49,6 +51,7 @@ if __name__ == '__main__':
 
             doc = WLDocument.from_file(main_input, provider=provider)
             pdf = doc.as_pdf(save_tex=options.save_tex,
 
             doc = WLDocument.from_file(main_input, provider=provider)
             pdf = doc.as_pdf(save_tex=options.save_tex,
+                        cover=options.with_cover,
                         morefloats=options.morefloats)
 
             doc.save_output_file(pdf,
                         morefloats=options.morefloats)
 
             doc.save_output_file(pdf,
index 023c943..4d8ec9b 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -39,6 +39,7 @@ setup(
              'scripts/book2mobi',
              'scripts/book2pdf',
              'scripts/book2partner',
              'scripts/book2mobi',
              'scripts/book2pdf',
              'scripts/book2partner',
+             'scripts/book2cover',
              'scripts/bookfragments',
              'scripts/genslugs'],
     tests_require=['nose>=0.11', 'coverage>=3.0.1'],
              'scripts/bookfragments',
              'scripts/genslugs'],
     tests_require=['nose>=0.11', 'coverage>=3.0.1'],