self.height += height
def text(self, text, color='#000', font=None, line_height=20,
- shadow_color=None):
+ shadow_color=None, shortener=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]
+ if shortener:
+ for line in shortener(text):
+ if text_draw.textsize(line, font=font)[0] <= self.max_text_width:
+ break
+ text = ''
+ else:
+ 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
# go to next line
text = text[len(line):]
+ @staticmethod
+ def person_shortener(text):
+ yield text
+ chunks = text.split()
+ n_chunks = len(chunks)
+ # make initials from given names, starting from last
+ for i in range(n_chunks - 2, -1, -1):
+ chunks[i] = chunks[i][0] + '.'
+ yield " ".join(chunks)
+ # remove given names initials, starting from last
+ while len(chunks) > 2:
+ del chunks[1]
+ yield " ".join(chunks)
+
+ @staticmethod
+ def title_shortener(text):
+ yield text
+ chunks = text.split()
+ n_chunks = len(chunks)
+ # remove words, starting from last one
+ while len(chunks) > 1:
+ del chunks[-1]
+ yield " ".join(chunks) + u'…'
+
def image(self):
"""Creates the actual Image object."""
image = Image.new('RGBA', (self.max_width,
background_color = '#fff'
background_img = None
+ author_align = 'c'
author_top = 100
author_margin_left = 20
author_margin_right = 20
author_color = '#000'
author_shadow = None
author_font = None
+ author_wrap = True
+ title_align = 'c'
title_top = 100
title_margin_left = 20
title_margin_right = 20
title_color = '#000'
title_shadow = None
title_font = None
+ title_wrap = True
logo_bottom = None
logo_width = None
if self.background_img:
background = Image.open(self.background_img)
- img.paste(background, None, background)
+ try:
+ img.paste(background, None, background)
+ except ValueError, e:
+ img.paste(background)
del background
# WL logo
)
author_font = self.author_font or ImageFont.truetype(
get_resource('fonts/DejaVuSerif.ttf'), 30)
+ author_shortener = None if self.author_wrap else TextBox.person_shortener
tbox.text(self.pretty_author(), self.author_color, author_font,
- self.author_lineskip, self.author_shadow)
+ self.author_lineskip, self.author_shadow, author_shortener)
text_img = tbox.image()
img.paste(text_img, (self.author_margin_left, top), text_img)
)
title_font = self.author_font or ImageFont.truetype(
get_resource('fonts/DejaVuSerif.ttf'), 40)
+ title_shortener = None if self.title_wrap else TextBox.title_shortener
tbox.text(self.pretty_title(), self.title_color, title_font,
- self.title_lineskip, self.title_shadow)
+ self.title_lineskip, self.title_shadow, title_shortener)
text_img = tbox.image()
img.paste(text_img, (self.title_margin_left, top), text_img)
logo_bottom = 25
logo_width = 250
format = 'PNG'
+
+
+class ArtaTechCover(Cover):
+ width = 600
+ height = 800
+ background_img = get_resource('res/cover-arta-tech.jpg')
+ author_top = 132
+ author_margin_left = 235
+ author_margin_right = 23
+ author_align = 'r'
+ author_font = ImageFont.truetype(get_resource('fonts/DroidSans.ttf'), 32)
+ author_color = '#555555'
+ author_wrap = False
+ title_top = 17
+ title_margin_right = 21
+ title_margin_left = 60
+ title_align = 'r'
+ title_font = ImageFont.truetype(get_resource('fonts/EBGaramond-Regular.ttf'), 42)
+ title_color = '#222222'
+ title_wrap = False
+ format = 'JPEG'
+
+ def pretty_author(self):
+ return self.author.upper()
+
+
+def ImageCover(img):
+ """ a class factory for simple image covers """
+ img = Image.open(img)
+
+ class ImgCover(Cover):
+ def image(self):
+ return img
+
+ @property
+ def format(self):
+ return self.image().format
+
+ return ImgCover
#
from __future__ import with_statement
+from copy import deepcopy
import os
import os.path
import subprocess
sample=n: generate sample e-book (with at least n paragraphs)
cover: a cover.Cover object or True for default
- flags: less-advertising, without-fonts
+ flags: less-advertising, without-fonts, images, not-wl
"""
def transform_file(wldoc, chunk_counter=1, first=True, sample=None):
spine = opf.find('.//' + OPFNS('spine'))
output_file = NamedTemporaryFile(prefix='librarian', suffix='.epub', delete=False)
+
zip = zipfile.ZipFile(output_file, 'w', zipfile.ZIP_DEFLATED)
# write static elements
'<rootfiles><rootfile full-path="OPS/content.opf" ' \
'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/jedenprocent.png'), os.path.join('OPS', 'jedenprocent.png'))
+ if not flags or 'not-wl' not in flags:
+ manifest.append(etree.fromstring(
+ '<item id="logo_wolnelektury" href="logo_wolnelektury.png" media-type="image/png" />'))
+ manifest.append(etree.fromstring(
+ '<item id="jedenprocent" href="jedenprocent.png" media-type="image/png" />'))
+ zip.write(get_resource('res/wl-logo-small.png'), os.path.join('OPS', 'logo_wolnelektury.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'))
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"/>'))
+ if flags and 'images' in flags:
+ for ilustr in document.edoc.findall('//ilustr'):
+ src = ilustr.get('src')
+ mime = ImageCover(src)().mime_type()
+ zip.write(src, os.path.join('OPS', src))
+ manifest.append(etree.fromstring(
+ '<item id="%s" href="%s" media-type="%s" />' % (src, src, mime)))
+ # get it up to master
+ after = ilustr
+ while after.getparent().tag not in ['powiesc', 'opowiadanie', 'liryka_l', 'liryka_lp', 'dramat_wierszowany_l', 'dramat_wierszowany_lp', 'dramat_wspolczesny']:
+ after = after.getparent()
+ if not(after is ilustr):
+ moved = deepcopy(ilustr)
+ ilustr.tag = 'extra'
+ ilustr.text = None
+ moved.tail = None
+ after.addnext(moved)
+ else:
+ for ilustr in document.edoc.findall('//ilustr'):
+ ilustr.tag = 'extra'
annotations = etree.Element('annotations')
'<item id="last" href="last.html" media-type="application/xhtml+xml" />'))
spine.append(etree.fromstring(
'<itemref idref="last" />'))
- html_tree = xslt(document.edoc, get_resource('epub/xsltLast.xsl'))
+ stopka = document.edoc.find('//stopka')
+ if stopka is not None:
+ stopka.tag = 'stopka_'
+ replace_by_verse(stopka)
+ html_tree = xslt(stopka, get_resource('epub/xsltScheme.xsl'))
+ else:
+ html_tree = xslt(document.edoc, get_resource('epub/xsltLast.xsl'))
chars.update(used_chars(html_tree.getroot()))
zip.writestr('OPS/last.html', etree.tostring(
html_tree, method="html", pretty_print=True))
#book-text
{
- margin: 2em;
+ /*margin: 2em;*/
+ margin: 5px;
/*margin-right: 9em;*/
}
p.footer {
margin-top: 2em;
}
+
+.ilustr {
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+.ilustr img {
+ max-width: 100%;
+}
<item id="toc" href="toc.ncx" media-type="application/x-dtbncx+xml" />
<item id="style" href="style.css" media-type="text/css" />
<item id="titlePage" href="title.html" media-type="application/xhtml+xml" />
- <item id="logo_wolnelektury" href="logo_wolnelektury.png" media-type="image/png" />
- <item id="jedenprocent" href="jedenprocent.png" media-type="image/png" />
</manifest>
<spine toc="toc">
<itemref idref="titlePage" />
<hr class="spacer-line" xmlns="http://www.w3.org/1999/xhtml"></hr>
</xsl:template>
+ <xsl:template match="ilustr">
+ <div xmlns="http://www.w3.org/1999/xhtml" class="ilustr">
+ <img xmlns="http://www.w3.org/1999/xhtml" alt="ilustracja">
+ <xsl:attribute name="src">
+ <xsl:value-of select="@src" />
+ </xsl:attribute>
+ </img>
+ </div>
+ </xsl:template>
+
+ <xsl:template match="stopka" />
+
<!--===========================================================-->
<!-- Tagi SPECJALNE -->
<!--===========================================================-->
<xsl:call-template name="translators" />
+ <xsl:if test="not(utwor/@not-wl)">
<xsl:if test="not(utwor/@less-advertising)">
<p class="info">
<a>
<p class="footer info">
<a href="http://www.wolnelektury.pl/"><img src="logo_wolnelektury.png" alt="WolneLektury.pl" /></a>
</p>
+ </xsl:if>
+ <!--xsl:if test="utwor/@not-wl">
+ <p class="info">
+ Konwersja wykonana przez<a href="http://www.nowoczesnapolska.org.pl/"> fundację Nowoczesna Polska</a>.
+ </p>
+ </xsl:if-->
</div>
</body>
</html>
class GandalfPdfPackager(PdfPackager):
cover = cover.GandalfCover
+class ArtaTechEpubPackager(EpubPackager):
+ cover = cover.ArtaTechCover
+
+class ArtaTechPdfPackager(PdfPackager):
+ cover = cover.ArtaTechCover
+
class BookotekaEpubPackager(EpubPackager):
cover = cover.BookotekaCover
import optparse
from librarian import DirDocProvider, ParseError
+from librarian.cover import ImageCover
from librarian.parser import WLDocument
help='specifies the output file')
parser.add_option('-O', '--output-dir', dest='output_dir', metavar='DIR',
help='specifies the directory for output')
+ parser.add_option('-i', '--with-images', action='store_true', dest='images', default=False,
+ help='add images with <ilustr src="..."/>')
+ parser.add_option('-A', '--less-advertising', action='store_true', dest='less_advertising', default=False,
+ help='less advertising, for commercial purposes')
+ parser.add_option('-W', '--not-wl', action='store_true', dest='not_wl', default=False,
+ help='not a WolneLektury book')
+ parser.add_option('--cover', dest='cover', metavar='FILE',
+ help='specifies the cover file')
options, input_filenames = parser.parse_args()
output_file = None
doc = WLDocument.from_file(main_input, provider=provider)
- epub = doc.as_epub(cover=options.with_cover)
+
+ if options.cover:
+ cover = ImageCover(options.cover)
+ else:
+ cover = options.with_cover
+
+ flags = []
+ if options.images:
+ flags.append('images')
+ if options.less_advertising:
+ flags.append('less-advertising')
+ if options.not_wl:
+ flags.append('not-wl')
+
+ epub = doc.as_epub(cover=cover, flags=flags)
doc.save_output_file(epub,
output_file, options.output_dir, options.make_dir, 'epub')
help='prepare EPUB files for Gandalf')
parser.add_option('--gandalf-pdf', action='store_true', dest='gandalf_pdf', default=False,
help='prepare PDF files for Gandalf')
+ parser.add_option('--artatech', action='store_true', dest='artatech', default=False,
+ help='prepare EPUB files for Arta-Tech')
+ parser.add_option('--artatech-pdf', action='store_true', dest='artatech_pdf', default=False,
+ help='prepare PDF files for Arta-Tech')
parser.add_option('--virtualo', action='store_true', dest='virtualo', default=False,
help='prepare files for Virtualo API')
parser.add_option('--prestigio', action='store_true', dest='prestigio', default=False,
packagers.GandalfEpubPackager.prepare(input_filenames, options.output_dir, options.verbose)
if options.gandalf_pdf:
packagers.GandalfPdfPackager.prepare(input_filenames, options.output_dir, options.verbose)
+ if options.artatech:
+ packagers.ArtaTechEpubPackager.prepare(input_filenames, options.output_dir, options.verbose)
+ if options.artatech_pdf:
+ packagers.ArtaTechPdfPackager.prepare(input_filenames, options.output_dir, options.verbose)
if options.virtualo:
packagers.VirtualoEpubPackager.prepare(input_filenames, options.output_dir, options.verbose)
if options.prestigio: