from .html import HtmlBuilder, StandaloneHtmlBuilder, DaisyHtmlBuilder
from .sanitize import Sanitizer
from .daisy import DaisyBuilder
+from .epub import EpubBuilder
+from .pdf import PdfBuilder
builders = OrderedDict([
("html-daisy", DaisyHtmlBuilder),
("daisy", DaisyBuilder),
("sanitizer", Sanitizer),
+
+ ("epub", EpubBuilder),
+ ("pdf", PdfBuilder),
])
--- /dev/null
+from datetime import date
+import os
+import tempfile
+from ebooklib import epub
+from lxml import etree
+import six
+from librarian import functions, OutputFile, get_resource, XHTMLNS
+from librarian.cover import make_cover
+from librarian.embeds.mathml import MathML
+import librarian.epub
+from librarian.fonts import strip_font
+from librarian.fundraising import FUNDRAISING
+
+
+
+
+class Xhtml:
+ def __init__(self):
+ self.element = etree.XML('''<html xmlns="http://www.w3.org/1999/xhtml"><head><link rel="stylesheet" href="style.css" type="text/css"/><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title>WolneLektury.pl</title></head><body/></html>''')
+
+ @property
+ def title(self):
+ return self.element.find('.//' + XHTMLNS('title'))
+
+ @property
+ def body(self):
+ return self.element.find('.//' + XHTMLNS('body'))
+
+
+class Builder:
+ file_extension = None
+
+ def __init__(self, base_url=None):
+ self._base_url = base_url or 'file:///home/rczajka/for/fnp/librarian/temp~/maly/img/'
+ self.footnotes = etree.Element('div', id='footnotes')
+
+ self.cursors = {
+# None: None,
+# 'header': self.header,
+ 'footnotes': self.footnotes,
+ }
+ self.current_cursors = []
+
+ self.toc_base = 0
+
+ @property
+ def cursor(self):
+ return self.current_cursors[-1]
+
+ def enter_fragment(self, fragment):
+ self.current_cursors.append(self.cursors[fragment])
+
+ def exit_fragment(self):
+ self.current_cursors.pop()
+
+ def create_fragment(self, name, element):
+ assert name not in self.cursors
+ self.cursors[name] = element
+
+ def forget_fragment(self, name):
+ del self.cursors[name]
+
+
+
+ @property
+ def base_url(self):
+ if self._base_url is not None:
+ return self._base_url
+ else:
+ return 'https://wolnelektury.pl/media/book/pictures/{}/'.format(self.document.meta.url.slug)
+
+
+ # Base URL should be on Document level, not builder.
+ def build(self, document, **kwargs):
+ """Should return an OutputFile with the output."""
+ raise NotImplementedError()
+
+
+class EpubBuilder(Builder):
+ file_extension = 'epub'
+
+ def __init__(self, *args, **kwargs):
+ self.chars = set()
+ self.fundr = 0
+ super().__init__(*args, **kwargs)
+
+ def build(self, document, **kwargs):
+ # replace_characters -- nie, robimy to na poziomie elementów
+
+ # hyphenator (\00ad w odp. miejscach) -- jeśli już, to też powinno to się dziać na poziomie elementów
+ # spójniki (\u00a0 po)-- jeśli już, to na poziomie elementów
+ # trick na dywizy: ­⁠-
+
+ # do toc trafia:
+ # początek z KAŻDEGO PLIKU xml
+
+ # zliczamy zbiór użytych znaków
+
+ # flagi:
+ # mieliśmy taką flagę less-advertising, używaną tylko dla Prestigio; już nie używamy.
+
+ # @editors = document.editors() (jako str)
+ # @funders = join(meta.funders)
+ # @thanks = meta.thanks
+
+
+ self.output = output = epub.EpubBook()
+ self.document = document
+
+ self.set_metadata()
+
+
+ self.add_cover()
+
+ self.add_title_page()
+ self.add_toc()
+
+
+
+ self.start_chunk()
+
+ self.add_toc_entry(
+ None,
+ 'Początek utworu', # i18n
+ 0
+ )
+ self.output.guide.append({
+ "type": "text",
+ "title": "Początek",
+ "href": "part1.xhtml"
+ })
+
+
+ self.build_document(self.document)
+
+
+ self.close_chunk()
+
+ self.add_annotations()
+ self.add_support_page()
+ self.add_last_page()
+
+
+ e = len(self.output.spine) - 3 - 3
+ nfunds = len(FUNDRAISING)
+ if e > 16:
+ nfunds *= 2
+
+ # COUNTING CHARACTERS?
+ for f in range(nfunds):
+ spine_index = int(4 + (f / nfunds * e) + f)
+
+ h = Xhtml()
+ h.body.append(
+ etree.XML('<div id="book-text"><div class="fundraising">' + FUNDRAISING[f % len(FUNDRAISING)] + '</div></div>')
+ )
+ self.add_html(h.element, file_name='fund%d.xhtml' % f, spine=spine_index)
+
+ self.add_fonts()
+
+ output_file = tempfile.NamedTemporaryFile(
+ prefix='librarian', suffix='.epub',
+ delete=False)
+ output_file.close()
+ epub.write_epub(output_file.name, output, {'epub3_landmark': False})
+ return OutputFile.from_filename(output_file.name)
+
+ def build_document(self, document):
+ self.toc_precedences = []
+
+ self.start_chunk()
+
+
+ document.tree.getroot().epub_build(self)
+ if document.meta.parts:
+ self.start_chunk()
+
+ self.start_element('div', {'class': 'title-page'})
+ self.start_element('h1', {'class': 'title'})
+ self.push_text(document.meta.title)
+ self.end_element()
+ self.end_element()
+
+ ######
+ # 160
+ # translators
+ # working copy?
+ # ta lektura
+ # tanks
+ # utwor opracowany
+ # isbn
+ # logo
+
+ for child in document.children:
+ self.start_chunk()
+ self.add_toc_entry(None, child.meta.title, 0)
+ self.build_document(child)
+
+ self.shift_toc_base()
+
+
+ def add_title_page(self):
+ html = Xhtml()
+ html.title.text = "Strona tytułowa"
+ bt = etree.SubElement(html.body, 'div', **{'class': 'book-text'})
+ tp = etree.SubElement(bt, 'div', **{'class': 'title-page'})
+
+ # Tak jak jest teraz – czy może być jednocześnie
+ # no „autor_utworu”
+ # i „dzieło nadrzędne”
+ # wcześniej mogło być dzieło nadrzędne,
+
+ e = self.document.tree.find('//autor_utworu')
+ if e is not None:
+ etree.SubElement(tp, 'h2', **{'class': 'author'}).text = e.raw_printable_text()
+ e = self.document.tree.find('//nazwa_utworu')
+ if e is not None:
+ etree.SubElement(tp, 'h1', **{'class': 'title'}).text = e.raw_printable_text()
+
+ if not len(tp):
+ for author in self.document.meta.authors:
+ etree.SubElement(tp, 'h2', **{'class': 'author'}).text = author.readable()
+ etree.SubElement(tp, 'h1', **{'class': 'title'}).text = self.document.meta.title
+
+# <xsl:apply-templates select="//nazwa_utworu | //podtytul | //dzielo_nadrzedne" mode="poczatek"/>
+# else:
+# <xsl:apply-templates select="//dc:creator" mode="poczatek"/>
+# <xsl:apply-templates select="//dc:title | //podtytul | //dzielo_nadrzedne" mode="poczatek"/>
+
+ etree.SubElement(tp, 'p', **{"class": "info"}).text = '\u00a0'
+
+ if self.document.meta.translators:
+ p = etree.SubElement(tp, 'p', **{'class': 'info'})
+ p.text = 'tłum. ' + ', '.join(t.readable() for t in self.document.meta.translators)
+
+ #<p class="info">[Kopia robocza]</p>
+
+ p = etree.XML("""<p class="info">
+ <a>Ta lektura</a>, podobnie jak tysiące innych, jest dostępna on-line na stronie
+ <a href="http://www.wolnelektury.pl/">wolnelektury.pl</a>.
+ </p>""")
+ p[0].attrib['href'] = str(self.document.meta.url)
+ tp.append(p)
+
+ if self.document.meta.thanks:
+ etree.SubElement(tp, 'p', **{'class': 'info'}).text = self.document.meta.thanks
+
+ tp.append(etree.XML("""
+ <p class="info">
+ Utwór opracowany został w ramach projektu<a href="http://www.wolnelektury.pl/"> Wolne Lektury</a> przez<a href="http://www.nowoczesnapolska.org.pl/"> fundację Nowoczesna Polska</a>.
+ </p>
+ """))
+
+ if self.document.meta.isbn_epub:
+ etree.SubElement(tp, 'p', **{"class": "info"}).text = self.document.meta.isbn_epub
+
+ tp.append(etree.XML("""<p class="footer info">
+ <a href="http://www.wolnelektury.pl/"><img src="logo_wolnelektury.png" alt="WolneLektury.pl" /></a>
+ </p>"""))
+
+ self.add_html(
+ html.element,
+ file_name='title.xhtml',
+ spine=True,
+ toc='Strona tytułowa' # TODO: i18n
+ )
+
+ self.add_file(
+ get_resource('res/wl-logo-small.png'),
+ file_name='logo_wolnelektury.png',
+ media_type='image/png'
+ )
+
+ def set_metadata(self):
+ self.output.set_identifier(
+ str(self.document.meta.url))
+ self.output.set_language(
+ functions.lang_code_3to2(self.document.meta.language)
+ )
+ self.output.set_title(self.document.meta.title)
+
+ for i, author in enumerate(self.document.meta.authors):
+ self.output.add_author(
+ author.readable(),
+ file_as=six.text_type(author),
+ uid='creator{}'.format(i)
+ )
+ for translator in self.document.meta.translators:
+ self.output.add_author(
+ translator.readable(),
+ file_as=six.text_type(translator),
+ role='trl',
+ uid='translator{}'.format(i)
+ )
+ for publisher in self.document.meta.publisher:
+ self.output.add_metadata("DC", "publisher", publisher)
+
+ self.output.add_metadata("DC", "date", self.document.meta.created_at)
+
+
+
+
+ def add_toc(self):
+ item = epub.EpubNav()
+ self.output.add_item(item)
+ self.output.spine.append(item)
+ self.output.add_item(epub.EpubNcx())
+
+ self.output.toc.append(
+ epub.Link(
+ "nav.xhtml",
+ "Spis treści",
+ "nav"
+ )
+ )
+
+
+
+ def add_support_page(self):
+ self.add_file(
+ get_resource('epub/support.xhtml'),
+ spine=True,
+ toc='Wesprzyj Wolne Lektury'
+ )
+
+ self.add_file(
+ get_resource('res/jedenprocent.png'),
+ media_type='image/png'
+ )
+ self.add_file(
+ get_resource('epub/style.css'),
+ media_type='text/css'
+ )
+
+
+ def add_file(self, path=None, content=None,
+ media_type='application/xhtml+xml',
+ file_name=None, uid=None,
+ spine=False, toc=None):
+
+ # update chars?
+ # jakieś tam ścieśnianie białych znaków?
+
+ if content is None:
+ with open(path, 'rb') as f:
+ content = f.read()
+ if file_name is None:
+ file_name = path.rsplit('/', 1)[-1]
+
+ if uid is None:
+ uid = file_name.split('.', 1)[0]
+
+ item = epub.EpubItem(
+ uid=uid,
+ file_name=file_name,
+ media_type=media_type,
+ content=content
+ )
+
+ self.output.add_item(item)
+ if spine:
+ if spine is True:
+ self.output.spine.append(item)
+ else:
+ self.output.spine.insert(spine, item)
+
+ if toc:
+ self.output.toc.append(
+ epub.Link(
+ file_name,
+ toc,
+ uid
+ )
+ )
+
+ def add_html(self, html_tree, **kwargs):
+ html = etree.tostring(
+ html_tree, pretty_print=True, xml_declaration=True,
+ encoding="utf-8",
+ doctype='<!DOCTYPE html>'
+ )
+
+ html = librarian.epub.squeeze_whitespace(html)
+
+ self.add_file(
+ content=html,
+ **kwargs
+ )
+
+
+ def add_fonts(self):
+ print("".join(sorted(self.chars)))
+ # TODO: optimizer
+ for fname in ('DejaVuSerif.ttf', 'DejaVuSerif-Bold.ttf',
+ 'DejaVuSerif-Italic.ttf', 'DejaVuSerif-BoldItalic.ttf'):
+ self.add_file(
+ content=strip_font(
+ get_resource('fonts/' + fname),
+ self.chars
+ ),
+ file_name=fname,
+ media_type='font/ttf'
+ )
+
+ def start_chunk(self):
+ if getattr(self, 'current_chunk', None) is not None:
+ if not len(self.current_chunk):
+ return
+ self.close_chunk()
+ self.current_chunk = etree.Element(
+ 'div',
+ id="book-text"
+ )
+ self.cursors[None] = self.current_chunk
+ self.current_cursors.append(self.current_chunk)
+
+ self.section_number = 0
+
+
+ def close_chunk(self):
+ assert self.cursor is self.current_chunk
+ ###### -- what if we're inside?
+
+ chunk_no = getattr(
+ self,
+ 'chunk_counter',
+ 1
+ )
+ self.chunk_counter = chunk_no + 1
+
+ html = Xhtml()
+ html.body.append(self.current_chunk)
+
+ self.add_html(
+ ## html container from template.
+ #self.current_chunk,
+ html.element,
+ file_name='part%d.xhtml' % chunk_no,
+ spine=True,
+
+ )
+ self.current_chunk = None
+ self.current_cursors.pop()
+
+ def start_element(self, tag, attr):
+ self.current_cursors.append(
+ etree.SubElement(self.cursor, tag, **attr)
+ )
+
+ def end_element(self):
+ self.current_cursors.pop()
+
+ def push_text(self, text):
+ self.chars.update(text)
+ if len(self.cursor):
+ self.cursor[-1].tail = (self.cursor[-1].tail or '') + text
+ else:
+ self.cursor.text = (self.cursor.text or '') + text
+
+
+ def assign_image_number(self):
+ image_number = getattr(self, 'image_number', 0)
+ self.image_number = image_number + 1
+ return image_number
+
+ def assign_footnote_number(self):
+ number = getattr(self, 'footnote_number', 1)
+ self.footnote_number = number + 1
+ return number
+
+ def assign_section_number(self):
+ number = getattr(self, 'section_number', 1)
+ self.section_number = number + 1
+ return number
+
+ def assign_mathml_number(self):
+ number = getattr(self, 'mathml_number', 0)
+ self.mathml_number = number + 1
+ return number
+
+
+ def add_toc_entry(self, fragment, name, precedence):
+ if precedence:
+ while self.toc_precedences and self.toc_precedences[-1] >= precedence:
+ self.toc_precedences.pop()
+ else:
+ self.toc_precedences = []
+
+ real_level = self.toc_base + len(self.toc_precedences)
+ if precedence:
+ self.toc_precedences.append(precedence)
+ else:
+ self.toc_base += 1
+
+ part_number = getattr(
+ self,
+ 'chunk_counter',
+ 1
+ )
+ filename = 'part%d.xhtml' % part_number
+ uid = filename.split('.')[0]
+ if fragment:
+ filename += '#' + fragment
+ uid += '-' + fragment
+
+ toc = self.output.toc
+ for l in range(1, real_level):
+ if isinstance(toc[-1], epub.Link):
+ toc[-1] = [toc[-1], []]
+ toc = toc[-1][1]
+
+ toc.append(
+ epub.Link(
+ filename,
+ name,
+ uid
+ )
+ )
+
+ def shift_toc_base(self):
+ self.toc_base -= 1
+
+
+ def add_last_page(self):
+ html = Xhtml()
+ m = self.document.meta
+
+ html.title.text = 'Strona redakcyjna'
+ d = etree.SubElement(html.body, 'div', id='book-text')
+
+ newp = lambda: etree.SubElement(d, 'p', {'class': 'info'})
+
+ p = newp()
+ if m.license:
+ p.text = """
+ Ten utwór jest udostępniony na licencji
+ """
+ etree.SubElement(p, 'a', href=m.license).text = m.license_description
+ else:
+ p.text = """
+ Ten utwór nie jest objęty majątkowym prawem autorskim i znajduje się w domenie
+ publicznej, co oznacza że możesz go swobodnie wykorzystywać, publikować
+ i rozpowszechniać. Jeśli utwór opatrzony jest dodatkowymi materiałami
+ (przypisy, motywy literackie etc.), które podlegają prawu autorskiemu, to
+ te dodatkowe materiały udostępnione są na licencji
+ """
+ a = etree.SubElement(p, "a", href="http://creativecommons.org/licenses/by-sa/3.0/")
+ a.text = """Creative Commons
+ Uznanie Autorstwa – Na Tych Samych Warunkach 3.0 PL"""
+ a.tail = "."
+
+
+ p = newp()
+ p.text = 'Źródło: '
+ etree.SubElement(
+ p, 'a', href=str(m.url),
+ title=', '.join((
+ ', '.join(p.readable() for p in m.authors),
+ m.title
+ ))
+ ).text = str(m.url)
+
+ newp().text = 'Tekst opracowany na podstawie: ' + m.source_name
+
+ newp().text = """
+ Wydawca:
+ """ + ", ".join(p for p in m.publisher)
+
+ if m.description:
+ newp().text = m.description
+
+
+ if m.editors:
+ newp().text = 'Opracowanie redakcyjne i przypisy: %s.' % (
+ ', '.join(e.readable() for e in sorted(self.document.editors())))
+
+ if m.funders:
+ etree.SubElement(d, 'p', {'class': 'minor-info'}).text = '''Publikację wsparli i wsparły:
+ %s.''' % (', '.join(m.funders))
+
+ if m.cover_by:
+ p = newp()
+ p.text = 'Okładka na podstawie: '
+ if m.cover_source:
+ etree.SubElement(
+ p,
+ 'a',
+ href=m.cover_source
+ ).text = m.cover_by
+ else:
+ p.text += m.cover_by
+
+ if m.isbn_epub:
+ newp().text = m.isbn_epub
+
+ newp().text = '\u00a0'
+
+ p = newp()
+ p.attrib['class'] = 'minor-info'
+ p.text = '''
+ Plik wygenerowany dnia '''
+ span = etree.SubElement(p, 'span', id='file_date')
+ span.text = str(date.today())
+ span.tail = '''.
+ '''
+
+ self.add_html(
+ html.element,
+ file_name='last.xhtml',
+ toc='Strona redakcyjna',
+ spine=True
+ )
+
+
+ def add_annotations(self):
+ if not len(self.footnotes):
+ return
+
+ html = Xhtml()
+ html.title.text = 'Przypisy'
+ d = etree.SubElement(
+ etree.SubElement(
+ html.body,
+ 'div',
+ id='book-text'
+ ),
+ 'div',
+ id='footnotes'
+ )
+
+ etree.SubElement(
+ d,
+ 'h2',
+ ).text = 'Przypisy:'
+
+ d.extend(self.footnotes)
+
+ self.add_html(
+ html.element,
+ file_name='annotations.xhtml',
+ spine=True,
+ toc='Przypisy'
+ )
+
+ def add_cover(self):
+ # TODO: allow other covers
+
+ cover_maker = make_cover
+
+ cover_file = six.BytesIO()
+ cover = cover_maker(self.document.meta)
+ cover.save(cover_file)
+ cover_name = 'cover.%s' % cover.ext()
+
+ self.output.set_cover(
+ file_name=cover_name,
+ content=cover_file.getvalue(),
+ create_page = False
+ )
+ ci = ('''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" lang="en" xml:lang="en">
+ <head>
+ <title>Okładka</title>
+ <style>
+ body { margin: 0em; padding: 0em; }
+ img { width: 100%%; }
+ </style>
+ </head>
+ <body>
+ <img src="cover.%s" alt="Okładka" />
+ </body>
+</html>''' % cover.ext()).encode('utf-8')
+ self.add_file(file_name='cover.xhtml', content=ci)
+
+ self.output.spine.append('cover')
+ self.output.guide.append({
+ 'type': 'cover',
+ 'href': 'cover.xhtml',
+ 'title': 'Okładka'
+ })
+
+ def mathml(self, element):
+ name = "math%d.png" % self.assign_mathml_number()
+ self.add_file(
+ content=MathML(element).to_latex().to_png().data,
+ media_type='image/png',
+ file_name=name
+ )
+ return name
--- /dev/null
+from librarian import OutputFile
+
+
+class PdfBuilder:
+ # Obowiązkowe
+ file_extension = 'pdf'
+ def build(self, document, mp3):
+ # stub
+ return OutputFile.from_bytes(b'')
+
+
+
default_license_description = {
"pol": (
- "Ten utwór nie jest objęty majątkowym prawem autorskim "
- "i znajduje się w domenie publicznej, co oznacza że "
- "możesz go swobodnie wykorzystywać, publikować "
- "i rozpowszechniać. Jeśli utwór opatrzony jest "
- "dodatkowymi materiałami (przypisy, motywy literackie "
- "etc.), które podlegają prawu autorskiemu, to te "
- "dodatkowe materiały udostępnione są na licencji "
- "Creative Commons Uznanie Autorstwa – Na Tych Samych "
- "Warunkach 3.0 PL "
- "(http://creativecommons.org/licenses/by-sa/3.0/)"
+ "Wszystkie zasoby Wolnych Lektur możesz swobodnie wykorzystywać, "
+ "publikować i rozpowszechniać pod warunkiem zachowania warunków "
+ "licencji i zgodnie z Zasadami wykorzystania Wolnych Lektur.\n"
+ "Ten utwór jest w domenie publicznej. "
+ "Wszystkie materiały dodatkowe (przypisy, motywy literackie) są "
+ "udostępnione na Licencji Wolnej Sztuki 1.3 "
+ "(https://artlibre.org/licence/lal/pl/).\n"
+ "Fundacja Nowoczesna Polska zastrzega sobie prawa do wydania "
+ "krytycznego zgodnie z art. Art.99(2) Ustawy o prawach autorskich "
+ "i prawach pokrewnych. Wykorzystując zasoby z Wolnych Lektur, "
+ "należy pamiętać o zapisach licencji oraz zasadach, które "
+ "spisaliśmy w Zasadach wykorzystania Wolnych Lektur "
+ "(https://wolnelektury.pl/info/zasady-wykorzystania/). Zapoznaj "
+ "się z nimi, zanim udostępnisz dalej nasze książki."
)
}
license_description = {
- "pol": "Ten utwór jest udostępniony na licencji {meta.license_description}: \n{meta.license}",
+ "pol": (
+ #"Ten utwór jest udostępniony na licencji {meta.license_description}: \n{meta.license}",
+ "Wszystkie zasoby Wolnych Lektur możesz swobodnie wykorzystywać, "
+ "publikować i rozpowszechniać pod warunkiem zachowania warunków "
+ "licencji i zgodnie z Zasadami wykorzystania Wolnych Lektur.\n"
+ "Ten utwór jest jest udostępniony na licencji {meta.license_description} ({meta.license}). "
+ "Wszystkie materiały dodatkowe (przypisy, motywy literackie) są "
+ "udostępnione na Licencji Wolnej Sztuki 1.3 "
+ "(https://artlibre.org/licence/lal/pl/).\n"
+ "Fundacja Nowoczesna Polska zastrzega sobie prawa do wydania "
+ "krytycznego zgodnie z art. Art.99(2) Ustawy o prawach autorskich "
+ "i prawach pokrewnych. Wykorzystując zasoby z Wolnych Lektur, "
+ "należy pamiętać o zapisach licencji oraz zasadach, które "
+ "spisaliśmy w Zasadach wykorzystania Wolnych Lektur "
+ "(https://wolnelektury.pl/info/zasady-wykorzystania/). Zapoznaj "
+ "się z nimi, zanim udostępnisz dalej nasze książki."
+ )
}
def __init__(self):
box_img = box.image()
# Find box position.
- if self.box_position == 'top':
- box_top = metr.box_top_margin
- elif self.box_position == 'bottom':
+ if self.box_position == 'bottom' or box_img.size[1] + metr.box_top_margin + metr.box_bottom_margin > metr.height:
box_top = metr.height - metr.box_bottom_margin - box_img.size[1]
+ elif self.box_position == 'top':
+ box_top = metr.box_top_margin
else: # Middle.
box_top = (metr.height - box_img.size[1]) // 2
class LogoWLCover(WLCover):
gradient_height = 90
gradient_logo_height = 60
+ gradient_logo_max_width = 1000
gradient_logo_margin_right = 30
gradient_logo_spacing = 40
gradient_color = '#000'
'res/wl-logo-white.png',
'res/fnp-logo-white.png',
]
+ annotation = None
+ annotation_height = 10
def __init__(self, book_info, *args, **kwargs):
super(LogoWLCover, self).__init__(book_info, *args, **kwargs)
- 2 * metr.gradient_logo_margin_right
)
widths = [
- logo.size[0] * metr.gradient_logo_height / logo.size[1]
+ min(
+ metr.gradient_logo_max_width,
+ logo.size[0] * metr.gradient_logo_height / logo.size[1]
+ )
for logo in logos]
taken_space = (
sum(widths)
logo = logo.resize(
(
int(round(widths[i] * logo_scale)),
- int(round(metr.gradient_logo_height * logo_scale))
+ int(round(
+ logo.size[1] * widths[i] / logo.size[0] * logo_scale
+ ))
),
Image.ANTIALIAS)
cursor -= logo.size[0]
- img.paste(logo, (cursor, logo_top), mask=logo)
+ img.paste(
+ logo,
+ (
+ cursor,
+ int(round(logo_top + (metr.gradient_logo_height - logo.size[1]) * logo_scale / 2))
+ ),
+ mask=logo
+ )
cursor -= int(round(metr.gradient_logo_spacing * logo_scale))
+ if self.annotation:
+ img2 = Image.new('RGBA', (metr.height, metr.height), color=None)
+ draw = ImageDraw.Draw(img2)
+ author_font = ImageFont.truetype(
+ self.author_font_ttf, metr.annotation_height,
+ layout_engine=ImageFont.LAYOUT_BASIC)
+ draw.text((self.annotation_height, self.annotation_height), self.annotation, font=author_font, fill='#FFFFFF')
+ img2.show()
+ img2 = img2.rotate(90)
+ img2.show()
+ img.putalpha(0)
+ img.alpha_composite(img2, (0, 0))
+ img = img.convert('RGB')
+
return img
]
+class BNCover(LogoWLCover):
+ gradient_logos = [
+ 'res/dofinansowano.png',
+ 'res/MKIDN.jpg',
+ 'res/BN.png',
+ 'res/wl-logo-white.png',
+ ]
+# annotation = 'Zadanie „Udostępnienie publikacji w formatach cyfrowych” w ramach Narodowego Programu Rozwoju Czytelnictwa. Dofinansowano ze środków Ministra Kultury, Dziedzictwa Narodowego i Sportu.'
+
+
COVER_CLASSES = {
'default': LogoWLCover,
'kmlu': KMLUCover,
'mpw': MPWCover,
'atrium': AtriumCover,
+ 'bn': BNCover,
}
from lxml import etree
import six
from .parser import parser
-from . import dcparser, DCNS
+from . import dcparser, DCNS, DirDocProvider
from .functions import lang_code_3to2
class WLDocument:
- def __init__(self, filename=None, url=None):
+ def __init__(self, filename=None, url=None, provider=None):
source = filename or six.moves.urllib.request.urlopen(url)
tree = etree.parse(source, parser=parser)
self.tree = tree
DCNS('language'): ["pol"],
}, validate_required=False)
+ self.provider = provider if provider is not None else DirDocProvider('.')
+
@property
def meta(self):
# Allow metadata of the master element as document meta.
return self.tree.getroot().meta
return master.meta
+ @property
+ def children(self):
+ for part_uri in self.meta.parts or []:
+ yield type(self)(
+ filename=self.provider.by_uri(part_uri),
+ provider=self.provider
+ )
+
+
def build(self, builder, **kwargs):
return builder().build(self, **kwargs)
_compat_assigns_section_ids_in_elem(child, idfier + '-')
_compat_assigns_section_ids_in_elem(self.tree.getroot().master)
+
+ def editors(self):
+ persons = set(self.meta.editors
+ + self.meta.technical_editors)
+ #for child in self.parts():
+ # persons.update(child.editors())
+ #if None in persons:
+ # persons.remove(None)
+ return persons
+
"naglowek_czesc": headers.NaglowekCzesc,
"naglowek_akt": headers.NaglowekCzesc,
- "naglowek_scena": headers.NaglowekRozdzial,
+ "naglowek_scena": headers.NaglowekScena,
"naglowek_rozdzial": headers.NaglowekRozdzial,
"naglowek_podrozdzial": headers.NaglowekPodrozdzial,
"srodtytul": headers.NaglowekCzesc,
import re
from lxml import etree
from librarian import dcparser, RDFNS
+from librarian.html import raw_printable_text
from librarian.util import get_translation
class WLElement(etree.ElementBase):
+ SECTION_PRECEDENCE = None
+
TXT_TOP_MARGIN = 0
TXT_BOTTOM_MARGIN = 0
TXT_PREFIX = ""
HTML_TAG = None
HTML_ATTR = {}
HTML_CLASS = None
-
+
+ EPUB_TAG = None
+ EPUB_ATTR = {}
+ EPUB_CLASS = None
+ EPUB_START_CHUNK = False
+
CAN_HAVE_TEXT = True
STRIP = False
text_substitutions = [
(u'---', u'—'),
(u'--', u'–'),
- (u'...', u'…'),
+ #(u'...', u'…'), # Temporary turnoff for epub
(u',,', u'„'),
(u'"', u'”'),
('\ufeff', ''),
+
+ ("'", "\u2019"), # This was enabled for epub.
]
@property
def gettext(self):
return get_translation(self.meta.language).gettext
+ def raw_printable_text(self):
+ # TODO: podtagi, wyroznienia, etc
+ t = ''
+ t += self.normalize_text(self.text)
+ for c in self:
+ if c.tag not in ('pe', 'pa', 'pt', 'pr', 'motyw'):
+ t += c.raw_printable_text()
+ t += self.normalize_text(c.tail)
+ return t
+
def normalize_text(self, text):
text = text or ''
for e, s in self.text_substitutions:
text = text.replace(e, s)
- text = re.sub(r'\s+', ' ', text)
+ # FIXME: TEmporary turnoff
+# text = re.sub(r'\s+', ' ', text)
+### TODO: Added now for epub
+ text = re.sub(r'(?<=\s\w)\s+', u'\u00A0', text)
+
return text
def _build_inner(self, builder, build_method):
if self.HTML_TAG:
builder.end_element()
+ def _epub_build_inner(self, builder):
+ self._build_inner(builder, 'epub_build')
+
+ def get_epub_attr(self, builder):
+ attr = self.EPUB_ATTR.copy()
+ if self.EPUB_CLASS:
+ attr['class'] = self.EPUB_CLASS
+ return attr
+
+ def epub_build(self, builder):
+ # TEMPORARY
+ self.CAN_HAVE_TEXT = True
+ self.STRIP = False
+
+ if self.EPUB_START_CHUNK:
+ builder.start_chunk()
+
+ fragment = None
+ if self.SECTION_PRECEDENCE:
+ if not self.EPUB_START_CHUNK:
+ fragment = 'sub%d' % builder.assign_section_number()
+ self.attrib['id'] = fragment
+
+ builder.add_toc_entry(
+ fragment,
+ self.raw_printable_text(),
+ self.SECTION_PRECEDENCE
+ )
+
+ if self.EPUB_TAG:
+ attr = self.get_epub_attr(builder)
+ if fragment:
+ attr['id'] = fragment
+ builder.start_element(
+ self.EPUB_TAG,
+ attr
+ )
+
+ self._epub_build_inner(builder)
+ if self.EPUB_TAG:
+ builder.end_element()
+
def sanitize(self):
# TODO: Remove insanity here.
for e in self:
class Dedykacja(WLElement):
TXT_LEGACY_TOP_MARGIN = 2
- HTML_TAG = "div"
- HTML_CLASS = "dedication"
+ EPUB_TAG = HTML_TAG = "div"
+ EPUB_CLASS = HTML_CLASS = "dedication"
TXT_LEGACY_BOTTOM_MARGIN = 0
HTML_TAG = 'blockquote'
+
+ EPUB_TAG = 'div'
+ EPUB_CLASS = 'block'
class Nota(WLElement):
CAN_HAVE_TEXT = False
- HTML_TAG = "div"
- HTML_CLASS = "note"
+ EPUB_TAG = HTML_TAG = "div"
+ EPUB_CLASS = HTML_CLASS = "note"
TXT_LEGACY_BOTTOM_MARGIN = 0
HTML_TAG = 'blockquote'
+
+ EPUB_TAG = 'div'
+ EPUB_CLASS = 'block'
HTML_TAG = "div"
HTML_CLASS = "ramka"
+ EPUB_TAG = "div"
+ EPUB_CLASS = "frame"
def html_build(self, builder):
pass
+
+ def epub_build(self, builder):
+ pass
builder.enter_fragment('nota_red')
super(NotaRed, self).html_build(builder)
builder.exit_fragment()
+
+ def epub_build(self, builder):
+ pass
def html_build(self, builder):
pass
+
+ def epub_build(self, builder):
+ pass
TXT_PREFIX = "/ "
TXT_SUFFIX = " /"
- HTML_TAG = "em"
- HTML_CLASS = "didaskalia"
+ EPUB_TAG = HTML_TAG = "em"
+ EPUB_CLASS = HTML_CLASS = "didaskalia"
TXT_PREFIX = "/ "
TXT_SUFFIX = " /"
- HTML_TAG = "div"
- HTML_CLASS = "didaskalia"
+ EPUB_TAG =_HTML_TAG = "div"
+ EPUB_CLASS = HTML_CLASS = "didaskalia"
class Kwestia(WLElement):
CAN_HAVE_TEXT = False
- HTML_TAG = "div"
- HTML_CLASS = "kwestia"
+ EPUB_TAG = HTML_TAG = "div"
+ EPUB_CLASS = HTML_CLASS = "kwestia"
super(ListaOsob, self)._html_build_inner(builder)
builder.cursor.append(ol)
builder.forget_fragment('list')
+
+ def _epub_build_inner(self, builder):
+ ol = etree.Element('ol')
+ builder.create_fragment('list', ol)
+ super(ListaOsob, self)._epub_build_inner(builder)
+ builder.cursor.append(ol)
+ builder.forget_fragment('list')
TXT_LEGACY_BOTTOM_MARGIN = 0
TXT_PREFIX = " * "
- HTML_TAG = "li"
+ EPUB_TAG = HTML_TAG = "li"
def html_build(self, builder):
builder.enter_fragment('list')
super(ListaOsoba, self).html_build(builder)
builder.exit_fragment()
+ def epub_build(self, builder):
+ builder.enter_fragment('list')
+ super(ListaOsoba, self).epub_build(builder)
+ builder.exit_fragment()
class MiejsceCzas(Akap):
- HTML_CLASS = 'place-and-time'
+ EPUB_CLASS = HTML_CLASS = 'place-and-time'
+
+ EPUB_TAG = "div"
+
class NaglowekListy(WLElement):
HTML_TAG = "h3"
+
+ EPUB_TAG = "div"
+ EPUB_CLASS = "h3"
TXT_LEGACY_BOTTOM_MARGIN = 0
HTML_TAG = "h4"
+
+ EPUB_TAG = "h2"
+ EPUB_CLASS = "h4"
class Osoba(WLElement):
- HTML_TAG = "em"
- HTML_CLASS = "person"
+ EPUB_TAG = HTML_TAG = "em"
+ EPUB_CLASS = HTML_CLASS = "person"
+import six.moves
+from PIL import Image
from ..base import WLElement
class Ilustr(WLElement):
- HTML_TAG = 'img'
+ EPUB_TAG = HTML_TAG = 'img'
def get_html_attr(self, builder):
+ ## TODO: thumbnail.
+
+ url = six.moves.urllib.parse.urljoin(
+ builder.base_url,
+ self.get('src')
+ )
+
+ imgfile = six.moves.urllib.request.urlopen(url)
+ img = Image.open(imgfile)
+ th_format, ext, media_type = {
+ 'GIF': ('GIF', 'gif', 'image/gif'),
+ 'PNG': ('PNG', 'png', 'image/png'),
+ }.get(img.format, ('JPEG', 'jpg', 'image/jpeg'))
+
+ width = 1200
+ if img.size[0] < width:
+ th = img
+ else:
+ th = img.resize((width, round(width * img.size[1] / img.size[0])))
+
+ imgfile.close()
+ buffer = six.BytesIO()
+ th.save(buffer, format=th_format)
+ ## TODO: Counter
+ file_name = 'image%d.%s' % (
+ builder.assign_image_number(),
+ ext
+ )
+
+ builder.add_file(
+ content=buffer.getvalue(),
+ file_name=file_name,
+ media_type=media_type,
+ )
+
return {
- 'src': builder.base_url + self.attrib['src'],
+ 'src': file_name,
'alt': self.attrib['alt'],
'title': self.attrib['alt'],
}
+
+ get_epub_attr = get_html_attr
class Kol(WLElement):
- HTML_TAG = 'td'
+ EPUB_TAG = HTML_TAG = 'td'
class Tabela(WLElement):
- HTML_TAG = 'table'
+ EPUB_TAG = HTML_TAG = 'table'
def get_html_attr(self, builder):
if self.attrib.get('ramka', '') == '1':
'class': 'border'
}
return {}
+
+ get_epub_attr = get_html_attr
+
+
class Wiersz(WLElement):
- HTML_TAG = 'tr'
+ EPUB_TAG = HTML_TAG = 'tr'
builder.end_element()
builder.exit_fragment()
+ def epub_build(self, builder):
+ fn_no = builder.assign_footnote_number()
+ part_number = getattr(
+ builder,
+ 'chunk_counter',
+ 1
+ )
+
+ builder.start_element(
+ 'a',
+ {
+ 'class': 'anchor',
+ 'id': f'anchor-{fn_no}',
+ 'href': f'annotations.xhtml#annotation-{fn_no}',
+ }
+ )
+ builder.start_element('sup', {})
+ builder.push_text(str(fn_no))
+ builder.end_element()
+ builder.end_element()
+
+
+ builder.enter_fragment('footnotes')
+ builder.start_element('p', {
+ 'id': f'annotation-{fn_no}',
+ 'class': "annotation"
+ })
+ builder.start_element('a', {
+ 'href': f"part{part_number}.xhtml#anchor-{fn_no}"
+ })
+ builder.push_text(str(fn_no))
+ builder.end_element()
+ builder.push_text('. ')
+
+ super().epub_build(builder)
+ builder.push_text(' [' + self.qualifier + ']')
+ builder.end_element()
+
+ builder.push_text('\n')
+
+ builder.exit_fragment()
+
+
class PA(Footnote):
"""Przypis autorski."""
TXT_LEGACY_BOTTOM_MARGIN = 2
HTML_CLASS = 'author'
+
+ def epub_build(self, builder):
+ return
TXT_LEGACY_BOTTOM_MARGIN = 1
HTML_CLASS = "collection"
+
+ def epub_build(self, builder):
+ return
TXT_LEGACY_TOP_MARGIN = 4
TXT_LEGACY_BOTTOM_MARGIN = 2
- HTML_TAG = "div"
- HTML_CLASS = "motto"
+ EPUB_TAG = HTML_TAG = "div"
+ EPUB_CLASS = HTML_CLASS = "motto"
class MottoPodpis(WLElement):
HTML_TAG = "p"
- HTML_CLASS = "motto_podpis"
+ EPUB_CLASS = HTML_CLASS = "motto_podpis"
+ EPUB_TAG = "div"
+
TXT_LEGACY_BOTTOM_MARGIN = 1
HTML_CLASS = 'title'
+
+ EPUB_TAG = 'h2'
+ EPUB_CLASS = 'intitle'
TXT_LEGACY_BOTTOM_MARGIN = 1
HTML_CLASS = 'subtitle'
+
+ EPUB_TAG = 'h2'
+ EPUB_CLASS = 'insubtitle'
+
from .naglowek_czesc import NaglowekCzesc
from .naglowek_podrozdzial import NaglowekPodrozdzial
from .naglowek_rozdzial import NaglowekRozdzial
+from .naglowek_scena import NaglowekScena
from .podtytul_czesc import PodtytulCzesc
from .podtytul_rozdzial import PodtytulRozdzial
from .podtytul_podrozdzial import PodtytulPodrozdzial
+
+
class NaglowekCzesc(WLElement):
+ SECTION_PRECEDENCE = 1
+
TXT_TOP_MARGIN = 5
TXT_BOTTOM_MARGIN = 2
TXT_LEGACY_TOP_MARGIN = 5
TXT_LEGACY_BOTTOM_MARGIN = 0
- HTML_TAG = "h2"
+ EPUB_TAG = HTML_TAG = "h2"
+
+ EPUB_CLASS = "h2"
+ EPUB_START_CHUNK = True
class NaglowekRozdzial(WLElement):
+ SECTION_PRECEDENCE = 2
+
TXT_TOP_MARGIN = 4
TXT_BOTTOM_MARGIN = 2
TXT_LEGACY_TOP_MARGIN = 4
TXT_LEGACY_BOTTOM_MARGIN = 0
HTML_TAG = 'h3'
+
+ EPUB_TAG = 'h2'
+ EPUB_CLASS = 'h3'
+ EPUB_START_CHUNK = True
--- /dev/null
+from ..base import WLElement
+
+
+class NaglowekScena(WLElement):
+ SECTION_PRECEDENCE = 2
+
+ TXT_TOP_MARGIN = 4
+ TXT_BOTTOM_MARGIN = 2
+ TXT_LEGACY_TOP_MARGIN = 4
+ TXT_LEGACY_BOTTOM_MARGIN = 0
+
+ HTML_TAG = 'h3'
+
+ EPUB_TAG = 'h2'
+ EPUB_CLASS = 'h3'
+ EPUB_START_CHUNK = False
+
HTML_TAG = "div"
HTML_CLASS = "subtitle2"
+
+ EPUB_TAG = "h2"
+ EPUB_CLASS = "h2"
+
+ def _epub_build_inner(self, builder):
+ builder.start_element('small', {})
+ super()._epub_build_inner(builder)
+ builder.end_element()
HTML_TAG = "div"
HTML_CLASS = "subtitle4"
+
+ EPUB_TAG = "h2"
+ EPUB_CLASS = "h4"
+
+ def _epub_build_inner(self, builder):
+ builder.start_element('small', {})
+ super()._epub_build_inner(builder)
+ builder.end_element()
HTML_TAG = "div"
HTML_CLASS = "subtitle3"
+
+ EPUB_TAG = "h2"
+ EPUB_CLASS = "h3"
+
+ def _epub_build_inner(self, builder):
+ builder.start_element('small', {})
+ super()._epub_build_inner(builder)
+ builder.end_element()
TXT_LEGACY_TOP_MARGIN = 2
TXT_LEGACY_BOTTOM_MARGIN = 0
- HTML_TAG = 'p'
- HTML_CLASS = 'paragraph'
+ EPUB_TAG = HTML_TAG = 'p'
+ EPUB_CLASS = HTML_CLASS = 'paragraph'
from copy import copy
+import re
from ..base import WLElement
from .wers import Wers
TXT_LEGACY_TOP_MARGIN = 1
TXT_LEGACY_BOTTOM_MARGIN = 0
- HTML_TAG = 'div'
- HTML_CLASS = 'stanza'
+ EPUB_TAG = HTML_TAG = 'div'
+ EPUB_CLASS = HTML_CLASS = 'stanza'
+
+ def epub_build(self, builder):
+ super().epub_build(builder)
+ builder.start_element(
+ 'div',
+ {
+ 'class': 'stanza-spacer'
+ }
+ )
+ builder.push_text('\u00a0');
+ builder.end_element()
def get_verses(self):
from librarian.parser import parser
]
if self.text:
# Before any tags. These are text-only verses.
- pieces = self.text.split('/')
+ pieces = re.split(r"/\s+", self.text)
for piece in pieces[:-1]:
verses[-1].text = piece
verses.append(parser.makeelement('wers'))
for child in self:
if child.tail:
- pieces = child.tail.split('/')
+ pieces = re.split(r"/\s+", child.tail)
child_copy = copy(child)
child_copy.tail = pieces[0]
verses[-1].append(child_copy)
TXT_LEGACY_TOP_MARGIN = 1
TXT_LEGACY_BOTTOM_MARGIN = 0
- HTML_TAG = 'div'
- HTML_CLASS = 'verse'
+ EPUB_TAG = HTML_TAG = 'div'
+ EPUB_CLASS = HTML_CLASS = 'verse'
@property
def meta(self):
if hasattr(self, 'stanza'):
return self.stanza.meta
return super(Wers, self).meta
+
+ def _epub_build_inner(self, builder):
+ super()._epub_build_inner(builder)
+ builder.push_text('''\u00a0''')
+
HTML_ATTR = {
"style": "padding-left: 1em"
}
+
+ EPUB_ATTR = {
+ "style": "margin-left: 1em"
+ }
HTML_ATTR = {
"style": "padding-left: 12em",
}
+
+ EPUB_ATTR = {
+ "style": "margin-left: 12em",
+ }
class WersDoPrawej(Wers):
TXT_PREFIX = ' '
- HTML_ATTR = {
+ EPUB_ATTR = HTML_ATTR = {
"style": "text-align: right",
}
attr = super(WersWciety, self).get_html_attr(builder)
attr['style'] = "padding-left: {}em".format(self.typ)
return attr
+
+ def get_epub_attr(self, builder):
+ attr = super(WersWciety, self).get_html_attr(builder)
+ attr['style'] = "margin-left: {}em".format(self.typ)
+ return attr
TXT_LEGACY_TOP_MARGIN = 2
TXT_LEGACY_BOTTOM_MARGIN = 2
- HTML_TAG = "p"
- HTML_CLASS = "spacer-asterisk"
+ EPUB_TAG = HTML_TAG = "p"
+ HTML_CLASS = HTML_CLASS = "spacer-asterisk"
def _txt_build_inner(self, builder):
builder.push_text('*')
def _html_build_inner(self, builder):
builder.push_text("*")
+ _epub_build_inner = _html_build_inner
+
HTML_TAG = "hr"
HTML_CLASS = "spacer"
+
+ EPUB_TAG = 'p'
+ EPUB_CLASS = 'spacer'
+
+ def _epub_build_inner(self, builder):
+ builder.push_text("\u00a0")
TXT_LEGACY_TOP_MARGIN = 2
TXT_LEGACY_BOTTOM_MARGIN = 2
- HTML_TAG = "hr"
- HTML_CLASS = "spacer-line"
+ EPUB_TAG = HTML_TAG = "hr"
+ EPUB_CLASS = HTML_CLASS = "spacer-line"
def _txt_build_inner(self, builder):
builder.push_text('-' * 48)
class IndeksDolny(WLElement):
TXT_PREFIX = "_"
- HTML_TAG = "sub"
+ EPUB_TAG = HTML_TAG = "sub"
e.tag = 'math'
e.attrib['xmlns'] = 'http://www.w3.org/1998/Math/MathML'
builder.cursor.append(e)
+
+ def epub_build(self, builder):
+ builder.start_element('img', {"src": builder.mathml(self)})
+ builder.end_element()
class SlowoObce(WLElement):
- HTML_TAG = 'em'
- HTML_CLASS = 'foreign-word'
+ EPUB_TAG = HTML_TAG = 'em'
+ EPUB_CLASS = HTML_CLASS = 'foreign-word'
class TytulDziela(WLElement):
- HTML_TAG = 'em'
- HTML_CLASS = 'book-title'
+ EPUB_TAG = HTML_TAG = 'em'
+ EPUB_CLASS = HTML_CLASS = 'book-title'
def normalize_text(self, text):
txt = super(TytulDziela, self).normalize_text(text)
TXT_PREFIX = "*"
TXT_SUFFIX = "*"
- HTML_TAG = "em"
- HTML_CLASS = "wieksze-odstepy"
+ EPUB_TAG = HTML_TAG = "em"
+ EPUB_CLASS = HTML_CLASS = "wieksze-odstepy"
TXT_PREFIX = "*"
TXT_SUFFIX = "*"
- HTML_TAG = "em"
- HTML_CLASS = "author-emphasis"
+ EPUB_TAG = HTML_TAG = "em"
+ EPUB_CLASS = HTML_CLASS = "author-emphasis"
"fid": fid,
"name": "m" + fid,
}
+
+ def epub_build(self, builder):
+ pass
def squeeze_whitespace(s):
+ return s
return re.sub(b'\\s+', b' ', s)
parent.tail = newt
-def inner_xml(node):
- """ returns node's text and children as a string
-
- >>> print(inner_xml(etree.fromstring('<a>x<b>y</b>z</a>')))
- x<b>y</b>z
- """
-
- nt = node.text if node.text is not None else ''
- return ''.join(
- [nt] + [etree.tostring(child, encoding='unicode') for child in node]
- )
-
-
-def set_inner_xml(node, text):
- """ sets node's text and children from a string
-
- >>> e = etree.fromstring('<a>b<b>x</b>x</a>')
- >>> set_inner_xml(e, 'x<b>y</b>z')
- >>> print(etree.tostring(e, encoding='unicode'))
- <a>x<b>y</b>z</a>
- """
-
- p = etree.fromstring('<x>%s</x>' % text)
- node.text = p.text
- node[:] = p[:]
-
-
def node_name(node):
""" Find out a node's name
toc[i] = e[0]
-def transform(wldoc, verbose=False, style=None,
- sample=None, cover=None, flags=None, hyphenate=False,
- base_url='file://./', output_type='epub'):
- """ produces a EPUB file
-
- sample=n: generate sample e-book (with at least n paragraphs)
- cover: a cover.Cover factory or True for default
- flags: less-advertising, without-fonts, working-copy
- """
- def transform_file(wldoc, chunk_counter=1, first=True, sample=None):
+def transform_file(wldoc, chunk_counter=1, first=True, sample=None, hyphenate=False, output_type='epub', spine=None, output=None, annotations=None):
""" processes one input file and proceeds to its children """
replace_characters(wldoc.edoc.getroot())
for child in wldoc.parts():
child_toc, chunk_counter, chunk_chars, sample = transform_file(
- child, chunk_counter, first=False, sample=sample)
+ child, chunk_counter, first=False, sample=sample,
+ hyphenate=hyphenate, output_type=output_type,
+ spine=spine, output=output, annotations=annotations,
+ )
toc[-1][1].extend(child_toc)
chars = chars.union(chunk_chars)
return toc, chunk_counter, chars, sample
+
+def transform(wldoc, verbose=False, style=None,
+ sample=None, cover=None, flags=None, hyphenate=False,
+ base_url='file://./', output_type='epub'):
+ """ produces a EPUB file
+
+ sample=n: generate sample e-book (with at least n paragraphs)
+ cover: a cover.Cover factory or True for default
+ flags: less-advertising, without-fonts, working-copy
+ """
+
+
document = deepcopy(wldoc)
del wldoc
base_url,
ilustr.get('src')
)
- with six.moves.urllib.request.urlopen(url) as imgfile:
- img = Image.open(imgfile)
+ imgfile = six.moves.urllib.request.urlopen(url)
+ img = Image.open(imgfile)
th_format, ext, media_type = {
'GIF': ('GIF', 'gif', 'image/gif'),
else:
th = img.resize((width, round(width * img.size[1] / img.size[0])))
+ imgfile.close()
+
buffer = six.BytesIO()
th.save(buffer, format=th_format)
annotations = etree.Element('annotations')
- toc, chunk_counter, chars, sample = transform_file(document, sample=sample)
+ toc, chunk_counter, chars, sample = transform_file(
+ document, sample=sample,
+ hyphenate=hyphenate, output_type=output_type,
+ spine=spine, output=output, annotations=annotations
+ )
output.toc = toc[0][1]
# Last modifications in container files and EPUB creation
os.chdir(cwd)
remove_empty_lists_from_toc(output.toc)
+ print(output.toc)
output_file = NamedTemporaryFile(prefix='librarian', suffix='.epub',
delete=False)
th, td {
vertical-align: top;
-}
\ No newline at end of file
+}
+
+.fundraising {
+ margin: 2em 1em 0;
+ border: 2px solid black;
+ padding: 2em 2em;
+ text-align: center;
+ font-size: 1.3em;
+ line-height: 1.4em;
+}
<div id="book-text" xmlns="http://www.w3.org/1999/xhtml">
<div id="footnotes" xmlns="http://www.w3.org/1999/xhtml">
<h2 xmlns="http://www.w3.org/1999/xhtml">
- Przypisy:
+ <xsl:text>Przypisy:</xsl:text>
</h2>
<xsl:apply-templates mode="przypis" />
</div>
</xsl:template>
<xsl:template match="pa|pe|pr|pt" mode="przypis">
- <p id="annotation-{@number}" class="annotation" xmlns="http://www.w3.org/1999/xhtml"><a href="part{@part}.xhtml#anchor-{@number}" xmlns="http://www.w3.org/1999/xhtml"><xsl:value-of select="@number" /></a>. <xsl:apply-templates /><xsl:if test="name()='pa'"> [przypis autorski]</xsl:if><xsl:if test="name()='pt'"> [przypis tłumacza]</xsl:if><xsl:if test="name()='pr'"> [przypis redakcyjny]</xsl:if><xsl:if test="name()='pe'"> [przypis edytorski]</xsl:if></p>
+ <p class="annotation" id="annotation-{@number}" xmlns="http://www.w3.org/1999/xhtml"><a href="part{@part}.xhtml#anchor-{@number}" xmlns="http://www.w3.org/1999/xhtml"><xsl:value-of select="@number" /></a>. <xsl:apply-templates /><xsl:if test="name()='pa'"> [przypis autorski]</xsl:if><xsl:if test="name()='pt'"> [przypis tłumacza]</xsl:if><xsl:if test="name()='pr'"> [przypis redakcyjny]</xsl:if><xsl:if test="name()='pe'"> [przypis edytorski]</xsl:if></p>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:element name="head">
<link rel="stylesheet" href="style.css" type="text/css" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title>
- WolneLektury.pl
- </title>
+ <title>WolneLektury.pl</title>
</xsl:element>
<xsl:element name="body" xmlns="http://www.w3.org/1999/xhtml">
<xsl:element name="div" xmlns="http://www.w3.org/1999/xhtml">
<xsl:template match="ilustr">
<img>
- <xsl:attribute name="src">
- <xsl:value-of select="@src" />
- </xsl:attribute>
<xsl:attribute name="alt">
<xsl:value-of select="@alt" />
</xsl:attribute>
+ <xsl:attribute name="src">
+ <xsl:value-of select="@src" />
+ </xsl:attribute>
<xsl:attribute name="title">
<xsl:value-of select="@alt" />
</xsl:attribute>
<xsl:template match="extra" />
<xsl:template match="pe|pa|pr|pt" >
- <a class="anchor" id="anchor-{.}" href="annotations.xhtml#annotation-{.}"
+ <a class="anchor" href="annotations.xhtml#annotation-{.}" id="anchor-{.}"
xmlns="http://www.w3.org/1999/xhtml"><sup xmlns="http://www.w3.org/1999/xhtml"><xsl:apply-templates /></sup></a>
</xsl:template>
--- /dev/null
+import os
+from shutil import rmtree
+import subprocess
+from tempfile import mkdtemp
+
+
+def strip_font(path, chars, verbose=False):
+ tmpdir = mkdtemp('-librarian-epub')
+ try:
+ cwd = os.getcwd()
+ except OSError:
+ cwd = None
+
+ os.chdir(os.path.join(os.path.dirname(os.path.realpath(__file__)),
+ 'font-optimizer'))
+ optimizer_call = [
+ 'perl', 'subset.pl', '--chars',
+ ''.join(chars).encode('utf-8'),
+ path,
+ os.path.join(tmpdir, 'font.ttf')
+ ]
+ env = {"PERL_USE_UNSAFE_INC": "1"}
+ if verbose:
+ print("Running font-optimizer")
+ subprocess.check_call(optimizer_call, env=env)
+ else:
+ dev_null = open(os.devnull, 'w')
+ subprocess.check_call(optimizer_call, stdout=dev_null,
+ stderr=dev_null, env=env)
+ with open(os.path.join(tmpdir, 'font.ttf'), 'rb') as f:
+ content = f.read()
+
+ rmtree(tmpdir)
+
+ if cwd is not None:
+ os.chdir(cwd)
+
+ return content
--- /dev/null
+FUNDRAISING = [
+ 'Przyjaciele Wolnych Lektur otrzymują dostęp do nowych tekstów współczesnych autorek i autorów wcześniej niż inni. <a href="https://wolnelektury.pl/towarzystwo/">Kliknij, by przejść do strony płatności.</a> Zadeklaruj stałą wpłatę i dołącz do Towarzystwa Przyjaciół Wolnych Lektur.',
+ 'Czytaj teksty współczesnych autorek i autorów wcześniej niż inni. Ty decydujesz, ile płacisz! <a href="https://wolnelektury.pl/towarzystwo/">Zadeklaruj stałą wpłatę i dołącz do Towarzystwa Przyjaciół Wolnych Lektur</a>.',
+ 'Informacje o nowościach w naszej bibliotece w Twojej skrzynce mailowej? Nic prostszego, zapisz się do newslettera.<br/><a href="https://wolnelektury.pl/newsletter/">Kliknij, by pozostawić swój adres e-mail</a>.',
+ '''Przekaż 1% podatku na Wolne Lektury.<br/>
+KRS: 0000070056<br/>
+Nazwa organizacji: Fundacja Nowoczesna Polska<br/>
+<br/>
+Możesz to zrobić w swoim formularzu PIT dostępnym od 15 lutego na stronie: <a href="https://www.podatki.gov.pl/pit">www.podatki.gov.pl/pit</a>.<br/>
+<br/>
+Każda wpłacona kwota zostanie przeznaczona na rozwój Wolnych Lektur.<br/>
+Dziękujemy, że jesteście z nami!''',
+]
rel_path = ilustr.attrib['src']
img_url = six.moves.urllib.parse.urljoin(base_url, rel_path)
- with six.moves.urllib.request.urlopen(img_url) as f:
- img = Image.open(f)
-
+ f = six.moves.urllib.request.urlopen(img_url)
+ img = Image.open(f)
ext = {'GIF': 'gif', 'PNG': 'png'}.get(img.format, 'jpg')
srcset = []
]
largest = None
for w in widths:
- height = round(img.size[1] * w / img.size[0])
- th = img.resize((w, height))
fname = '%d.W%d.%s' % (i, w, ext)
- th.save(gallery_path + fname)
+ fpath = gallery_path + fname
+ if not os.path.exists(fpath):
+ height = round(img.size[1] * w / img.size[0])
+ th = img.resize((w, height))
+ th.save(fpath)
th_url = gallery_url + fname
srcset.append(" ".join((
th_url,
ilustr.attrib['srcset'] = ", ".join(srcset)
ilustr.attrib['src'] = largest_url
+ f.close()
+
def transform(wldoc, stylesheet='legacy', options=None, flags=None, css=None, gallery_path='img/', gallery_url='img/', base_url='file://./'):
"""Transforms the WL document to XHTML.
base_url,
ilustr.get('src')
)
- with six.moves.urllib.request.urlopen(url) as imgfile:
- img = Image.open(imgfile)
+ imgfile = six.moves.urllib.request.urlopen(url)
+ img = Image.open(imgfile)
th_format, ext, media_type = {
'GIF': ('GIF', 'gif', 'image/gif'),
th.save(os.path.join(temp, file_name))
ilustr.set('src', file_name)
+ imgfile.close()
+
for sponsor in book_info.sponsors:
ins = etree.Element("data-sponsor", name=sponsor)
logo = sponsor_logo(sponsor)
\usepackage{unicode-math}
\setmathfont{Latin Modern Math}
+\usepackage{wrapfig}
+
\usepackage[overload]{textcase}
\usepackage{scalefnt}
\usepackage[colorlinks=true,linkcolor=black,setpagesize=false,urlcolor=black,xetex]{hyperref}
</xsl:template>
<xsl:template match="ilustr">
- <cmd name="ilustr">
+ <xsl:choose>
+ <xsl:when test="@oblew = 'true'">
+ <cmd name="par"/>
+ <env name="wrapfigure">
+ <parm>R</parm>
+ <parm>5cm</parm>
+ <cmd name="includegraphics">
+ <opt>width=<cmd name="linewidth"/></opt>
+ <parm><xsl:value-of select="@src"/></parm>
+ </cmd>
+ </env>
+ </xsl:when>
+ <xsl:otherwise>
+ <cmd name="ilustr">
<parm><xsl:value-of select="@src" /></parm>
<parm><xsl:value-of select="@alt" /></parm>
- </cmd>
+ </cmd>
+ </xsl:otherwise>
+ </xsl:choose>
</xsl:template>
<!-- ========================================== -->
description = parsed_dc.description
url = document.book_info.url
- license_description = parsed_dc.license_description
+ license_name = parsed_dc.license_description
license = parsed_dc.license
+ license_description = [
+ (
+ "Wszystkie zasoby Wolnych Lektur możesz swobodnie wykorzystywać, "
+ "publikować i rozpowszechniać pod warunkiem zachowania warunków "
+ "licencji i zgodnie z Zasadami wykorzystania Wolnych Lektur."
+ )
+ ]
+
if license:
- license_description = (
- u"Ten utwór jest udostępniony na licencji %s: \n%s" % (
- license_description, license
+ license_description.append(
+ "Ten utwór jest udostępniony na licencji %s: %s" % (
+ license_name, license
)
)
else:
- license_description = (
- "Ten utwór nie jest objęty majątkowym prawem autorskim "
- "i znajduje się w domenie publicznej, co oznacza że "
- "możesz go swobodnie wykorzystywać, publikować "
- "i rozpowszechniać. Jeśli utwór opatrzony jest "
- "dodatkowymi materiałami (przypisy, motywy literackie "
- "etc.), które podlegają prawu autorskiemu, to te "
- "dodatkowe materiały udostępnione są na licencji "
- "Creative Commons Uznanie Autorstwa – Na Tych Samych "
- "Warunkach 3.0 PL "
- "(http://creativecommons.org/licenses/by-sa/3.0/)"
+ license_description.append(
+ "Ten utwór jest w domenie publicznej."
)
+ license_description.append(
+ "Wszystkie materiały dodatkowe (przypisy, motywy literackie) są "
+ "udostępnione na Licencji Wolnej Sztuki 1.3: "
+ "https://artlibre.org/licence/lal/pl/\n"
+ "Fundacja Nowoczesna Polska zastrzega sobie prawa do wydania "
+ "krytycznego zgodnie z art. Art.99(2) Ustawy o prawach autorskich "
+ "i prawach pokrewnych.\nWykorzystując zasoby z Wolnych Lektur, "
+ "należy pamiętać o zapisach licencji oraz zasadach, które "
+ "spisaliśmy w Zasadach wykorzystania Wolnych Lektur: "
+ "https://wolnelektury.pl/info/zasady-wykorzystania/\nZapoznaj "
+ "się z nimi, zanim udostępnisz dalej nasze książki"
+ )
+ license_description = "\n".join(license_description)
source = parsed_dc.source_name
if source:
<xsl:value-of select="$css" />
</xsl:attribute>
</link>
+ <style>
+ .ilustr.prawo img {
+ float: right;
+ }
+ .ilustr.lewo img {
+ float: left;
+ }
+ .ilustr.srodek {
+ text-align: center;
+ }
+ .ilustr .stop {
+ clear: both;
+ }
+ .ilustr.oblew .stop {
+ clear: none;
+ }
+
+ .ilustr.oblew img {
+ margin-bottom: 1em;
+ }
+ .ilustr.oblew.lewo img {
+ margin-right: 2em;
+ }
+ .ilustr.oblew.prawo img {
+ margin-left: 2em;
+ }
+
+
+ .ilustr img {
+ min-width: 200px !important;
+ }
+ @media screen and (max-width: 320px) {
+ .ilustr img {
+ width: 100% !important;
+ min-width: auto !important;
+ }
+ .ilustr.lewo img {
+ float: none;
+ }
+ .ilustr.prawo img {
+ float:none;
+ }
+ .ilustr.oblew.prawo img {
+ margin-left: 0;
+ }
+ .ilustr.oblew.lewo img{
+ margin-right: 0;
+ }
+ .ilustr .stop {
+ clear: none;
+ }
+
+ }
+ </style>
</head>
<body>
<xsl:call-template name="book-text" />
</xsl:template>
<xsl:template match="ilustr">
+ <div>
+
+ <xsl:attribute name="class">
+ <xsl:text>ilustr </xsl:text>
+ <xsl:value-of select="@wyrownanie"/>
+ <xsl:if test="@oblew">
+ <xsl:text> oblew</xsl:text>
+ </xsl:if>
+ </xsl:attribute>
+
<img>
- <xsl:attribute name="src">
- <xsl:value-of select="@src" />
- </xsl:attribute>
- <xsl:attribute name="srcset">
- <xsl:value-of select="@srcset" />
- </xsl:attribute>
- <xsl:attribute name="sizes">
- (min-width: 718px) 600px,
- (min-width: 600px) calc(100vw - 118px),
- (min-width: 320px) calc(100vw - 75px),
- (min-width: 15em) calc(100wv - 60px),
- calc(100wv - 40px)
- </xsl:attribute>
- <xsl:attribute name="alt">
- <xsl:value-of select="@alt" />
- </xsl:attribute>
- <xsl:attribute name="title">
- <xsl:value-of select="@alt" />
+ <xsl:attribute name="src">
+ <xsl:value-of select="@src" />
+ </xsl:attribute>
+ <xsl:attribute name="srcset">
+ <xsl:value-of select="@srcset" />
+ </xsl:attribute>
+ <xsl:attribute name="sizes">
+ (min-width: 718px) 600px,
+ (min-width: 600px) calc(100vw - 118px),
+ (min-width: 320px) calc(100vw - 75px),
+ (min-width: 15em) calc(100wv - 60px),
+ calc(100wv - 40px)
+ </xsl:attribute>
+ <xsl:attribute name="alt">
+ <xsl:value-of select="@alt" />
+ </xsl:attribute>
+ <xsl:attribute name="title">
+ <xsl:value-of select="@alt" />
+ </xsl:attribute>
+
+ <xsl:if test="@szer">
+ <xsl:attribute name="style">
+ <xsl:text>width: </xsl:text>
+ <xsl:value-of select="@szer"/>
</xsl:attribute>
+ </xsl:if>
</img>
+
+ <div class="stop"></div>
+ </div>
</xsl:template>
<xsl:template match="animacja">
<dc:date>2020-01-08</dc:date>
<dc:publisher>Fundacja Nowoczesna Polska</dc:publisher>
<dc:language>pol</dc:language>
- <dc:identifier.url>wl-test</dc:identifier.url>
+ <dc:identifier.url>main</dc:identifier.url>
<dc:rights>gnu gpl</dc:rights>
</rdf:Description>
</rdf:RDF>
<opowiadanie>
-<autor_utworu>Wolne Lektury</autor_utworu>
-<nazwa_utworu>Testy</nazwa_utworu>
-<podtytul>Podtytuł</podtytul>
-
+ <dzielo_nadrzedne>Dzieło nadrzędne<pa>Przypis w dziele nadrzędnym</pa></dzielo_nadrzedne>
+ <autor_utworu>Wolne<pa>Przypis w nazwie utworu</pa> Lektury</autor_utworu>
+ <nazwa_utworu>Testy<pa>Przypis w tytule utworu</pa></nazwa_utworu>
+ <podtytul>Podtytuł<pa>Przypis w podtytule</pa></podtytul>
+
<naglowek_czesc>Testy struktury</naglowek_czesc>
-
+
<naglowek_czesc>Nagłówek części</naglowek_czesc>
<podtytul_czesc>Podtytuł części</podtytul_czesc>
-
+
<naglowek_rozdzial>Nagłówek rozdziału</naglowek_rozdzial>
<podtytul_rozdzial>Podtytuł rozdziału</podtytul_rozdzial>
-
+
<naglowek_podrozdzial>Nagłówek podrozdziału</naglowek_podrozdzial>
<podtytul_podrozdzial>Podtytuł podrozdziału</podtytul_podrozdzial>
-
+
<naglowek_akt>Nagłówek aktu</naglowek_akt>
<podtytul_akt>Podtytuł aktu</podtytul_akt>
<srodtytul>Śródtytuł</srodtytul>
<akap>Nagłówki powinny tworzyć prawidłową strukturę. Użyte elementy: tytuły i podtytuły części, rozdziału, podrozdziału, aktu i sceny, oraz śródtytuł.</akap>
+
+
+
+ <naglowek_czesc>Akapity</naglowek_czesc>
+
+ <akap>Zwykły akapit.</akap>
+
+ <akap_cd>Kontynuacja akapitu.</akap_cd>
+
+ <akap_dialog>--- Akapit dialogowy.</akap_dialog>
+
+ <akap>Zastępnik wersu w akapicie:</akap>
+ <akap><zastepnik_wersu>. . . . . . . .</zastepnik_wersu></akap>
+
+ <akap>Poezja cytowana w akapicie dialogowym (?):</akap>
+ <akap_dialog><poezja_cyt><strofa>--- Cytat</strofa></poezja_cyt></akap_dialog>
+
+
+
+
+
+
+ <naglowek_czesc>Dramat</naglowek_czesc>
+
+ <lista_osob>
+ <naglowek_listy>
+ Lista osób
+ </naglowek_listy>
+ <lista_osoba>
+ <osoba>Pustelnik</osoba> --- pustelnik
+ </lista_osoba>
+ <lista_osoba>
+ <osoba>Hesia</osoba> --- Hesia
+ </lista_osoba>
+
+ </lista_osob>
+
+ <miejsce_czas>
+ </miejsce_czas>
+
+ <naglowek_osoba>PUSTELNIK</naglowek_osoba>
+
+ <kwestia>
+ <strofa>
+ Więc jako dawniej czynili mocarze,/
+ Z Lechem się mieniał Scyta na obrączki;/
+ A pokochawszy mocniej sercem, w darze/
+ Dał mu koronę... stąd nasza korona./
+ Zbawiciel niegdyś wyciągając rączki/
+ Szedł do niej z matki zadumanej łona/
+ I ku rubinom podawał się cały/
+ Jako różyczka z liści wychylona,/
+ I wołał: caca! i na brylant biały/
+ Różanych ustek perełkami świecił.
+ </strofa>
+ </kwestia>
+
+ <didaskalia>Słychać głos Hesi.</didaskalia>
+
+ <naglowek_osoba>GŁOS HESI</naglowek_osoba>
+
+ <kwestia>
+ <akap>
+ Mamuńciu, tak zimno! troszkę ciepłej wody...
+ </akap>
+ </kwestia>
+
+ <naglowek_osoba>DULSKA</naglowek_osoba>
+
+ <kwestia>
+ <akap>
+ Jeszcze czego? Hartujcie się... Felicjan! wstajesz? Wiesz? ten błazen, twój syn, nie wrócił jeszcze do domu! Co? nic nie mówisz? naturalnie.
+ Ojciec toleruje. Niedaleko padło jabłko od jabłoni. Ale jak będą dłużki małe --- nie zapłacę.
+ </akap>
+ </kwestia>
+
+
+
+
+ <naglowek_czesc>Wyróżnienia</naglowek_czesc>
+
+ <akap>Wyróżnienia:
+ <didask_tekst>didaskalia tekstowe</didask_tekst>,
+ <didaskalia>didaskalia</didaskalia>,
+ <indeks_dolny>indeks dolny</indeks_dolny>,
+ <osoba>osoba</osoba>,
+ <slowo_obce>słowo obce</slowo_obce>,
+ <tytul_dziela>tytuł dzieła</tytul_dziela>,
+ <wieksze_odstepy>większe odstępny</wieksze_odstepy>,
+ <wyroznienie>wyróżnienie</wyroznienie>,
+ <www>https://wolnelektury.pl/</www>.
+ </akap>
+
+
+
+
+ <naglowek_czesc>Grupy</naglowek_czesc>
+
+ <akap>Długi cytat:</akap>
+
+ <dlugi_cytat>
+ <akap>Długi cytat, akapit.</akap>
+ <akap_cd>Kontynuacja akapitu.</akap_cd>
+ <akap_dialog>--- Akapit dialogowy</akap_dialog>
+
+ <strofa>Strofa/ w/ cytacie</strofa>
+
+ <didaskalia>Didaskalia (czy tak?)</didaskalia>
+
+ <dlugi_cytat>
+ <akap>Cytat w cytacie!</akap>
+ <akap_cd>Kontynuacja akapitu w cytacie</akap_cd>
+ <akap_dialog>--- Akapit dialogowy w cytacie</akap_dialog>
+ </dlugi_cytat>
+
+
+ <poezja_cyt>
+ <strofa>Poezja/ cytowana/ w cytacie</strofa>
+ </poezja_cyt>
+
+
+ <naglowek_osoba>
+ </naglowek_osoba>
+ <kwestia>
+ ...
+ </kwestia>
+
+
+ <naglowek_rozdzial>Rozdział w cytacie</naglowek_rozdzial>
+ <naglowek_podrozdzial>Podrozdział w cytacie</naglowek_podrozdzial>
+ <srodtytul>Śródtytuł w cytacie</srodtytul>
+
+ <motto_podpis>
+ </motto_podpis>
+
+ <nota>
+ <akap>Nota w cytacie</akap>
+ </nota>
+
+ <akap>Asterysk:</akap>
+ <sekcja_asterysk/>
+
+ <akap>Światło:</akap>
+ <sekcja_swiatlo/>
+
+ <akap>Separator linia:</akap>
+ <separator_linia/>
+
+ <akap>Koniec cytatu.</akap>
+
+ </dlugi_cytat>
+
+ <akap>Tekst za cytatem.</akap>
+
+
+ <akap>Cytat poetycki:</akap>
+
+ <poezja_cyt>
+ <naglowek_rozdzial>Nagłówek rozdziału</naglowek_rozdzial>
+ <naglowek_podrozdzial>Nagłówek podrozdziału</naglowek_podrozdzial>
+ <srodtytul>Śródtytuł</srodtytul>
+ <naglowek_osoba>Nagłówek: osoba</naglowek_osoba>
+
+ <nota>
+ <akap>
+ Nota
+ </akap>
+ </nota>
+
+ <akap>Akapit</akap>
+
+ <strofa>Strofa/ w/ cytacie</strofa>
+
+ <didaskalia>didaskalia?</didaskalia>
+
+ <kwestia>
+ <strofa>
+ Strofa/ w/ kwestii/ w cytacie.
+ </strofa>
+ </kwestia>
+
+ <motto_podpis>
+ Motto-podpis
+ </motto_podpis>
+
+ <poezja_cyt>
+ <strofa>
+ Poezja/
+ cytowana/
+ w cytacie/
+ poetyckim
+ </strofa>
+ </poezja_cyt>
+
+ <akap>Asterysk:</akap>
+ <sekcja_asterysk/>
+
+
+
+ </poezja_cyt>
+
+
+
+
<naglowek_czesc>Strofa w przypisie</naglowek_czesc>
</akap>
+
+
+
+
+ <naglowek_czesc>Wzory</naglowek_czesc>
+
+ <akap>
+ Wzór:
+ <mat><mrow>
+ <mi>δ</mi>
+ <mo>=</mo>
+ <mfrac>
+ <mrow>
+ <mi>e</mi>
+ <mo></mo>
+ <mi>F</mi>
+ <mo></mo>
+ <mi>l</mi>
+ <mo>×</mo>
+ <mfenced><mrow>
+ <mfrac>
+ <mi>l</mi>
+ <mn>2</mn>
+ </mfrac>
+ <mo>+</mo>
+ <mi>h</mi>
+ </mrow>
+ </mfenced>
+ </mrow>
+ <mrow>
+ <mi>m</mi>
+ <mo></mo>
+ <msup>
+ <mi>v</mi>
+ <mn>2</mn>
+ </msup>
+ </mrow>
+ </mfrac>
+ </mrow></mat>
+ </akap>
+
+
+
+
+
+ <naglowek_czesc>Separatory</naglowek_czesc>
+
+
+ <akap>Asterysk:</akap>
+ <sekcja_asterysk/>
+
+ <akap>Światło:</akap>
+ <sekcja_swiatlo/>
+
+ <akap>Separator linia:</akap>
+ <separator_linia/>
+
+
+
+
+ <naglowek_czesc>Tabele</naglowek_czesc>
+
+ <akap>Tabela bez ramek:</akap>
+
+ <tabela>
+ <wiersz>
+ <kol>
+ Komórka 1
+ </kol>
+ <kol>
+ Komórka 2
+ </kol>
+ </wiersz>
+ <wiersz>
+ <kol>
+ Komórka 3
+ </kol>
+ <kol>
+ Komórka 4
+ </kol>
+ </wiersz>
+ </tabela>
+
+ <akap>Tabela z ramkami:</akap>
+
+
+ <tabela ramka="1">
+ <wiersz>
+ <kol>
+ Komórka 1
+ </kol>
+ <kol>
+ Komórka 2
+ </kol>
+ </wiersz>
+ <wiersz>
+ <kol>
+ Komórka 3
+ </kol>
+ <kol>
+ Komórka 4
+ </kol>
+ </wiersz>
+ </tabela>
+
+ <naglowek_czesc>Ilustracje</naglowek_czesc>
+
+
</opowiadanie>
</utwor>
--- /dev/null
+<utwor>
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ <rdf:Description xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <dc:creator>Radek Czajka</dc:creator>
+ <dc:title>Test Parent Document</dc:title>
+ <dc:date>2020-01-08</dc:date>
+ <dc:publisher>Fundacja Nowoczesna Polska</dc:publisher>
+ <dc:language>pol</dc:language>
+ <dc:identifier.url>wl-test-parent</dc:identifier.url>
+ <dc:rights>gnu agpl</dc:rights>
+ <dc:relation.hasPart>main</dc:relation.hasPart>
+ <dc:relation.hasPart>part2</dc:relation.hasPart>
+ </rdf:Description>
+ </rdf:RDF>
+</utwor>
--- /dev/null
+<utwor>
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ <rdf:Description xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <dc:creator>Radek Czajka</dc:creator>
+ <dc:title>Test Document, Part 2</dc:title>
+ <dc:date>2020-01-08</dc:date>
+ <dc:publisher>Fundacja Nowoczesna Polska</dc:publisher>
+ <dc:language>pol</dc:language>
+ <dc:identifier.url>part2</dc:identifier.url>
+ <dc:rights>gnu gpl</dc:rights>
+ </rdf:Description>
+ </rdf:RDF>
+
+ <opowiadanie>
+
+<autor_utworu>Wolne Lektury</autor_utworu>
+<nazwa_utworu>Testy</nazwa_utworu>
+<podtytul>Podtytuł</podtytul>
+
+<akap>
+ Druga część. Powinna być widoczna
+</akap>
+
+ </opowiadanie>
+</utwor>