Ejemplo n.º 1
0
def transform_chunk(chunk_xml, chunk_no, annotations, empty=False, _empty_html_static=[]):
    """ transforms one chunk, returns a HTML string, a TOC object and a set of used characters """

    toc = TOC()
    for element in chunk_xml[0]:
        if element.tag == "naglowek_czesc":
            toc.add(node_name(element), "part%d.html#book-text" % chunk_no)
        elif element.tag in ("naglowek_rozdzial", "naglowek_akt", "srodtytul"):
            toc.add(node_name(element), "part%d.html" % chunk_no)
        elif element.tag in ('naglowek_podrozdzial', 'naglowek_scena'):
            subnumber = toc.add(node_name(element), "part%d.html" % chunk_no, level=1, is_part=False)
            element.set('sub', str(subnumber))
    if empty:
        if not _empty_html_static:
            _empty_html_static.append(open(get_resource('epub/emptyChunk.html')).read())
        chars = set()
        output_html = _empty_html_static[0]
    else:
        find_annotations(annotations, chunk_xml, chunk_no)
        replace_by_verse(chunk_xml)
        html_tree = xslt(chunk_xml, get_resource('epub/xsltScheme.xsl'))
        chars = used_chars(html_tree.getroot())
        output_html = etree.tostring(
            html_tree, pretty_print=True, xml_declaration=True,
            encoding="utf-8",
            doctype='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" ' +
                    '"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
        )
    return output_html, toc, chars
Ejemplo n.º 2
0
class PrestigioCover(Cover):
    width = 580
    height = 783
    background_img = get_resource('res/cover-prestigio.png')

    author_top = 446
    author_margin_left = 118
    author_margin_right = 62
    author_lineskip = 60
    author_color = '#fff'
    author_shadow = '#000'
    author_font_ttf = get_resource('fonts/JunicodeWL-Italic.ttf')
    author_font_size = 50

    title_top = 0
    title_margin_left = 118
    title_margin_right = 62
    title_lineskip = 60
    title_color = '#fff'
    title_shadow = '#000'
    title_font_ttf = get_resource('fonts/JunicodeWL-Italic.ttf')
    title_font_size = 50

    def pretty_title(self):
        return u"„%s”" % self.title
Ejemplo n.º 3
0
def transform_chunk(chunk_xml, chunk_no, annotations, empty=False, _empty_html_static=[]):
    """ transforms one chunk, returns a HTML string, a TOC object and a set of used characters """

    toc = TOC()
    for element in chunk_xml[0]:
        if element.tag == "naglowek_czesc":
            toc.add(node_name(element), "part%d.html#book-text" % chunk_no)
        elif element.tag in ("naglowek_rozdzial", "naglowek_akt", "srodtytul"):
            toc.add(node_name(element), "part%d.html" % chunk_no)
        elif element.tag in ('naglowek_podrozdzial', 'naglowek_scena'):
            subnumber = toc.add(node_name(element), "part%d.html" % chunk_no, level=1, is_part=False)
            element.set('sub', str(subnumber))
    if empty:
        if not _empty_html_static:
            _empty_html_static.append(open(get_resource('epub/emptyChunk.html')).read())
        chars = set()
        output_html = _empty_html_static[0]
    else:
        find_annotations(annotations, chunk_xml, chunk_no)
        replace_by_verse(chunk_xml)
        html_tree = xslt(chunk_xml, get_resource('epub/xsltScheme.xsl'))
        chars = used_chars(html_tree.getroot())
        output_html = etree.tostring(
            html_tree, pretty_print=True, xml_declaration=True,
            encoding="utf-8",
            doctype='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" ' +
                    '"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
        )
    return output_html, toc, chars
Ejemplo n.º 4
0
class GandalfCover(Cover):
    width = 600
    height = 730
    background_img = get_resource('res/cover-gandalf.png')
    author_font_ttf = get_resource('fonts/JunicodeWL-Regular.ttf')
    author_font_size = 30
    title_font_ttf = get_resource('fonts/JunicodeWL-Regular.ttf')
    title_font_size = 40
    logo_bottom = 25
    logo_width = 250
    format = 'PNG'
Ejemplo n.º 5
0
    def image(self):
        img = super(LogoWLCover, self).image()
        metr = Metric(self, self.scale)
        gradient = Image.new("RGBA", (metr.width - metr.bar_width, metr.gradient_height), self.gradient_color)
        gradient_mask = Image.new("L", (metr.width - metr.bar_width, metr.gradient_height))
        draw = ImageDraw.Draw(gradient_mask)
        for line in range(0, metr.gradient_height):
            draw.line(
                (0, line, metr.width - metr.bar_width, line),
                fill=int(255 * self.gradient_opacity * line / metr.gradient_height),
            )
        img.paste(gradient, (metr.bar_width, metr.height - metr.gradient_height), mask=gradient_mask)

        cursor = metr.width - metr.gradient_logo_margin_right
        logo_top = metr.height - metr.gradient_height / 2 - metr.gradient_logo_height / 2
        for logo_path in self.gradient_logos[::-1]:
            logo = Image.open(get_resource(logo_path))
            logo = logo.resize(
                (logo.size[0] * metr.gradient_logo_height / logo.size[1], metr.gradient_logo_height), Image.ANTIALIAS
            )
            cursor -= logo.size[0]
            img.paste(logo, (cursor, logo_top), mask=logo)
            cursor -= metr.gradient_logo_spacing

        return img
Ejemplo n.º 6
0
    def image(self):
        img = super(LogoWLCover, self).image()
        metr = Metric(self, self.scale)
        gradient = Image.new(
            'RGBA', (metr.width - metr.bar_width, metr.gradient_height),
            self.gradient_color)
        gradient_mask = Image.new(
            'L', (metr.width - metr.bar_width, metr.gradient_height))
        draw = ImageDraw.Draw(gradient_mask)
        for line in range(0, metr.gradient_height):
            draw.line((0, line, metr.width - metr.bar_width, line),
                      fill=int(255 * self.gradient_opacity * line /
                               metr.gradient_height))
        img.paste(gradient,
                  (metr.bar_width, metr.height - metr.gradient_height),
                  mask=gradient_mask)

        cursor = metr.width - metr.gradient_logo_margin_right
        logo_top = metr.height - metr.gradient_height / 2 - metr.gradient_logo_height / 2 - metr.bleed / 2
        for logo_path in self.gradient_logos[::-1]:
            logo = Image.open(get_resource(logo_path))
            logo = logo.resize(
                (logo.size[0] * metr.gradient_logo_height / logo.size[1],
                 metr.gradient_logo_height), Image.ANTIALIAS)
            cursor -= logo.size[0]
            img.paste(logo, (cursor, logo_top), mask=logo)
            cursor -= metr.gradient_logo_spacing

        return img
Ejemplo n.º 7
0
    def image(self):
        metr = Metric(self, self.scale)
        img = Image.new("RGB", (metr.width, metr.height), self.background_color)

        if self.background_img:
            background = Image.open(self.background_img)
            img.paste(background, None, background)
            del background

        # WL logo
        if metr.logo_width:
            logo = Image.open(get_resource("res/wl-logo.png"))
            logo = logo.resize((metr.logo_width, logo.size[1] * metr.logo_width / logo.size[0]))
            img.paste(logo, ((metr.width - metr.logo_width) / 2, img.size[1] - logo.size[1] - metr.logo_bottom))

        top = metr.author_top
        tbox = TextBox(metr.width - metr.author_margin_left - metr.author_margin_right, metr.height - top)

        author_font = ImageFont.truetype(self.author_font_ttf, metr.author_font_size)
        tbox.text(self.pretty_author(), self.author_color, author_font, metr.author_lineskip, self.author_shadow)
        text_img = tbox.image()
        img.paste(text_img, (metr.author_margin_left, top), text_img)

        top += text_img.size[1] + metr.title_top
        tbox = TextBox(metr.width - metr.title_margin_left - metr.title_margin_right, metr.height - top)
        title_font = ImageFont.truetype(self.title_font_ttf, metr.title_font_size)
        tbox.text(self.pretty_title(), self.title_color, title_font, metr.title_lineskip, self.title_shadow)
        text_img = tbox.image()
        img.paste(text_img, (metr.title_margin_left, top), text_img)

        return img
Ejemplo n.º 8
0
 def to_png(self):
     tmpl = open(get_resource('res/embeds/latex/template.tex'), 'rb').read().decode('utf-8')
     tempdir = mkdtemp('-librarian-embed-latex')
     fpath = os.path.join(tempdir, 'doc.tex')
     with open(fpath, 'wb') as f:
         f.write((tmpl % {'code': self.data}).encode('utf-8'))
     call(['xelatex', '-interaction=batchmode', '-output-directory', tempdir, fpath], stdout=PIPE, stderr=PIPE)
     call(['convert', '-density', '150', os.path.join(tempdir, 'doc.pdf'), '-trim',
          os.path.join(tempdir, 'doc.png')])
     pngdata = open(os.path.join(tempdir, 'doc.png'), 'rb').read()
     shutil.rmtree(tempdir)
     return create_embed('image/png', data=pngdata)
Ejemplo n.º 9
0
 def to_png(self):
     tmpl = open(get_resource('res/embeds/latex/template.tex')).read().decode('utf-8')
     tempdir = mkdtemp('-librarian-embed-latex')
     fpath = os.path.join(tempdir, 'doc.tex')
     with open(fpath, 'w') as f:
         f.write((tmpl % {'code': self.data}).encode('utf-8'))
     call(['xelatex', '-interaction=batchmode', '-output-directory', tempdir, fpath], stdout=PIPE, stderr=PIPE)
     call(['convert', '-density', '150', os.path.join(tempdir, 'doc.pdf'), '-trim',
             os.path.join(tempdir, 'doc.png')])
     pngdata = open(os.path.join(tempdir, 'doc.png')).read()
     shutil.rmtree(tempdir)
     return create_embed('image/png', data=pngdata)
Ejemplo n.º 10
0
 def get_short_lng_code(text):
     result = ''
     text = ''.join(text)
     with open(get_resource('res/ISO-639-2_8859-1.txt'), 'rb') as f:
         for line in f:
             list = line.strip().split('|')
             if list[0] == text:
                 result = list[2]
     if result == '':
         return text
     else:
         return result
Ejemplo n.º 11
0
 def get_short_lng_code(text):
     result = ''
     text = ''.join(text)
     with open(get_resource('res/ISO-639-2_8859-1.txt'), 'rb') as f:
         for line in f:
             list = line.strip().split('|')
             if list[0] == text:
                 result = list[2]
     if result == '':
         return text
     else:
         return result
Ejemplo n.º 12
0
 def lang_code_3to2(context, text):
     """Convert 3-letter language code to 2-letter code"""
     result = ''
     text = ''.join(text)
     with open(get_resource('res/ISO-639-2_8859-1.txt'), 'rb') as f:
         for line in f.read().decode('latin1').split('\n'):
             list = line.strip().split('|')
             if list[0] == text:
                 result = list[2]
     if result == '':
         return text
     else:
         return result
Ejemplo n.º 13
0
def transform_chunk(chunk_xml, chunk_no, annotations, empty=False, _empty_html_static=[]):
    """ transforms one chunk, returns a HTML string, a TOC object and a set of used characters """

    toc = TOC()
    for element in chunk_xml[0]:
        if element.tag in ("naglowek_czesc", "naglowek_rozdzial", "naglowek_akt", "srodtytul"):
            toc.add(node_name(element), "part%d.html" % chunk_no)
        elif element.tag in ('naglowek_podrozdzial', 'naglowek_scena'):
            subnumber = toc.add(node_name(element), "part%d.html" % chunk_no, level=1, is_part=False)
            element.set('sub', str(subnumber))
    if empty:
        if not _empty_html_static:
            _empty_html_static.append(open(get_resource('epub/emptyChunk.html')).read())
        chars = set()
        output_html = _empty_html_static[0]
    else:
        find_annotations(annotations, chunk_xml, chunk_no)
        replace_by_verse(chunk_xml)
        html_tree = xslt(chunk_xml, get_resource('epub/xsltScheme.xsl'))
        chars = used_chars(html_tree.getroot())
        output_html = etree.tostring(html_tree, method="html", pretty_print=True)
    return output_html, toc, chars
Ejemplo n.º 14
0
	def lang_code_3to2(context, text):
		"""Convert 3-letter language code to 2-letter code"""
		result = ''
		text = ''.join(text)
		with open(get_resource('res/ISO-639-2_8859-1.txt'), 'rb') as f:
			for line in f:
				list = line.strip().split('|')
				if list[0] == text:
					result=list[2]
		if result == '':
			return text
		else:
			return result
Ejemplo n.º 15
0
class BookotekaCover(Cover):
    width = 2140
    height = 2733
    background_img = get_resource('res/cover-bookoteka.png')

    author_top = 480
    author_margin_left = 307
    author_margin_right = 233
    author_lineskip = 156
    author_color = '#d9d919'
    author_font_ttf = get_resource('fonts/JunicodeWL-Regular.ttf')
    author_font_size = 130

    title_top = 400
    title_margin_left = 307
    title_margin_right = 233
    title_lineskip = 168
    title_color = '#d9d919'
    title_font_ttf = get_resource('fonts/JunicodeWL-Regular.ttf')
    title_font_size = 140

    format = 'PNG'
Ejemplo n.º 16
0
    def image(self):
        img = Image.new('RGB', (self.width, self.height), self.background_color)

        if self.background_img:
            background = Image.open(self.background_img)
            img.paste(background, None, background)
            del background

        # WL logo
        if self.logo_width:
            logo = Image.open(get_resource('res/wl-logo.png'))
            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))

        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
Ejemplo n.º 17
0
    def add_source_note(wlpic, img):
        from PIL import ImageDraw, ImageFont
        from librarian import get_resource

        annotated = Image.new(img.mode, (img.size[0], img.size[1] + 40), (255, 255, 255))
        annotated.paste(img, (0, 0))
        annotation = Image.new('RGB', (img.size[0] * 3, 120), (255, 255, 255))
        ImageDraw.Draw(annotation).text(
            (30, 15),
            wlpic.picture_info.source_name,
            (0, 0, 0),
            font=ImageFont.truetype(get_resource("fonts/DejaVuSerif.ttf"), 75)
        )
        annotated.paste(annotation.resize((img.size[0], 40), Image.ANTIALIAS), (0, img.size[1]))
        return annotated
Ejemplo n.º 18
0
def transform(wldoc, verbose=False,
              sample=None, cover=None, flags=None):
    """ produces a MOBI file

    wldoc: a WLDocument
    sample=n: generate sample e-book (with at least n paragraphs)
    cover: a cover.Cover factory overriding default
    flags: less-advertising,
    """

    document = deepcopy(wldoc)
    del wldoc
    book_info = document.book_info

    # provide a cover by default
    if not cover:
        cover = DefaultEbookCover
    cover_file = NamedTemporaryFile(suffix='.png', delete=False)
    bound_cover = cover(book_info)
    bound_cover.save(cover_file)

    if bound_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) + ['with-full-fonts']
    epub = document.as_epub(verbose=verbose, sample=sample, html_toc=True,
            flags=flags, style=get_resource('epub/style.css'))

    if verbose:
        kwargs = {}
    else:
        devnull = open("/dev/null", 'w')
        kwargs = {"stdout": devnull, "stderr": devnull}

    output_file = NamedTemporaryFile(prefix='librarian', suffix='.mobi', delete=False)
    output_file.close()
    subprocess.check_call(['ebook-convert', epub.get_filename(), output_file.name,
            '--no-inline-toc', '--mobi-file-type=both', '--subset-embedded-fonts', '--mobi-ignore-margins', '--cover=%s' % cover_file.name], **kwargs)
    os.unlink(cover_file.name)
    return OutputFile.from_filename(output_file.name)
Ejemplo n.º 19
0
    def image(self):
        metr = Metric(self, self.scale)
        img = Image.new('RGB', (metr.width, metr.height),
                        self.background_color)

        if self.background_img:
            background = Image.open(self.background_img)
            img.paste(background, None, background)
            del background

        # WL logo
        if metr.logo_width:
            logo = Image.open(get_resource('res/wl-logo.png'))
            logo = logo.resize(
                (metr.logo_width,
                 int(round(logo.size[1] * metr.logo_width / logo.size[0]))))
            img.paste(logo, ((metr.width - metr.logo_width) // 2,
                             img.size[1] - logo.size[1] - metr.logo_bottom))

        top = metr.author_top
        tbox = TextBox(
            metr.width - metr.author_margin_left - metr.author_margin_right,
            metr.height - top,
        )

        author_font = ImageFont.truetype(self.author_font_ttf,
                                         metr.author_font_size)
        tbox.text(self.pretty_author(), self.author_color, author_font,
                  metr.author_lineskip, self.author_shadow)
        text_img = tbox.image()
        img.paste(text_img, (metr.author_margin_left, top), text_img)

        top += text_img.size[1] + metr.title_top
        tbox = TextBox(
            metr.width - metr.title_margin_left - metr.title_margin_right,
            metr.height - top,
        )
        title_font = ImageFont.truetype(self.title_font_ttf,
                                        metr.title_font_size)
        tbox.text(self.pretty_title(), self.title_color, title_font,
                  metr.title_lineskip, self.title_shadow)
        text_img = tbox.image()
        img.paste(text_img, (metr.title_margin_left, top), text_img)

        return img
Ejemplo n.º 20
0
def set_hyph_language(source_tree):
    def get_short_lng_code(text):
        result = ''
        text = ''.join(text)
        with open(get_resource('res/ISO-639-2_8859-1.txt'), 'rb') as f:
            for line in f:
                list = line.strip().split('|')
                if list[0] == text:
                    result = list[2]
        if result == '':
            return text
        else:
            return result
    bibl_lng = etree.XPath('//dc:language//text()',
                           namespaces={'dc': str(DCNS)})(source_tree)
    short_lng = get_short_lng_code(bibl_lng[0])
    try:
        return Hyphenator(get_resource('res/hyph-dictionaries/hyph_' +
                                       short_lng + '.dic'))
    except:
        pass
Ejemplo n.º 21
0
def set_hyph_language(source_tree):
    def get_short_lng_code(text):
        result = ''
        text = ''.join(text)
        with open(get_resource('res/ISO-639-2_8859-1.txt'), 'rb') as f:
            for line in f:
                list = line.strip().split('|')
                if list[0] == text:
                    result = list[2]
        if result == '':
            return text
        else:
            return result
    bibl_lng = etree.XPath('//dc:language//text()',
                           namespaces={'dc': str(DCNS)})(source_tree)
    short_lng = get_short_lng_code(bibl_lng[0])
    try:
        return Hyphenator(get_resource('res/hyph-dictionaries/hyph_' +
                                       short_lng + '.dic'))
    except:
        pass
Ejemplo n.º 22
0
def transform(wldoc, verbose=False,
              style=None, html_toc=False,
              sample=None, cover=None, flags=None):
    """ 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):
        """ processes one input file and proceeds to its children """

        replace_characters(wldoc.edoc.getroot())

        hyphenator = set_hyph_language(wldoc.edoc.getroot())
        hyphenate_and_fix_conjunctions(wldoc.edoc.getroot(), hyphenator)

        # every input file will have a TOC entry,
        # pointing to starting chunk
        toc = TOC(wldoc.book_info.title, "part%d.html" % chunk_counter)
        chars = set()
        if first:
            # write book title page
            html_tree = xslt(wldoc.edoc, get_resource('epub/xsltTitle.xsl'))
            chars = used_chars(html_tree.getroot())
            zip.writestr(
                'OPS/title.html',
                etree.tostring(
                    html_tree, pretty_print=True, xml_declaration=True,
                    encoding="utf-8",
                    doctype='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"' +
                            ' "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
                )
            )
            # add a title page TOC entry
            toc.add(u"Strona tytułowa", "title.html")
        elif wldoc.book_info.parts:
            # write title page for every parent
            if sample is not None and sample <= 0:
                chars = set()
                html_string = open(get_resource('epub/emptyChunk.html')).read()
            else:
                html_tree = xslt(wldoc.edoc, get_resource('epub/xsltChunkTitle.xsl'))
                chars = used_chars(html_tree.getroot())
                html_string = etree.tostring(
                    html_tree, pretty_print=True, xml_declaration=True,
                    encoding="utf-8",
                    doctype='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"' +
                            ' "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
                )
            zip.writestr('OPS/part%d.html' % chunk_counter, html_string)
            add_to_manifest(manifest, chunk_counter)
            add_to_spine(spine, chunk_counter)
            chunk_counter += 1

        if len(wldoc.edoc.getroot()) > 1:
            # rdf before style master
            main_text = wldoc.edoc.getroot()[1]
        else:
            # rdf in style master
            main_text = wldoc.edoc.getroot()[0]
            if main_text.tag == RDFNS('RDF'):
                main_text = None

        if main_text is not None:
            for chunk_xml in chop(main_text):
                empty = False
                if sample is not None:
                    if sample <= 0:
                        empty = True
                    else:
                        sample -= len(chunk_xml.xpath('//strofa|//akap|//akap_cd|//akap_dialog'))
                chunk_html, chunk_toc, chunk_chars = transform_chunk(chunk_xml, chunk_counter, annotations, empty)

                toc.extend(chunk_toc)
                chars = chars.union(chunk_chars)
                zip.writestr('OPS/part%d.html' % chunk_counter, chunk_html)
                add_to_manifest(manifest, chunk_counter)
                add_to_spine(spine, chunk_counter)
                chunk_counter += 1

        for child in wldoc.parts():
            child_toc, chunk_counter, chunk_chars, sample = transform_file(
                child, chunk_counter, first=False, sample=sample)
            toc.append(child_toc)
            chars = chars.union(chunk_chars)

        return toc, chunk_counter, chars, sample

    document = deepcopy(wldoc)
    del wldoc

    if flags:
        for flag in flags:
            document.edoc.getroot().set(flag, 'yes')

    # add editors info
    editors = document.editors()
    if editors:
        document.edoc.getroot().set('editors', u', '.join(sorted(
            editor.readable() for editor in editors)))
    if document.book_info.funders:
        document.edoc.getroot().set('funders', u', '.join(
            document.book_info.funders))
    if document.book_info.thanks:
        document.edoc.getroot().set('thanks', document.book_info.thanks)

    opf = xslt(document.book_info.to_etree(), get_resource('epub/xsltContent.xsl'))
    manifest = opf.find('.//' + OPFNS('manifest'))
    guide = opf.find('.//' + OPFNS('guide'))
    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
    mime = zipfile.ZipInfo()
    mime.filename = 'mimetype'
    mime.compress_type = zipfile.ZIP_STORED
    mime.extra = ''
    zip.writestr(mime, 'application/epub+zip')
    zip.writestr(
        'META-INF/container.xml',
        '<?xml version="1.0" ?>'
        '<container version="1.0" '
        'xmlns="urn:oasis:names:tc:opendocument:xmlns:container">'
        '<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 style:
        style = get_resource('epub/style.css')
    zip.write(style, os.path.join('OPS', 'style.css'))

    if cover:
        if cover is True:
            cover = DefaultEbookCover

        cover_file = StringIO()
        bound_cover = cover(document.book_info)
        bound_cover.save(cover_file)
        cover_name = 'cover.%s' % bound_cover.ext()
        zip.writestr(os.path.join('OPS', cover_name), cover_file.getvalue())
        del cover_file

        cover_tree = etree.parse(get_resource('epub/cover.html'))
        cover_tree.find('//' + XHTMLNS('img')).set('src', cover_name)
        zip.writestr('OPS/cover.html', etree.tostring(
            cover_tree, pretty_print=True, xml_declaration=True,
            encoding="utf-8",
            doctype='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" ' +
                    '"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
        ))

        if bound_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)

        manifest.append(etree.fromstring(
            '<item id="cover" href="cover.html" media-type="application/xhtml+xml" />'))
        manifest.append(etree.fromstring(
            '<item id="cover-image" href="%s" media-type="%s" />' % (cover_name, bound_cover.mime_type())))
        spine.insert(0, etree.fromstring('<itemref idref="cover"/>'))
        opf.getroot()[0].append(etree.fromstring('<meta name="cover" content="cover-image"/>'))
        guide.append(etree.fromstring('<reference href="cover.html" type="cover" title="Okładka"/>'))

    annotations = etree.Element('annotations')

    toc_file = etree.fromstring(
        '<?xml version="1.0" encoding="utf-8"?><!DOCTYPE ncx PUBLIC '
        '"-//NISO//DTD ncx 2005-1//EN" '
        '"http://www.daisy.org/z3986/2005/ncx-2005-1.dtd">'
        '<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" xml:lang="pl" '
        'version="2005-1"><head></head><docTitle></docTitle><navMap>'
        '</navMap></ncx>'
    )
    nav_map = toc_file[-1]

    if html_toc:
        manifest.append(etree.fromstring(
            '<item id="html_toc" href="toc.html" media-type="application/xhtml+xml" />'))
        spine.append(etree.fromstring(
            '<itemref idref="html_toc" />'))
        guide.append(etree.fromstring('<reference href="toc.html" type="toc" title="Spis treści"/>'))

    toc, chunk_counter, chars, sample = transform_file(document, sample=sample)

    if len(toc.children) < 2:
        toc.add(u"Początek utworu", "part1.html")

    # Last modifications in container files and EPUB creation
    if len(annotations) > 0:
        toc.add("Przypisy", "annotations.html")
        manifest.append(etree.fromstring(
            '<item id="annotations" href="annotations.html" media-type="application/xhtml+xml" />'))
        spine.append(etree.fromstring(
            '<itemref idref="annotations" />'))
        replace_by_verse(annotations)
        html_tree = xslt(annotations, get_resource('epub/xsltAnnotations.xsl'))
        chars = chars.union(used_chars(html_tree.getroot()))
        zip.writestr('OPS/annotations.html', etree.tostring(
            html_tree, pretty_print=True, xml_declaration=True,
            encoding="utf-8",
            doctype='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" ' +
                    '"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
        ))

    toc.add("Wesprzyj Wolne Lektury", "support.html")
    manifest.append(etree.fromstring(
        '<item id="support" href="support.html" media-type="application/xhtml+xml" />'))
    spine.append(etree.fromstring(
        '<itemref idref="support" />'))
    html_string = open(get_resource('epub/support.html')).read()
    chars.update(used_chars(etree.fromstring(html_string)))
    zip.writestr('OPS/support.html', html_string)

    toc.add("Strona redakcyjna", "last.html")
    manifest.append(etree.fromstring(
        '<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'))
    chars.update(used_chars(html_tree.getroot()))
    zip.writestr('OPS/last.html', etree.tostring(
        html_tree, pretty_print=True, xml_declaration=True,
        encoding="utf-8",
        doctype='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" ' +
                '"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
    ))

    if not flags or not 'without-fonts' in flags:
        # strip fonts
        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'))
        for fname in 'DejaVuSerif.ttf', 'DejaVuSerif-Bold.ttf', 'DejaVuSerif-Italic.ttf', 'DejaVuSerif-BoldItalic.ttf':
            optimizer_call = ['perl', 'subset.pl', '--chars',
                              ''.join(chars).encode('utf-8'),
                              get_resource('fonts/' + fname),
                              os.path.join(tmpdir, fname)]
            if verbose:
                print "Running font-optimizer"
                subprocess.check_call(optimizer_call)
            else:
                subprocess.check_call(optimizer_call, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            zip.write(os.path.join(tmpdir, fname), os.path.join('OPS', fname))
            manifest.append(etree.fromstring(
                '<item id="%s" href="%s" media-type="application/x-font-truetype" />' % (fname, fname)))
        rmtree(tmpdir)
        if cwd is not None:
            os.chdir(cwd)
    zip.writestr('OPS/content.opf', etree.tostring(opf, pretty_print=True,
                 xml_declaration=True, encoding="utf-8"))
    title = document.book_info.title
    attributes = "dtb:uid", "dtb:depth", "dtb:totalPageCount", "dtb:maxPageNumber"
    for st in attributes:
        meta = toc_file.makeelement(NCXNS('meta'))
        meta.set('name', st)
        meta.set('content', '0')
        toc_file[0].append(meta)
    toc_file[0][0].set('content', str(document.book_info.url))
    toc_file[0][1].set('content', str(toc.depth()))
    set_inner_xml(toc_file[1], ''.join(('<text>', title, '</text>')))

    # write TOC
    if html_toc:
        toc.add(u"Spis treści", "toc.html", index=1)
        zip.writestr('OPS/toc.html', toc.html().encode('utf-8'))
    toc.write_to_xml(nav_map)
    zip.writestr('OPS/toc.ncx', etree.tostring(toc_file, pretty_print=True,
                 xml_declaration=True, encoding="utf-8"))
    zip.close()

    return OutputFile.from_filename(output_file.name)
Ejemplo n.º 23
0
def transform(wldoc,
              verbose=False,
              save_tex=None,
              morefloats=None,
              cover=None,
              flags=None,
              customizations=None,
              ilustr_path='',
              latex_dir=False):
    """ produces a PDF file with XeLaTeX

    wldoc: a WLDocument
    verbose: prints all output from LaTeX
    save_tex: path to save the intermediary LaTeX file to
    morefloats (old/new/none): force specific morefloats
    cover: a cover.Cover factory or True for default
    flags: less-advertising,
    customizations: user requested customizations regarding various formatting parameters (passed to wl LaTeX class)
    """

    # Parse XSLT
    try:
        book_info = wldoc.book_info
        document = load_including_children(wldoc)
        root = document.edoc.getroot()

        if cover:
            if cover is True:
                cover = make_cover
            bound_cover = cover(book_info, width=1200)
            root.set('data-cover-width', str(bound_cover.width))
            root.set('data-cover-height', str(bound_cover.height))
            if bound_cover.uses_dc_cover:
                if book_info.cover_by:
                    root.set('data-cover-by', book_info.cover_by)
                if book_info.cover_source:
                    root.set('data-cover-source', book_info.cover_source)
        if flags:
            for flag in flags:
                root.set('flag-' + flag, 'yes')

        # check for LaTeX packages
        if morefloats:
            root.set('morefloats', morefloats.lower())
        elif package_available('morefloats', 'maxfloats=19'):
            root.set('morefloats', 'new')

        # add customizations
        if customizations is not None:
            root.set('customizations', u','.join(customizations))

        # add editors info
        editors = document.editors()
        if editors:
            root.set(
                'editors',
                u', '.join(sorted(editor.readable() for editor in editors)))
        if document.book_info.funders:
            root.set('funders', u', '.join(document.book_info.funders))
        if document.book_info.thanks:
            root.set('thanks', document.book_info.thanks)

        # hack the tree
        move_motifs_inside(document.edoc)
        hack_motifs(document.edoc)
        parse_creator(document.edoc)
        substitute_hyphens(document.edoc)
        fix_hanging(document.edoc)
        fix_tables(document.edoc)
        mark_subauthors(document.edoc)

        # wl -> TeXML
        style_filename = get_stylesheet("wl2tex")
        style = etree.parse(style_filename)
        functions.reg_mathml_latex()

        # TeXML -> LaTeX
        temp = mkdtemp('-wl2pdf')

        for ilustr in document.edoc.findall("//ilustr"):
            shutil.copy(os.path.join(ilustr_path, ilustr.get("src")), temp)

        for sponsor in book_info.sponsors:
            ins = etree.Element("data-sponsor", name=sponsor)
            logo = sponsor_logo(sponsor)
            if logo:
                fname = 'sponsor-%s' % os.path.basename(logo)
                shutil.copy(logo, os.path.join(temp, fname))
                ins.set('src', fname)
            root.insert(0, ins)

        if book_info.sponsor_note:
            root.set("sponsor-note", book_info.sponsor_note)

        texml = document.transform(style)

        if cover:
            with open(os.path.join(temp, 'cover.png'), 'w') as f:
                bound_cover.save(f, quality=80)

        del document  # no longer needed large object :)

        tex_path = os.path.join(temp, 'doc.tex')
        fout = open(tex_path, 'wb')
        process(six.BytesIO(texml), fout, 'utf-8')
        fout.close()
        del texml

        if save_tex:
            shutil.copy(tex_path, save_tex)

        # LaTeX -> PDF
        shutil.copy(get_resource('pdf/wl.cls'), temp)
        shutil.copy(get_resource('res/wl-logo.png'), temp)

        if latex_dir:
            return temp

        try:
            cwd = os.getcwd()
        except OSError:
            cwd = None
        os.chdir(temp)

        # some things work better when compiled twice
        # (table of contents, [line numbers - disabled])
        for run in range(2):
            if verbose:
                p = call(['xelatex', tex_path])
            else:
                p = call(['xelatex', '-interaction=batchmode', tex_path],
                         stdout=PIPE,
                         stderr=PIPE)
            if p:
                raise ParseError("Error parsing .tex file")

        if cwd is not None:
            os.chdir(cwd)

        output_file = NamedTemporaryFile(prefix='librarian',
                                         suffix='.pdf',
                                         delete=False)
        pdf_path = os.path.join(temp, 'doc.pdf')
        shutil.move(pdf_path, output_file.name)
        shutil.rmtree(temp)
        return OutputFile.from_filename(output_file.name)

    except (XMLSyntaxError, XSLTApplyError) as e:
        raise ParseError(e)
Ejemplo n.º 24
0
 def html(self):
     with open(get_resource('epub/toc.html')) as f:
         t = unicode(f.read(), 'utf-8')
     return t % self.html_part()
Ejemplo n.º 25
0
 def html(self):
     with open(get_resource('epub/toc.html'), 'rb') as f:
         t = f.read().decode('utf-8')
     return t % self.html_part()
Ejemplo n.º 26
0
def get_stylesheet(name):
    return get_resource(STYLESHEETS[name])
Ejemplo n.º 27
0
def transform(wldoc, verbose=False, save_tex=None, morefloats=None,
              cover=None, flags=None, customizations=None):
    """ produces a PDF file with XeLaTeX

    wldoc: a WLDocument
    verbose: prints all output from LaTeX
    save_tex: path to save the intermediary LaTeX file to
    morefloats (old/new/none): force specific morefloats
    cover: a cover.Cover factory or True for default
    flags: less-advertising,
    customizations: user requested customizations regarding various formatting parameters (passed to wl LaTeX class)
    """

    # Parse XSLT
    try:
        book_info = wldoc.book_info
        document = load_including_children(wldoc)
        root = document.edoc.getroot()

        if cover:
            if cover is True:
                cover = DefaultEbookCover
            bound_cover = cover(book_info, width=1200)
            root.set('data-cover-width', str(bound_cover.width))
            root.set('data-cover-height', str(bound_cover.height))
            if bound_cover.uses_dc_cover:
                if book_info.cover_by:
                    root.set('data-cover-by', book_info.cover_by)
                if book_info.cover_source:
                    root.set('data-cover-source',
                            book_info.cover_source)
        if flags:
            for flag in flags:
                root.set('flag-' + flag, 'yes')

        # check for LaTeX packages
        if morefloats:
            root.set('morefloats', morefloats.lower())
        elif package_available('morefloats', 'maxfloats=19'):
            root.set('morefloats', 'new')

        # add customizations
        if customizations is not None:
            root.set('customizations', u','.join(customizations))

        # add editors info
        editors = document.editors()
        if editors:
            root.set('editors', u', '.join(sorted(
                editor.readable() for editor in editors)))
        if document.book_info.funders:
            root.set('funders', u', '.join(document.book_info.funders))
        if document.book_info.thanks:
            root.set('thanks', document.book_info.thanks)

        # hack the tree
        move_motifs_inside(document.edoc)
        hack_motifs(document.edoc)
        parse_creator(document.edoc)
        substitute_hyphens(document.edoc)
        fix_hanging(document.edoc)
        fix_tables(document.edoc)

        # wl -> TeXML
        style_filename = get_stylesheet("wl2tex")
        style = etree.parse(style_filename)
        functions.reg_mathml_latex()

        # TeXML -> LaTeX
        temp = mkdtemp('-wl2pdf')

        for sponsor in book_info.sponsors:
            ins = etree.Element("data-sponsor", name=sponsor)
            logo = sponsor_logo(sponsor)
            if logo:
                fname = 'sponsor-%s' % os.path.basename(logo)
                shutil.copy(logo, os.path.join(temp, fname))
                ins.set('src', fname)
            root.insert(0, ins)
                
        if book_info.sponsor_note:
            root.set("sponsor-note", book_info.sponsor_note)

        texml = document.transform(style)

        if cover:
            with open(os.path.join(temp, 'cover.png'), 'w') as f:
                bound_cover.save(f, quality=80)

        del document # no longer needed large object :)

        tex_path = os.path.join(temp, 'doc.tex')
        fout = open(tex_path, 'w')
        process(StringIO(texml), fout, 'utf-8')
        fout.close()
        del texml

        if save_tex:
            shutil.copy(tex_path, save_tex)

        # LaTeX -> PDF
        shutil.copy(get_resource('pdf/wl.cls'), temp)
        shutil.copy(get_resource('res/wl-logo.png'), temp)

        try:
            cwd = os.getcwd()
        except OSError:
            cwd = None
        os.chdir(temp)

        if verbose:
            p = call(['xelatex', tex_path])
        else:
            p = call(['xelatex', '-interaction=batchmode', tex_path], stdout=PIPE, stderr=PIPE)
        if p:
            raise ParseError("Error parsing .tex file")

        if cwd is not None:
            os.chdir(cwd)

        output_file = NamedTemporaryFile(prefix='librarian', suffix='.pdf', delete=False)
        pdf_path = os.path.join(temp, 'doc.pdf')
        shutil.move(pdf_path, output_file.name)
        shutil.rmtree(temp)
        return OutputFile.from_filename(output_file.name)

    except (XMLSyntaxError, XSLTApplyError), e:
        raise ParseError(e)
Ejemplo n.º 28
0
 def to_latex(self):
     xslt = etree.parse(get_resource('res/embeds/mathml/mathml2latex.xslt'))
     output = self.tree.xslt(xslt)
     return create_embed('application/x-latex', data=unicode(output))
Ejemplo n.º 29
0
def transform(wldoc, verbose=False, style=None, html_toc=False,
              sample=None, cover=None, flags=None, hyphenate=False, ilustr_path='', 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):
        """ processes one input file and proceeds to its children """

        replace_characters(wldoc.edoc.getroot())

        hyphenator = set_hyph_language(wldoc.edoc.getroot()) if hyphenate else None
        hyphenate_and_fix_conjunctions(wldoc.edoc.getroot(), hyphenator)

        # every input file will have a TOC entry,
        # pointing to starting chunk
        toc = TOC(wldoc.book_info.title, "part%d.html" % chunk_counter)
        chars = set()
        if first:
            # write book title page
            html_tree = xslt(wldoc.edoc, get_resource('epub/xsltTitle.xsl'), outputtype=output_type)
            chars = used_chars(html_tree.getroot())
            zip.writestr(
                'OPS/title.html',
                etree.tostring(
                    html_tree, pretty_print=True, xml_declaration=True,
                    encoding="utf-8",
                    doctype='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"' +
                            ' "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
                )
            )
            # add a title page TOC entry
            toc.add(u"Strona tytułowa", "title.html")
        elif wldoc.book_info.parts:
            # write title page for every parent
            if sample is not None and sample <= 0:
                chars = set()
                html_string = open(get_resource('epub/emptyChunk.html')).read()
            else:
                html_tree = xslt(wldoc.edoc, get_resource('epub/xsltChunkTitle.xsl'))
                chars = used_chars(html_tree.getroot())
                html_string = etree.tostring(
                    html_tree, pretty_print=True, xml_declaration=True,
                    encoding="utf-8",
                    doctype='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"' +
                            ' "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
                )
            zip.writestr('OPS/part%d.html' % chunk_counter, html_string)
            add_to_manifest(manifest, chunk_counter)
            add_to_spine(spine, chunk_counter)
            chunk_counter += 1

        if len(wldoc.edoc.getroot()) > 1:
            # rdf before style master
            main_text = wldoc.edoc.getroot()[1]
        else:
            # rdf in style master
            main_text = wldoc.edoc.getroot()[0]
            if main_text.tag == RDFNS('RDF'):
                main_text = None

        if main_text is not None:
            for chunk_xml in chop(main_text):
                empty = False
                if sample is not None:
                    if sample <= 0:
                        empty = True
                    else:
                        sample -= len(chunk_xml.xpath('//strofa|//akap|//akap_cd|//akap_dialog'))
                chunk_html, chunk_toc, chunk_chars = transform_chunk(chunk_xml, chunk_counter, annotations, empty)

                toc.extend(chunk_toc)
                chars = chars.union(chunk_chars)
                zip.writestr('OPS/part%d.html' % chunk_counter, chunk_html)
                add_to_manifest(manifest, chunk_counter)
                add_to_spine(spine, chunk_counter)
                chunk_counter += 1

        for child in wldoc.parts():
            child_toc, chunk_counter, chunk_chars, sample = transform_file(
                child, chunk_counter, first=False, sample=sample)
            toc.append(child_toc)
            chars = chars.union(chunk_chars)

        return toc, chunk_counter, chars, sample

    document = deepcopy(wldoc)
    del wldoc

    if flags:
        for flag in flags:
            document.edoc.getroot().set(flag, 'yes')

    document.clean_ed_note()
    document.clean_ed_note('abstrakt')

    # add editors info
    editors = document.editors()
    if editors:
        document.edoc.getroot().set('editors', u', '.join(sorted(
            editor.readable() for editor in editors)))
    if document.book_info.funders:
        document.edoc.getroot().set('funders', u', '.join(
            document.book_info.funders))
    if document.book_info.thanks:
        document.edoc.getroot().set('thanks', document.book_info.thanks)

    opf = xslt(document.book_info.to_etree(), get_resource('epub/xsltContent.xsl'))
    manifest = opf.find('.//' + OPFNS('manifest'))
    guide = opf.find('.//' + OPFNS('guide'))
    spine = opf.find('.//' + OPFNS('spine'))

    output_file = NamedTemporaryFile(prefix='librarian', suffix='.epub', delete=False)
    zip = zipfile.ZipFile(output_file, 'w', zipfile.ZIP_DEFLATED)

    functions.reg_mathml_epub(zip)

    if os.path.isdir(ilustr_path):
        for i, filename in enumerate(os.listdir(ilustr_path)):
            file_path = os.path.join(ilustr_path, filename)
            zip.write(file_path, os.path.join('OPS', filename))
            image_id = 'image%s' % i
            manifest.append(etree.fromstring(
                '<item id="%s" href="%s" media-type="%s" />' % (image_id, filename, guess_type(file_path)[0])))

    # write static elements
    mime = zipfile.ZipInfo()
    mime.filename = 'mimetype'
    mime.compress_type = zipfile.ZIP_STORED
    mime.extra = ''
    zip.writestr(mime, 'application/epub+zip')
    zip.writestr(
        'META-INF/container.xml',
        '<?xml version="1.0" ?>'
        '<container version="1.0" '
        'xmlns="urn:oasis:names:tc:opendocument:xmlns:container">'
        '<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 style:
        style = get_resource('epub/style.css')
    zip.write(style, os.path.join('OPS', 'style.css'))

    if cover:
        if cover is True:
            cover = DefaultEbookCover

        cover_file = StringIO()
        bound_cover = cover(document.book_info)
        bound_cover.save(cover_file)
        cover_name = 'cover.%s' % bound_cover.ext()
        zip.writestr(os.path.join('OPS', cover_name), cover_file.getvalue())
        del cover_file

        cover_tree = etree.parse(get_resource('epub/cover.html'))
        cover_tree.find('//' + XHTMLNS('img')).set('src', cover_name)
        zip.writestr('OPS/cover.html', etree.tostring(
            cover_tree, pretty_print=True, xml_declaration=True,
            encoding="utf-8",
            doctype='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" ' +
                    '"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
        ))

        if bound_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)

        manifest.append(etree.fromstring(
            '<item id="cover" href="cover.html" media-type="application/xhtml+xml" />'))
        manifest.append(etree.fromstring(
            '<item id="cover-image" href="%s" media-type="%s" />' % (cover_name, bound_cover.mime_type())))
        spine.insert(0, etree.fromstring('<itemref idref="cover"/>'))
        opf.getroot()[0].append(etree.fromstring('<meta name="cover" content="cover-image"/>'))
        guide.append(etree.fromstring('<reference href="cover.html" type="cover" title="Okładka"/>'))

    annotations = etree.Element('annotations')

    toc_file = etree.fromstring(
        '<?xml version="1.0" encoding="utf-8"?><!DOCTYPE ncx PUBLIC '
        '"-//NISO//DTD ncx 2005-1//EN" '
        '"http://www.daisy.org/z3986/2005/ncx-2005-1.dtd">'
        '<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" xml:lang="pl" '
        'version="2005-1"><head></head><docTitle></docTitle><navMap>'
        '</navMap></ncx>'
    )
    nav_map = toc_file[-1]

    if html_toc:
        manifest.append(etree.fromstring(
            '<item id="html_toc" href="toc.html" media-type="application/xhtml+xml" />'))
        spine.append(etree.fromstring(
            '<itemref idref="html_toc" />'))
        guide.append(etree.fromstring('<reference href="toc.html" type="toc" title="Spis treści"/>'))

    toc, chunk_counter, chars, sample = transform_file(document, sample=sample)

    if len(toc.children) < 2:
        toc.add(u"Początek utworu", "part1.html")

    # Last modifications in container files and EPUB creation
    if len(annotations) > 0:
        toc.add("Przypisy", "annotations.html")
        manifest.append(etree.fromstring(
            '<item id="annotations" href="annotations.html" media-type="application/xhtml+xml" />'))
        spine.append(etree.fromstring(
            '<itemref idref="annotations" />'))
        replace_by_verse(annotations)
        html_tree = xslt(annotations, get_resource('epub/xsltAnnotations.xsl'))
        chars = chars.union(used_chars(html_tree.getroot()))
        zip.writestr('OPS/annotations.html', etree.tostring(
            html_tree, pretty_print=True, xml_declaration=True,
            encoding="utf-8",
            doctype='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" ' +
                    '"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
        ))

    toc.add("Wesprzyj Wolne Lektury", "support.html")
    manifest.append(etree.fromstring(
        '<item id="support" href="support.html" media-type="application/xhtml+xml" />'))
    spine.append(etree.fromstring(
        '<itemref idref="support" />'))
    html_string = open(get_resource('epub/support.html')).read()
    chars.update(used_chars(etree.fromstring(html_string)))
    zip.writestr('OPS/support.html', html_string)

    toc.add("Strona redakcyjna", "last.html")
    manifest.append(etree.fromstring(
        '<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'), outputtype=output_type)
    chars.update(used_chars(html_tree.getroot()))
    zip.writestr('OPS/last.html', etree.tostring(
        html_tree, pretty_print=True, xml_declaration=True,
        encoding="utf-8",
        doctype='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" ' +
                '"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
    ))

    if not flags or 'without-fonts' not in flags:
        # strip fonts
        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'))
        for fname in 'DejaVuSerif.ttf', 'DejaVuSerif-Bold.ttf', 'DejaVuSerif-Italic.ttf', 'DejaVuSerif-BoldItalic.ttf':
            optimizer_call = ['perl', 'subset.pl', '--chars',
                              ''.join(chars).encode('utf-8'),
                              get_resource('fonts/' + fname),
                              os.path.join(tmpdir, fname)]
            if verbose:
                print "Running font-optimizer"
                subprocess.check_call(optimizer_call)
            else:
                dev_null = open(os.devnull, 'w')
                subprocess.check_call(optimizer_call, stdout=dev_null, stderr=dev_null)
            zip.write(os.path.join(tmpdir, fname), os.path.join('OPS', fname))
            manifest.append(etree.fromstring(
                '<item id="%s" href="%s" media-type="application/x-font-truetype" />' % (fname, fname)))
        rmtree(tmpdir)
        if cwd is not None:
            os.chdir(cwd)
    zip.writestr('OPS/content.opf', etree.tostring(opf, pretty_print=True,
                 xml_declaration=True, encoding="utf-8"))
    title = document.book_info.title
    attributes = "dtb:uid", "dtb:depth", "dtb:totalPageCount", "dtb:maxPageNumber"
    for st in attributes:
        meta = toc_file.makeelement(NCXNS('meta'))
        meta.set('name', st)
        meta.set('content', '0')
        toc_file[0].append(meta)
    toc_file[0][0].set('content', str(document.book_info.url))
    toc_file[0][1].set('content', str(toc.depth()))
    set_inner_xml(toc_file[1], ''.join(('<text>', title, '</text>')))

    # write TOC
    if html_toc:
        toc.add(u"Spis treści", "toc.html", index=1)
        zip.writestr('OPS/toc.html', toc.html().encode('utf-8'))
    toc.write_to_xml(nav_map)
    zip.writestr('OPS/toc.ncx', etree.tostring(toc_file, pretty_print=True,
                 xml_declaration=True, encoding="utf-8"))
    zip.close()

    return OutputFile.from_filename(output_file.name)
Ejemplo n.º 30
0
    def transform_file(wldoc, chunk_counter=1, first=True, sample=None):
        """ processes one input file and proceeds to its children """

        replace_characters(wldoc.edoc.getroot())

        hyphenator = set_hyph_language(wldoc.edoc.getroot()) if hyphenate else None
        hyphenate_and_fix_conjunctions(wldoc.edoc.getroot(), hyphenator)

        # every input file will have a TOC entry,
        # pointing to starting chunk
        toc = TOC(wldoc.book_info.title, "part%d.html" % chunk_counter)
        chars = set()
        if first:
            # write book title page
            html_tree = xslt(wldoc.edoc, get_resource('epub/xsltTitle.xsl'), outputtype=output_type)
            chars = used_chars(html_tree.getroot())
            zip.writestr(
                'OPS/title.html',
                etree.tostring(
                    html_tree, pretty_print=True, xml_declaration=True,
                    encoding="utf-8",
                    doctype='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"' +
                            ' "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
                )
            )
            # add a title page TOC entry
            toc.add(u"Strona tytułowa", "title.html")
        elif wldoc.book_info.parts:
            # write title page for every parent
            if sample is not None and sample <= 0:
                chars = set()
                html_string = open(get_resource('epub/emptyChunk.html')).read()
            else:
                html_tree = xslt(wldoc.edoc, get_resource('epub/xsltChunkTitle.xsl'))
                chars = used_chars(html_tree.getroot())
                html_string = etree.tostring(
                    html_tree, pretty_print=True, xml_declaration=True,
                    encoding="utf-8",
                    doctype='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"' +
                            ' "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
                )
            zip.writestr('OPS/part%d.html' % chunk_counter, html_string)
            add_to_manifest(manifest, chunk_counter)
            add_to_spine(spine, chunk_counter)
            chunk_counter += 1

        if len(wldoc.edoc.getroot()) > 1:
            # rdf before style master
            main_text = wldoc.edoc.getroot()[1]
        else:
            # rdf in style master
            main_text = wldoc.edoc.getroot()[0]
            if main_text.tag == RDFNS('RDF'):
                main_text = None

        if main_text is not None:
            for chunk_xml in chop(main_text):
                empty = False
                if sample is not None:
                    if sample <= 0:
                        empty = True
                    else:
                        sample -= len(chunk_xml.xpath('//strofa|//akap|//akap_cd|//akap_dialog'))
                chunk_html, chunk_toc, chunk_chars = transform_chunk(chunk_xml, chunk_counter, annotations, empty)

                toc.extend(chunk_toc)
                chars = chars.union(chunk_chars)
                zip.writestr('OPS/part%d.html' % chunk_counter, chunk_html)
                add_to_manifest(manifest, chunk_counter)
                add_to_spine(spine, chunk_counter)
                chunk_counter += 1

        for child in wldoc.parts():
            child_toc, chunk_counter, chunk_chars, sample = transform_file(
                child, chunk_counter, first=False, sample=sample)
            toc.append(child_toc)
            chars = chars.union(chunk_chars)

        return toc, chunk_counter, chars, sample
Ejemplo n.º 31
0
    def image(self):
        metr = Metric(self, self.scale)
        img = Image.new('RGB', (metr.width, metr.height), self.background_color)
        draw = ImageDraw.Draw(img)

        if self.epoch in self.epoch_colors:
            epoch_color = self.epoch_colors[self.epoch]
        else:
            epoch_color = '#000'
        draw.rectangle((0, 0, metr.bar_width, metr.height), fill=epoch_color)

        if self.background_img:
            src = Image.open(self.background_img)
            trg_size = (metr.width - metr.bar_width, metr.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, Image.ANTIALIAS)
                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, Image.ANTIALIAS)
                src = src.crop((cut, 0, src.size[0] - cut, src.size[1]))

            img.paste(src, (metr.bar_width, 0))
            del src

        box = TextBox(metr.title_box_width, metr.height, padding_y=metr.box_padding_y)
        author_font = ImageFont.truetype(
            self.author_font_ttf, metr.author_font_size)
        box.text(self.pretty_author(),
                 font=author_font,
                 line_height=metr.author_lineskip,
                 color=self.author_color,
                 shadow_color=self.author_shadow,
                )

        box.skip(metr.box_above_line)
        box.draw.line((metr.box_line_left, box.height, metr.box_line_right, box.height),
                fill=self.author_color, width=metr.box_line_width)
        box.skip(metr.box_below_line)

        title_font = ImageFont.truetype(
            self.title_font_ttf, metr.title_font_size)
        box.text(self.pretty_title(),
                 line_height=metr.title_lineskip,
                 font=title_font,
                 color=epoch_color,
                 shadow_color=self.title_shadow,
                )

        if self.with_logo:
            logo = Image.open(get_resource('res/wl-logo-mono.png'))
            logo = logo.resize((metr.logo_width, logo.size[1] * metr.logo_width / logo.size[0]), Image.ANTIALIAS)
            alpha = logo.split()[3]
            alpha = ImageEnhance.Brightness(alpha).enhance(.75)
            logo.putalpha(alpha)
            box.skip(metr.logo_top + logo.size[1])

        box_img = box.image()

        if self.kind == 'Liryka':
            # top
            box_top = metr.box_top_margin
        elif self.kind == 'Epika':
            # bottom
            box_top = metr.height - metr.box_bottom_margin - box_img.size[1]
        else:
            # center
            box_top = (metr.height - box_img.size[1]) / 2

        box_left = metr.bar_width + (metr.width - metr.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)

        if self.with_logo:
            img.paste(logo, 
                (box_left + (box_img.size[0] - logo.size[0]) / 2,
                    box_top + box_img.size[1] - metr.box_padding_y - logo.size[1]), mask=logo)

        return img
Ejemplo n.º 32
0
 def html(self):
     with open(get_resource('epub/toc.html')) as f:
         t = unicode(f.read(), 'utf-8')
     return t % self.html_part()
Ejemplo n.º 33
0
class Cover(object):
    """Abstract base class for cover images generator."""
    width = 600
    height = 800
    background_color = '#fff'
    background_img = None

    author_top = 100
    author_margin_left = 20
    author_margin_right = 20
    author_lineskip = 40
    author_color = '#000'
    author_shadow = None
    author_font_ttf = get_resource('fonts/DejaVuSerif.ttf')
    author_font_size = 30

    title_top = 100
    title_margin_left = 20
    title_margin_right = 20
    title_lineskip = 54
    title_color = '#000'
    title_shadow = None
    title_font_ttf = get_resource('fonts/DejaVuSerif.ttf')
    title_font_size = 40

    logo_bottom = None
    logo_width = None
    uses_dc_cover = False

    format = 'JPEG'
    scale = 1
    scale_after = 1

    exts = {
        'JPEG': 'jpg',
        'PNG': 'png',
    }

    mime_types = {
        'JPEG': 'image/jpeg',
        'PNG': 'image/png',
    }

    def __init__(self, book_info, format=None, width=None, height=None):
        self.author = ", ".join(auth.readable() for auth in book_info.authors)
        self.title = book_info.title
        if format is not None:
            self.format = format
        if width and height:
            self.height = height * self.width / width
        scale = max(
            float(width or 0) / self.width,
            float(height or 0) / self.height)
        if scale >= 1:
            self.scale = scale
        elif scale:
            self.scale_after = scale

    def pretty_author(self):
        """Allows for decorating author's name."""
        return self.author

    def pretty_title(self):
        """Allows for decorating title."""
        return self.title

    def image(self):
        metr = Metric(self, self.scale)
        img = Image.new('RGB', (metr.width, metr.height),
                        self.background_color)

        if self.background_img:
            background = Image.open(self.background_img)
            img.paste(background, None, background)
            del background

        # WL logo
        if metr.logo_width:
            logo = Image.open(get_resource('res/wl-logo.png'))
            logo = logo.resize((metr.logo_width,
                                logo.size[1] * metr.logo_width / logo.size[0]))
            img.paste(logo, ((metr.width - metr.logo_width) / 2,
                             img.size[1] - logo.size[1] - metr.logo_bottom))

        top = metr.author_top
        tbox = TextBox(
            metr.width - metr.author_margin_left - metr.author_margin_right,
            metr.height - top,
        )

        author_font = ImageFont.truetype(self.author_font_ttf,
                                         metr.author_font_size)
        tbox.text(self.pretty_author(), self.author_color, author_font,
                  metr.author_lineskip, self.author_shadow)
        text_img = tbox.image()
        img.paste(text_img, (metr.author_margin_left, top), text_img)

        top += text_img.size[1] + metr.title_top
        tbox = TextBox(
            metr.width - metr.title_margin_left - metr.title_margin_right,
            metr.height - top,
        )
        title_font = ImageFont.truetype(self.title_font_ttf,
                                        metr.title_font_size)
        tbox.text(self.pretty_title(), self.title_color, title_font,
                  metr.title_lineskip, self.title_shadow)
        text_img = tbox.image()
        img.paste(text_img, (metr.title_margin_left, top), text_img)

        return img

    def final_image(self):
        img = self.image()
        if self.scale_after != 1:
            img = img.resize((int(round(img.size[0] * self.scale_after)),
                              int(round(img.size[1] * self.scale_after))),
                             Image.ANTIALIAS)
        return img

    def mime_type(self):
        return self.mime_types[self.format]

    def ext(self):
        return self.exts[self.format]

    def save(self, *args, **kwargs):
        default_kwargs = {
            'format': self.format,
            'quality': 95,
        }
        default_kwargs.update(kwargs)
        return self.final_image().save(*args, **default_kwargs)

    def output_file(self, *args, **kwargs):
        imgstr = StringIO()
        self.save(imgstr, *args, **kwargs)
        return OutputFile.from_string(imgstr.getvalue())
Ejemplo n.º 34
0
    def transform_file(wldoc, chunk_counter=1, first=True, sample=None):
        """ processes one input file and proceeds to its children """

        replace_characters(wldoc.edoc.getroot())

        hyphenator = set_hyph_language(wldoc.edoc.getroot())
        hyphenate_and_fix_conjunctions(wldoc.edoc.getroot(), hyphenator)

        # every input file will have a TOC entry,
        # pointing to starting chunk
        toc = TOC(wldoc.book_info.title, "part%d.html" % chunk_counter)
        chars = set()
        if first:
            # write book title page
            html_tree = xslt(wldoc.edoc, get_resource('epub/xsltTitle.xsl'))
            chars = used_chars(html_tree.getroot())
            zip.writestr(
                'OPS/title.html',
                etree.tostring(
                    html_tree, pretty_print=True, xml_declaration=True,
                    encoding="utf-8",
                    doctype='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"' +
                            ' "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
                )
            )
            # add a title page TOC entry
            toc.add(u"Strona tytułowa", "title.html")
        elif wldoc.book_info.parts:
            # write title page for every parent
            if sample is not None and sample <= 0:
                chars = set()
                html_string = open(get_resource('epub/emptyChunk.html')).read()
            else:
                html_tree = xslt(wldoc.edoc, get_resource('epub/xsltChunkTitle.xsl'))
                chars = used_chars(html_tree.getroot())
                html_string = etree.tostring(
                    html_tree, pretty_print=True, xml_declaration=True,
                    encoding="utf-8",
                    doctype='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"' +
                            ' "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
                )
            zip.writestr('OPS/part%d.html' % chunk_counter, html_string)
            add_to_manifest(manifest, chunk_counter)
            add_to_spine(spine, chunk_counter)
            chunk_counter += 1

        if len(wldoc.edoc.getroot()) > 1:
            # rdf before style master
            main_text = wldoc.edoc.getroot()[1]
        else:
            # rdf in style master
            main_text = wldoc.edoc.getroot()[0]
            if main_text.tag == RDFNS('RDF'):
                main_text = None

        if main_text is not None:
            for chunk_xml in chop(main_text):
                empty = False
                if sample is not None:
                    if sample <= 0:
                        empty = True
                    else:
                        sample -= len(chunk_xml.xpath('//strofa|//akap|//akap_cd|//akap_dialog'))
                chunk_html, chunk_toc, chunk_chars = transform_chunk(chunk_xml, chunk_counter, annotations, empty)

                toc.extend(chunk_toc)
                chars = chars.union(chunk_chars)
                zip.writestr('OPS/part%d.html' % chunk_counter, chunk_html)
                add_to_manifest(manifest, chunk_counter)
                add_to_spine(spine, chunk_counter)
                chunk_counter += 1

        for child in wldoc.parts():
            child_toc, chunk_counter, chunk_chars, sample = transform_file(
                child, chunk_counter, first=False, sample=sample)
            toc.append(child_toc)
            chars = chars.union(chunk_chars)

        return toc, chunk_counter, chars, sample
Ejemplo n.º 35
0
def get_stylesheet(name):
    return get_resource(STYLESHEETS[name])
Ejemplo n.º 36
0
def sponsor_logo(name):
    return {
        'Narodowe Centrum Kultury': get_resource('res/sponsors/nck.png')
    }.get(name.strip())
Ejemplo n.º 37
0
class WLCover(Cover):
    """Wolne Lektury cover without logos."""
    width = 600
    height = 833
    uses_dc_cover = True
    author_font_ttf = get_resource('fonts/JunicodeWL-Regular.ttf')
    author_font_size = 20
    author_lineskip = 30
    title_font_ttf = get_resource('fonts/DejaVuSerif-Bold.ttf')
    title_font_size = 30
    title_lineskip = 40
    title_box_width = 350

    box_top_margin = 100
    box_bottom_margin = 100
    box_padding_y = 20
    box_above_line = 10
    box_below_line = 15
    box_line_left = 75
    box_line_right = 275
    box_line_width = 2

    logo_top = 15
    logo_width = 140

    bar_width = 35
    bar_color = '#000'
    box_position = 'middle'
    background_color = '#444'
    author_color = '#444'
    background_img = get_resource('res/cover.png')
    format = 'JPEG'

    epoch_colors = {
        u'Starożytność': '#9e3610',
        u'Średniowiecze': '#564c09',
        u'Renesans': '#8ca629',
        u'Barok': '#a6820a',
        u'Oświecenie': '#f2802e',
        u'Romantyzm': '#db4b16',
        u'Pozytywizm': '#961060',
        u'Modernizm': '#7784e0',
        u'Dwudziestolecie międzywojenne': '#3044cf',
        u'Współczesność': '#06393d',
    }

    kind_box_position = {
        u'Liryka': 'top',
        u'Epika': 'bottom',
    }

    def __init__(self,
                 book_info,
                 format=None,
                 width=None,
                 height=None,
                 bleed=0):
        super(WLCover, self).__init__(book_info,
                                      format=format,
                                      width=width,
                                      height=height)
        # Set box position.
        self.box_position = book_info.cover_box_position or \
            self.kind_box_position.get(book_info.kind, self.box_position)
        # Set bar color.
        if book_info.cover_bar_color == 'none':
            self.bar_width = 0
        else:
            self.bar_color = book_info.cover_bar_color or \
                self.epoch_colors.get(book_info.epoch, self.bar_color)
        # Set title color.
        self.title_color = self.epoch_colors.get(book_info.epoch,
                                                 self.title_color)

        self.bleed = bleed
        self.box_top_margin += bleed
        self.box_bottom_margin += bleed
        self.bar_width += bleed

        if book_info.cover_url:
            url = book_info.cover_url
            bg_src = None
            if bg_src is None:
                bg_src = URLOpener().open(url)
            self.background_img = StringIO(bg_src.read())
            bg_src.close()

    def pretty_author(self):
        return self.author.upper()

    def add_box(self, img):
        if self.box_position == 'none':
            return img

        metr = Metric(self, self.scale)

        # Write author name.
        box = TextBox(metr.title_box_width,
                      metr.height,
                      padding_y=metr.box_padding_y)
        author_font = ImageFont.truetype(self.author_font_ttf,
                                         metr.author_font_size)
        box.text(self.pretty_author(),
                 font=author_font,
                 line_height=metr.author_lineskip,
                 color=self.author_color,
                 shadow_color=self.author_shadow)

        box.skip(metr.box_above_line)
        box.draw.line(
            (metr.box_line_left, box.height, metr.box_line_right, box.height),
            fill=self.author_color,
            width=metr.box_line_width)
        box.skip(metr.box_below_line)

        # Write title.
        title_font = ImageFont.truetype(self.title_font_ttf,
                                        metr.title_font_size)
        box.text(self.pretty_title(),
                 line_height=metr.title_lineskip,
                 font=title_font,
                 color=self.title_color,
                 shadow_color=self.title_shadow)

        box_img = box.image()

        # Find box position.
        if self.box_position == 'top':
            box_top = metr.box_top_margin
        elif self.box_position == 'bottom':
            box_top = metr.height - metr.box_bottom_margin - box_img.size[1]
        else:  # Middle.
            box_top = (metr.height - box_img.size[1]) / 2

        box_left = metr.bar_width + (metr.width - metr.bar_width -
                                     box_img.size[0]) / 2

        # Draw the white box.
        ImageDraw.Draw(img).rectangle(
            (box_left, box_top, box_left + box_img.size[0],
             box_top + box_img.size[1]),
            fill='#fff')
        # Paste the contents into the white box.
        img.paste(box_img, (box_left, box_top), box_img)
        return img

    def add_cut_lines(self, img):
        line_ratio = 0.5
        if self.bleed == 0:
            return img
        metr = Metric(self, self.scale)
        draw = ImageDraw.Draw(img)
        for corner_x, corner_y in ((0, 0), (metr.width, 0), (0, metr.height),
                                   (metr.width, metr.height)):
            dir_x = 1 if corner_x == 0 else -1
            dir_y = 1 if corner_y == 0 else -1
            for offset in (-1, 0, 1):
                draw.line((corner_x, corner_y + dir_y * metr.bleed + offset,
                           corner_x + dir_x * metr.bleed * line_ratio,
                           corner_y + dir_y * metr.bleed + offset),
                          fill='black' if offset == 0 else 'white',
                          width=1)
                draw.line((corner_x + dir_x * metr.bleed + offset, corner_y,
                           corner_x + dir_x * metr.bleed + offset,
                           corner_y + dir_y * metr.bleed * line_ratio),
                          fill='black' if offset == 0 else 'white',
                          width=1)
        return img

    def image(self):
        metr = Metric(self, self.scale)
        img = Image.new('RGB', (metr.width, metr.height),
                        self.background_color)
        draw = ImageDraw.Draw(img)

        draw.rectangle((0, 0, metr.bar_width, metr.height),
                       fill=self.bar_color)

        if self.background_img:
            src = Image.open(self.background_img)
            trg_size = (metr.width - metr.bar_width, metr.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, Image.ANTIALIAS)
                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, Image.ANTIALIAS)
                src = src.crop((cut, 0, src.size[0] - cut, src.size[1]))

            img.paste(src, (metr.bar_width, 0))
            del src

        img = self.add_box(img)

        img = self.add_cut_lines(img)

        return img