From: Marcin Koziej Date: Wed, 7 Aug 2013 10:03:14 +0000 (+0200) Subject: Merge changes from master to Aigrain publishing code - that will be used for new... X-Git-Url: https://git.mdrn.pl/librarian.git/commitdiff_plain/f318053fb3349c5364cfb866b2a3d33c2423e12a?hp=-c Merge changes from master to Aigrain publishing code - that will be used for new publishing code for few publications Summer/Autumn 2013 --- f318053fb3349c5364cfb866b2a3d33c2423e12a diff --combined librarian/cover.py index 741436a,8b770ca..dfd451b --- a/librarian/cover.py +++ b/librarian/cover.py @@@ -4,8 -4,22 +4,22 @@@ # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # import re - import Image, ImageFont, ImageDraw, ImageFilter - from librarian import get_resource + from PIL import Image, ImageFont, ImageDraw, ImageFilter, ImageEnhance + from StringIO import StringIO + from librarian import get_resource, OutputFile, URLOpener + + + class Metric(object): + """Gets metrics from an object, scaling it by a factor.""" + def __init__(self, obj, scale): + self._obj = obj + self._scale = float(scale) + + def __getattr__(self, name): + src = getattr(self._obj, name) + if src and self._scale: + src = type(src)(self._scale * src) + return src class TextBox(object): @@@ -93,7 -107,8 +107,8 @@@ class Cover(object) author_lineskip = 40 author_color = '#000' author_shadow = None - author_font = None + author_font_ttf = get_resource('fonts/DejaVuSerif.ttf') + author_font_size = 30 title_top = 100 title_margin_left = 20 @@@ -101,13 -116,15 +116,15 @@@ title_lineskip = 54 title_color = '#000' title_shadow = None - title_font = 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 exts = { 'JPEG': 'jpg', @@@ -119,9 -136,14 +136,14 @@@ 'PNG': 'image/png', } - def __init__(self, book_info): - #self.author = ", ".join(auth.readable() for auth in book_info.authors) + 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 + scale = max(float(width or 0) / self.width, float(height or 0) / self.height) + if scale: + self.scale = scale def pretty_author(self): """Allows for decorating author's name.""" @@@ -132,7 -154,8 +154,8 @@@ return self.title def image(self): - img = Image.new('RGB', (self.width, self.height), self.background_color) + 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) @@@ -140,34 -163,35 +163,35 @@@ del background # WL logo - if self.logo_width: + if metr.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)) + 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 = self.author_top + top = metr.author_top tbox = TextBox( - self.width - self.author_margin_left - self.author_margin_right, - self.height - top, + metr.width - metr.author_margin_left - metr.author_margin_right, + metr.height - top, ) - author_font = self.author_font or ImageFont.truetype( - get_resource('fonts/DejaVuSerif.ttf'), 30) + + author_font = ImageFont.truetype( + self.author_font_ttf, metr.author_font_size) tbox.text(self.pretty_author(), self.author_color, author_font, - self.author_lineskip, self.author_shadow) + metr.author_lineskip, self.author_shadow) text_img = tbox.image() - img.paste(text_img, (self.author_margin_left, top), text_img) + img.paste(text_img, (metr.author_margin_left, top), text_img) - top += text_img.size[1] + self.title_top + top += text_img.size[1] + metr.title_top tbox = TextBox( - self.width - self.title_margin_left - self.title_margin_right, - self.height - top, + metr.width - metr.title_margin_left - metr.title_margin_right, + metr.height - top, ) - title_font = self.author_font or ImageFont.truetype( - get_resource('fonts/DejaVuSerif.ttf'), 40) + title_font = ImageFont.truetype( + self.title_font_ttf, metr.title_font_size) tbox.text(self.pretty_title(), self.title_color, title_font, - self.title_lineskip, self.title_shadow) + metr.title_lineskip, self.title_shadow) text_img = tbox.image() - img.paste(text_img, (self.title_margin_left, top), text_img) + img.paste(text_img, (metr.title_margin_left, top), text_img) return img @@@ -178,7 -202,12 +202,12 @@@ return self.exts[self.format] def save(self, *args, **kwargs): - return self.image().save(format=self.format, *args, **kwargs) + return self.image().save(format=self.format, quality=95, *args, **kwargs) + + def output_file(self, *args, **kwargs): + imgstr = StringIO() + self.save(imgstr, *args, **kwargs) + return OutputFile.from_string(imgstr.getvalue()) class WLCover(Cover): @@@ -186,13 -215,26 +215,26 @@@ width = 600 height = 833 uses_dc_cover = True - author_font = ImageFont.truetype( - get_resource('fonts/JunicodeWL-Regular.ttf'), 20) + author_font_ttf = get_resource('fonts/JunicodeWL-Regular.ttf') + author_font_size = 20 author_lineskip = 30 - title_font = ImageFont.truetype( - get_resource('fonts/DejaVuSerif-Bold.ttf'), 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 background_color = '#444' author_color = '#444' @@@ -212,16 -254,16 +254,15 @@@ u'Współczesność': '#06393d', } - def __init__(self, book_info): - super(WLCover, self).__init__(book_info) + def __init__(self, book_info, format=None, width=None, height=None, with_logo=False): + super(WLCover, self).__init__(book_info, format=format, width=width, height=height) self.kind = book_info.kind self.epoch = book_info.epoch - print book_info.cover_url - self.with_logo = with_logo if book_info.cover_url: - from urllib2 import urlopen - from StringIO import StringIO - - bg_src = urlopen(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() else: @@@ -231,25 -273,26 +272,26 @@@ return self.author.upper() def image(self): - img = Image.new('RGB', (self.width, self.height), self.background_color) + 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, self.bar_width, self.height), fill=epoch_color) + draw.rectangle((0, 0, metr.bar_width, metr.height), fill=epoch_color) if self.background_img: src = Image.open(self.background_img) - trg_size = (self.width - self.bar_width, self.height) + 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) + src = src.resize(resized, Image.ANTIALIAS) src = src.crop((0, cut, src.size[0], src.size[1] - cut)) else: resized = ( @@@ -257,52 -300,69 +299,69 @@@ trg_size[1], ) cut = (resized[0] - trg_size[0]) / 2 - src = src.resize(resized) + src = src.resize(resized, Image.ANTIALIAS) src = src.crop((cut, 0, src.size[0] - cut, src.size[1])) - img.paste(src, (self.bar_width, 0)) + img.paste(src, (metr.bar_width, 0)) del src - box = TextBox(self.title_box_width, self.height, padding_y=20) + 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=self.author_font, - line_height=self.author_lineskip, + font=author_font, + line_height=metr.author_lineskip, color=self.author_color, shadow_color=self.author_shadow, ) - box.skip(10) - box.draw.line((75, box.height, 275, box.height), - fill=self.author_color, width=2) - box.skip(15) + box.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=self.title_lineskip, - font=self.title_font, + 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 = 100 + box_top = metr.box_top_margin elif self.kind == 'Epika': # bottom - box_top = self.height - 100 - box_img.size[1] + box_top = metr.height - metr.box_bottom_margin - box_img.size[1] else: # center - box_top = (self.height - box_img.size[1]) / 2 + box_top = (metr.height - box_img.size[1]) / 2 - box_left = self.bar_width + (self.width - self.bar_width - + 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) - return 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 class VirtualoCover(Cover): @@@ -325,7 -385,8 +384,8 @@@ class PrestigioCover(Cover) author_lineskip = 60 author_color = '#fff' author_shadow = '#000' - author_font = ImageFont.truetype(get_resource('fonts/JunicodeWL-Italic.ttf'), 50) + author_font_ttf = get_resource('fonts/JunicodeWL-Italic.ttf') + author_font_size = 50 title_top = 0 title_margin_left = 118 @@@ -333,7 -394,8 +393,8 @@@ title_lineskip = 60 title_color = '#fff' title_shadow = '#000' - title_font = ImageFont.truetype(get_resource('fonts/JunicodeWL-Italic.ttf'), 50) + title_font_ttf = get_resource('fonts/JunicodeWL-Italic.ttf') + title_font_size = 50 def pretty_title(self): return u"„%s”" % self.title @@@ -349,14 -411,16 +410,16 @@@ class BookotekaCover(Cover) author_margin_right = 233 author_lineskip = 156 author_color = '#d9d919' - author_font = ImageFont.truetype(get_resource('fonts/JunicodeWL-Regular.ttf'), 130) + 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 = ImageFont.truetype(get_resource('fonts/JunicodeWL-Regular.ttf'), 140) + title_font_ttf = get_resource('fonts/JunicodeWL-Regular.ttf') + title_font_size = 140 format = 'PNG' @@@ -365,18 -429,10 +428,10 @@@ class GandalfCover(Cover) width = 600 height = 730 background_img = get_resource('res/cover-gandalf.png') - author_font = ImageFont.truetype(get_resource('fonts/JunicodeWL-Regular.ttf'), 30) - title_font = ImageFont.truetype(get_resource('fonts/JunicodeWL-Regular.ttf'), 40) + 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' - - class ImageCover(WLCover): - format = 'JPEG' - def __init__(self, *args, **kwargs): - super(ImageCover, self).__init__(*args, **kwargs) - self.im = Image.open(self.background_img) - self.width, self.height = self.im.size - - def image(self): - return self.im diff --combined librarian/dcparser.py index d4bdc67,eddd8e5..3e6ac1b --- a/librarian/dcparser.py +++ b/librarian/dcparser.py @@@ -115,10 -115,21 +115,21 @@@ class Field(object) except ValueError, e: raise ValidationError("Field '%s' - invald value: %s" % (self.uri, e.message)) - def validate(self, fdict, strict=False): + def validate(self, fdict, fallbacks=None, strict=False): + if fallbacks is None: + fallbacks = {} if not fdict.has_key(self.uri): if not self.required: - f = self.default + # Accept single value for single fields and saliases. + if self.name in fallbacks: + if self.multiple: + f = fallbacks[self.name] + else: + f = [fallbacks[self.name]] + elif self.salias and self.salias in fallbacks: + f = [fallbacks[self.salias]] + else: + f = self.default else: raise ValidationError("Required field %s not found" % self.uri) else: @@@ -152,7 -163,7 +163,7 @@@ class WorkInfo(object) __metaclass__ = DCInfo FIELDS = ( - Field( DCNS('creator'), 'authors', as_person, salias='author', multiple=True), + Field( DCNS('creator'), 'authors', as_person, salias='author', multiple=True, required=False), Field( DCNS('title'), 'title'), Field( DCNS('type'), 'type', required=False, multiple=True), @@@ -170,7 -181,7 +181,7 @@@ Field( DCNS('source'), 'source_name', required=False), Field( DCNS('source.URL'), 'source_url', required=False), - Field( DCNS('identifier.url'), 'url', WLURI, strict=as_wluri_strict), + Field( DCNS('identifier.url'), 'url', WLURI, strict=as_wluri_strict, required=False), Field( DCNS('rights.license'), 'license', required=False), Field( DCNS('rights'), 'license_description'), ) @@@ -224,7 -235,7 +235,7 @@@ return cls(desc.attrib, field_dict, *args, **kwargs) - def __init__(self, rdf_attrs, dc_fields, strict=False): + def __init__(self, rdf_attrs, dc_fields, fallbacks=None, strict=False): """rdf_attrs should be a dictionary-like object with any attributes of the RDF:Description. dc_fields - dictionary mapping DC fields (with namespace) to list of text values for the given field. """ @@@ -233,7 -244,8 +244,8 @@@ self.fmap = {} for field in self.FIELDS: - value = field.validate(dc_fields, strict=strict) + value = field.validate(dc_fields, fallbacks=fallbacks, + strict=strict) setattr(self, 'prop_' + field.name, value) self.fmap[field.name] = field if field.salias: self.fmap[field.salias] = field diff --combined librarian/epub.py index 034d82d,eab2b18..223bde9 --- a/librarian/epub.py +++ b/librarian/epub.py @@@ -7,6 -7,7 +7,7 @@@ from __future__ import with_statemen import os import os.path + import re import subprocess from StringIO import StringIO from copy import deepcopy @@@ -16,7 -17,7 +17,7 @@@ from tempfile import mkdtemp, NamedTemp from shutil import rmtree from librarian import RDFNS, WLNS, NCXNS, OPFNS, XHTMLNS, OutputFile - from librarian.cover import ImageCover as WLCover + from librarian.cover import WLCover from librarian import functions, get_resource @@@ -79,7 -80,7 +80,7 @@@ def replace_characters(node) return text.replace(u"\ufeff", u"")\ .replace("---", u"\u2014")\ .replace("--", u"\u2013")\ - .replace(",,", u"“")\ + .replace(",,", u"\u201E")\ .replace('"', u"\u201D")\ .replace("'", u"\u2019") if node.tag in ('uwaga', 'extra'): @@@ -109,31 -110,74 +110,74 @@@ def find_annotations(annotations, sourc find_annotations(annotations, child, part_no) + class Stanza(object): + """ + Converts / verse endings into verse elements in a stanza. + + Slashes may only occur directly in the stanza. Any slashes in subelements + will be ignored, and the subelements will be put inside verse elements. + + >>> s = etree.fromstring("a c c/\\nbx/\\nyc/ \\nd") + >>> Stanza(s).versify() + >>> print etree.tostring(s) + a c cbx/ + ycd + + """ + def __init__(self, stanza_elem): + self.stanza = stanza_elem + self.verses = [] + self.open_verse = None + + def versify(self): + self.push_text(self.stanza.text) + for elem in self.stanza: + self.push_elem(elem) + self.push_text(elem.tail) + tail = self.stanza.tail + self.stanza.clear() + self.stanza.tail = tail + self.stanza.extend(self.verses) + + def open_normal_verse(self): + self.open_verse = self.stanza.makeelement("wers_normalny") + self.verses.append(self.open_verse) + + def get_open_verse(self): + if self.open_verse is None: + self.open_normal_verse() + return self.open_verse + + def push_text(self, text): + if not text: + return + for i, verse_text in enumerate(re.split(r"/\s*\n", text)): + if i: + self.open_normal_verse() + verse = self.get_open_verse() + if len(verse): + verse[-1].tail = (verse[-1].tail or "") + verse_text + else: + verse.text = (verse.text or "") + verse_text + + def push_elem(self, elem): + if elem.tag.startswith("wers"): + verse = deepcopy(elem) + verse.tail = None + self.verses.append(verse) + self.open_verse = verse + else: + appended = deepcopy(elem) + appended.tail = None + self.get_open_verse().append(appended) + + def replace_by_verse(tree): """ Find stanzas and create new verses in place of a '/' character """ stanzas = tree.findall('.//' + WLNS('strofa')) - for node in stanzas: - for child_node in node: - if child_node.tag in ('slowo_obce', 'wyroznienie'): - foreign_verses = inner_xml(child_node).split('/\n') - if len(foreign_verses) > 1: - new_foreign = '' - for foreign_verse in foreign_verses: - if foreign_verse.startswith('', foreign_verse, '')) - set_inner_xml(child_node, new_foreign) - verses = inner_xml(node).split('/\n') - if len(verses) > 1: - modified_inner_xml = '' - for verse in verses: - if verse.startswith('', verse, '')) - set_inner_xml(node, modified_inner_xml) + for stanza in stanzas: + Stanza(stanza).versify() def add_to_manifest(manifest, partno): @@@ -248,15 -292,14 +292,14 @@@ def chop(main_text) last_node_part = False for one_part in main_text: name = one_part.tag - #if name == 'naglowek_czesc': - # yield part_xml - # last_node_part = True - # main_xml_part[:] = [deepcopy(one_part)] - #elif not last_node_part and name in ("naglowek_rozdzial", "naglowek_akt", "srodtytul"): - # yield part_xml - # main_xml_part[:] = [deepcopy(one_part)] - #else: - if True: + if name == 'naglowek_czesc': + yield part_xml + last_node_part = True + main_xml_part[:] = [deepcopy(one_part)] + elif not last_node_part and name in ("naglowek_rozdzial", "naglowek_akt", "srodtytul"): + yield part_xml + main_xml_part[:] = [deepcopy(one_part)] + else: main_xml_part.append(deepcopy(one_part)) last_node_part = False yield part_xml @@@ -266,24 -309,21 +309,21 @@@ def transform_chunk(chunk_xml, chunk_no """ 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)) + 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: - if chunk_no == 1: - html_tree = xslt(chunk_xml, get_resource('epub/xsltScheme-FoC.xsl')) - else: - find_annotations(annotations, chunk_xml, chunk_no) - replace_by_verse(chunk_xml) - html_tree = xslt(chunk_xml, get_resource('epub/xsltScheme.xsl')) + 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 @@@ -295,7 -335,7 +335,7 @@@ def transform(wldoc, verbose=False """ produces a EPUB file sample=n: generate sample e-book (with at least n paragraphs) - cover: a cover.Cover object or True for default + cover: a cover.Cover factory or True for default flags: less-advertising, without-fonts, working-copy """ @@@ -306,16 -346,7 +346,7 @@@ # every input file will have a TOC entry, # pointing to starting chunk - - # hack for FoC: - if wldoc.book_info.author is not None: - toc_title = "%s, %s" % (wldoc.book_info.author.readable(), wldoc.book_info.title) - note = wldoc.edoc.find('//dzielo_nadrzedne') - if note is not None: - toc_title += " (%s)" % note.text - else: - toc_title = wldoc.book_info.title - toc = TOC(toc_title, "part%d.html" % chunk_counter) + toc = TOC(wldoc.book_info.title, "part%d.html" % chunk_counter) chars = set() if first: # write book title page @@@ -324,8 -355,7 +355,7 @@@ zip.writestr('OPS/title.html', etree.tostring(html_tree, method="html", pretty_print=True)) # add a title page TOC entry - toc.add(u"Title page", "title.html") - toc.add(u"Dear readers!", "part1.html") + 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: @@@ -382,6 -412,10 +412,10 @@@ for flag in flags: document.edoc.getroot().set(flag, 'yes') + # add editors info + document.edoc.getroot().set('editors', u', '.join(sorted( + editor.readable() for editor in document.editors()))) + opf = xslt(document.book_info.to_etree(), get_resource('epub/xsltContent.xsl')) manifest = opf.find('.//' + OPFNS('manifest')) guide = opf.find('.//' + OPFNS('guide')) @@@ -401,9 -435,8 +435,8 @@@ '' \ '') - #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')) - zip.write('logo.png', os.path.join('OPS', 'logo.png')) + zip.write(get_resource('res/wl-logo-small.png'), os.path.join('OPS', 'logo_wolnelektury.png')) + zip.write(get_resource('res/jedenprocent.png'), os.path.join('OPS', 'jedenprocent.png')) if not style: style = get_resource('epub/style.css') zip.write(style, os.path.join('OPS', 'style.css')) @@@ -411,31 -444,29 +444,29 @@@ if cover: if cover is True: cover = WLCover - if cover.uses_dc_cover: - if document.book_info.cover_by: - document.edoc.getroot().set('data-cover-by', document.book_info.cover_by) - if document.book_info.cover_source: - document.edoc.getroot().set('data-cover-source', document.book_info.cover_source) cover_file = StringIO() - bound_cover = cover(document.book_info) - bound_cover.save(cover_file) - cover_name = 'cover.%s' % bound_cover.ext() - zip.writestr(os.path.join('OPS', cover_name), cover_file.getvalue()) + c = cover(document.book_info) - import Image - c.im = Image.open('cover.jpg') - c.ext = lambda: 'jpg' + c.save(cover_file) + c_name = 'cover.%s' % c.ext() + zip.writestr(os.path.join('OPS', c_name), cover_file.getvalue()) del cover_file cover_tree = etree.parse(get_resource('epub/cover.html')) - cover_tree.find('//' + XHTMLNS('img')).set('src', c_name) + cover_tree.find('//' + XHTMLNS('img')).set('src', cover_name) zip.writestr('OPS/cover.html', etree.tostring( cover_tree, method="html", pretty_print=True)) + 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( '')) manifest.append(etree.fromstring( - '' % (c_name, c.mime_type()))) + '' % (cover_name, bound_cover.mime_type()))) spine.insert(0, etree.fromstring('')) opf.getroot()[0].append(etree.fromstring('')) guide.append(etree.fromstring('')) @@@ -455,7 -486,7 +486,7 @@@ '')) spine.append(etree.fromstring( '')) - guide.append(etree.fromstring('')) + guide.append(etree.fromstring('')) toc, chunk_counter, chars, sample = transform_file(document, sample=sample) @@@ -475,7 -506,16 +506,16 @@@ zip.writestr('OPS/annotations.html', etree.tostring( html_tree, method="html", pretty_print=True)) - toc.add("Editorial page", "last.html") + toc.add("Weprzyj Wolne Lektury", "support.html") + manifest.append(etree.fromstring( + '')) + spine.append(etree.fromstring( + '')) + 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( '')) spine.append(etree.fromstring( @@@ -488,7 -528,10 +528,10 @@@ if not flags or not 'without-fonts' in flags: # strip fonts tmpdir = mkdtemp('-librarian-epub') - cwd = os.getcwd() + 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': @@@ -503,7 -546,8 +546,8 @@@ manifest.append(etree.fromstring( '' % (fname, fname))) rmtree(tmpdir) - os.chdir(cwd) + if cwd is not None: + os.chdir(cwd) zip.writestr('OPS/content.opf', etree.tostring(opf, pretty_print=True)) title = document.book_info.title @@@ -519,7 -563,7 +563,7 @@@ # write TOC if html_toc: - toc.add(u"Table of Contents", "toc.html", index=1) + 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)) diff --combined librarian/epub/xsltLast.xsl index 09dbc15,9b52203..f6802d8 --- a/librarian/epub/xsltLast.xsl +++ b/librarian/epub/xsltLast.xsl @@@ -15,7 -15,7 +15,7 @@@ - <xsl:text>Editorial page</xsl:text> + <xsl:text>Strona redakcyjna</xsl:text> @@@ -23,13 -23,13 +23,13 @@@

- This book is available under the terms of + Ten utwór jest udostepniony na licencji - . + Ten utwór nie jest chroniony prawem autorskim i znajduje się w domenie @@@ -43,12 -43,28 +43,28 @@@

-

Published by Modern Poland Foundation, 2012.

+

Źródło: + + + + + , + + +

+ + +

Tekst opracowany na podstawie:

+
+ + +

+
-

Cover image: +

Okładka na podstawie: @@@ -64,6 -80,12 +80,19 @@@

+ ++
++ Logo 1% ++
Przekaż 1% podatku na rozwój Wolnych Lektur.
++
Nazwa organizacji: Fundacja Nowoczesna Polska
++
KRS 0000070056
++
++ +

 

+

+ Plik wygenerowany dnia . +

+ @@@ -74,22 -96,13 +103,17 @@@ - +

- Technical editors: - - - , - - . -

+ Opracowanie redakcyjne i przypisy: + .

+ +
+
+ diff --combined librarian/mobi.py index 6de72b3,d98b838..99b724e mode 100755,100644..100644 --- a/librarian/mobi.py +++ b/librarian/mobi.py @@@ -9,7 -9,7 +9,7 @@@ import subproces from tempfile import NamedTemporaryFile from librarian import OutputFile - from librarian.cover import ImageCover as WLCover + from librarian.cover import WLCover from librarian import get_resource @@@ -19,7 -19,7 +19,7 @@@ def transform(wldoc, verbose=False wldoc: a WLDocument sample=n: generate sample e-book (with at least n paragraphs) - cover: a cover.Cover object + cover: a cover.Cover factory overriding default flags: less-advertising, """ @@@ -30,15 -30,12 +30,12 @@@ # provide a cover by default if not cover: cover = WLCover + cover_file = NamedTemporaryFile(suffix='.png', delete=False) - bound_cover = cover(book_info) - bound_cover.save(cover_file) + c = cover(book_info) - import Image - c.im = Image.open('cover.jpg') - c.ext = lambda: 'jpg' - cover_file = NamedTemporaryFile(suffix='.' + c.ext(), delete=False) + c.save(cover_file) - if cover.uses_dc_cover: - if document.book_info.cover_by: + if bound_cover.uses_dc_cover: - if document.book_info.cover_by: ++ if document.remobook_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) diff --combined librarian/pdf/wl.cls index 82e1362,4a7648e..cb53a3f --- a/librarian/pdf/wl.cls +++ b/librarian/pdf/wl.cls @@@ -14,9 -14,6 +14,9 @@@ \RequirePackage{setspace} \RequirePackage{type1cm} +\RequirePackage{amssymb} +\RequirePackage{amsmath} + \DeclareOption{13pt}{% \AtEndOfClass{% % font size definitions, similar to ones in /usr/share/texmf-texlive/tex/latex/base/ @@@ -64,20 -61,18 +64,19 @@@ \DeclareOption*{\PassOptionsToClass{\CurrentOption}{book}} \ProcessOptions\relax -\LoadClass[a4paper,oneside]{book} +\LoadClass[a4paper]{book} \usepackage{trace} - +\usepackage{caption} +\usepackage{tabularx} \usepackage[MeX]{polski} - +\usepackage{icomma} \usepackage[xetex]{graphicx} \usepackage{fontspec} \usepackage{xunicode} \usepackage{xltxtra} - \usepackage[overload]{textcase} \usepackage{scalefnt} \usepackage[colorlinks=true,linkcolor=black,setpagesize=false,urlcolor=black,xetex]{hyperref} @@@ -143,8 -138,7 +142,8 @@@ Letters={SmallCaps,UppercaseSmallCaps \setlength{\marginparsep}{2em} \setlength{\marginparwidth}{8.5em} -\setlength{\oddsidemargin}{0pt} +\setlength{\oddsidemargin}{36mm} +\setlength{\evensidemargin}{0pt} \setlength{\voffset}{0pt} \setlength{\topmargin}{0pt} \setlength{\headheight}{0pt} @@@ -155,12 -149,9 +154,12 @@@ \fancyhf{} \renewcommand{\headrulewidth}{0pt} \renewcommand{\footrulewidth}{0pt} -\lfoot{{\footnotesize \textsc{\@author} \emph{\@title}}} + +%\lfoot{{\footnotesize \textsc{\@author} \emph{\@title}}} \cfoot{} -\rfoot{{\footnotesize \thepage}} +%\rfoot{{\footnotesize \thepage}} +\fancyfoot[LO,RE]{{\footnotesize \textsc{\@author} \emph{\@title}}} +\fancyfoot[LE,RO]{{\footnotesize \thepage}} \clubpenalty=100000 \widowpenalty=100000 @@@ -178,10 -169,8 +177,8 @@@ \raisebox{0pt}[0pt][0pt]{\makebox[0pt][r]{\usebox{\xglyphbox}}}} \newcommand{\makecover}[2]{ - - - %\pdfpagewidth=#1 - %\pdfpageheight=#2 + \pdfpagewidth=#1 + \pdfpageheight=#2 \thispagestyle{empty} \newlength{\PictHOffset} @@@ -196,41 -185,15 +193,36 @@@ \addtolength{\PictVOffset}{\headheight} \addtolength{\PictVOffset}{\headsep} \addtolength{\PictVOffset}{\topskip} - - \addtolength{\PictVOffset}{-#2} + \addtolength{\PictVOffset}{-\pdfpageheight} \noindent\hspace*{-\PictHOffset}% \raisebox{\PictVOffset}[0pt][0pt]{\makebox[0pt][l]{% - \includegraphics[height=#2,width=#1]{cover.jpg}}} - %\clearpage - \vspace{#2} + \includegraphics[height=\pdfpageheight,width=\pdfpagewidth]{cover.png}}} + \clearpage - \hspace{-36mm}\parbox{16cm}{ - \setlength{\pdfpagewidth}{210mm} - \setlength{\pdfpageheight}{297mm} ++ ++%% Strona tytułowa %% XXX ++ \hspace{-36mm}\parbox{16cm}{ + {\addfontfeature{LetterSpace=-4.0}{\scalefont{4}% + \noindent Philippe Aigrain}} + + {\addfontfeature{LetterSpace=-4.0}{\scalefont{2.5}% + przy współpracy Suzanne Aigrain + }} + + \vspace{2em} + {\addfontfeature{LetterSpace=-4.0}{\scalefont{6}% + Dzielenie się + }} + + \vspace{2em} + {\addfontfeature{LetterSpace=-4.0}{\scalefont{3}% + Kultura i gospodarka epoki internetu + }} - - - %\emph{\thankyou}\\ - %\indent\emph{You made this book possible.} + } + - - %\setlength{\pdfpagewidth}{210mm} - %\setlength{\pdfpageheight}{297mm} ++ \setlength{\pdfpagewidth}{210mm} ++ \setlength{\pdfpageheight}{297mm} } @@@ -260,157 -223,59 +252,160 @@@ \vspace{.6em} \color{black} - } } +\usepackage{printlen} + \newcommand{\editorialsection}{ - \begin{figure}[b!] - { - \footnotesize - \color{theme} - \noindent \rule{\linewidth}{0.4pt} ++%% XXX % sprawdzic czy czegos nie zgubilem z master ++%% szczegolnie jesli chodzi o makra wstawiajace dane z DC, jak np \editors +\clearpage + \thispagestyle{empty} - \rightsinfo - \vspace{.6em} +% Pusta strona +\clearpage + \thispagestyle{empty} - Źródło: \href{\bookurl}{\bookurl} +\vspace{2em} + \hspace{0mm}\parbox{16cm}{ +\centering + {\addfontfeature{LetterSpace=-4.0}{\scalefont{6}% + Dzielenie się + }} + + \vspace{2em} + {\addfontfeature{LetterSpace=-4.0}{\scalefont{3}% + Kultura i gospodarka epoki internetu + }} +} - \vspace{.6em} - \sourceinfo +\clearpage + \thispagestyle{empty} - \description - \vspace{.6em} +\clearpage + \thispagestyle{empty} - \editors +%\parbox{10cm}{ +% \centering + + \hspace{-36mm}\parbox{16cm}{ +\centering + + {\addfontfeature{LetterSpace=-4.0}{\scalefont{4}% + \noindent Philippe Aigrain + }} + + {\addfontfeature{LetterSpace=-4.0}{\scalefont{2.5}% + przy współpracy Suzanne Aigrain + }} + + \vspace{2em} + {\addfontfeature{LetterSpace=-4.0}{\scalefont{6}% + Dzielenie się + }} + + \vspace{2em} + {\addfontfeature{LetterSpace=-4.0}{\scalefont{4}% + Kultura i gospodarka epoki internetu + }} + + \vspace{2em} + {\addfontfeature{LetterSpace=-4.0}{\scalefont{2}% + Z języka angielskiego przełożył \\ + \emph{Wojciech Pędzich} + }} + +\vspace{22em} + +\includegraphics[scale=.2]{logo.eps} +} - \ifdefined\coverby - \vspace{.6em} - \coverby - \fi ++ Przekaż darowiznę na konto: ++ \href{http://nowoczesnapolska.org.pl/pomoz-nam/wesprzyj-nas/}{szczegóły na stronie Fundacji}. - \vspace{.6em} - \emph{Wesprzyj Wolne Lektury!} +\clearpage + \thispagestyle{empty} - Wolne Lektury to projekt fundacji Nowoczesna Polska – organizacji - pożytku publicznego działającej na rzecz wolności korzystania - z dóbr kultury. +\noindent Tytuł oryginału - Co roku do domeny publicznej przechodzi twórczość kolejnych autorów. - Dzięki Twojemu wsparciu będziemy je mogli udostępnić wszystkim bezpłatnie. +\noindent \emph{Sharing. Culture and the Economy in the Internet Age} - \vspace{.6em} - \emph{Jak możesz pomóc?} +\vspace{1em} - Przekaż 1\% podatku na rozwój Wolnych Lektur: - Fundacja Nowoczesna Polska, KRS 0000070056. +\noindent \editors - Pomóż uwolnić konkretną książkę, wspierając - \href{http://www.wolnelektury.pl/wesprzyj/}{zbiórkę na stronie wolnelektury.pl}. +\vspace{1em} - Przekaż darowiznę na konto: - \href{http://nowoczesnapolska.org.pl/pomoz-nam/wesprzyj-nas/}{szczegóły na stronie Fundacji}. - \color{black} - } - \end{figure} +\noindent \rightsinfo + +\vspace{1em} + +\noindent \coverby + + +%\set\textwidth=450pt +%\printlength\textwidth + + +%% {\scalefont{1.5}Drogi czytelniku!} + + + +%% \vspace{1em} + +\vspace{1em} + +\noindent Tłumaczenie książki powstało w ramach projektu "Przyszłość prawa autorskiego" finansowanego przez {\it Trust for Civil Society in Central and Eastern Europe}. + +\vspace{1em} + +\noindent \includegraphics[scale=.4]{cce_trust.eps} + +\vspace{1em} + +\noindent Wydawca: Fundacja Nowoczesna Polska, Warszawa 2012 + +\vspace{1em} +\includegraphics[scale=.2]{logo.eps} +\vspace{1em} + +\noindent \href{http://nowoczesnapolska.org.pl/}{http://nowoczesnapolska.org.pl/} + + + +%\vspace{4em} +%\box{\tableofcontents} + +%% \begin{figure}[b!] +%% { +%% \footnotesize +%% \color{theme} +%% \noindent \rule{\linewidth}{0.4pt} + +%% \rightsinfo +%% % \vspace{.6em} + +%% %Źródło: \href{\bookurl}{\bookurl} + +%% %\vspace{.6em} +%% %\sourceinfo + +%% %\description +%% %\vspace{.6em} + +%% Opublikowano przez \href{http://nowoczesnapolska.org.pl}{Fundację Nowoczesna Polska}, 2012. + +%% \editors + +%% %\vspace{.6em} +%% \coverby + +%% \color{black} +%% } +%% \end{figure} +\clearpage } @@@ -435,13 -300,10 +430,10 @@@ Letters={Uppercase %{\addfontfeature{Scale=2.0, FakeStretch=0.98, LetterSpace=-2.0}\emph{#1}} } + \newcommand{\tytul}[1]{% #1% - %\vspace{1em}% - } - - \newcommand{\autorpodutworu}[1]{% - \section*{\typosection{#1}}% + \vspace{1em}% } \newcommand{\nazwapodutworu}[1]{% @@@ -449,7 -311,6 +441,6 @@@ } \newcommand{\autorutworu}[1]{% - \addcontentsline{toc}{part}{???} \subsection*{\typosubsection{#1}}% } @@@ -465,14 -326,11 +456,15 @@@ \subsection*{\typosubsubsection{#1}}% } +\newcommand{\podtytulpodutworu}[1]{% +\subsection*{\typosubsubsection{#1}}% +} + \newcommand{\translator}[1]{% \subsection*{\typosubsubsection{tłum. #1}}% } + \newcommand{\powiesc}[1]{#1} \newcommand{\opowiadanie}[1]{#1} \newcommand{\lirykal}[1]{#1} @@@ -482,9 -340,7 +474,7 @@@ \newcommand{\dramatwspolczesny}[1]{#1} \newcommand{\nota}[1]{% - \begin{quotation}% - #1% - \end{quotation}% + \par{#1}% } \newcommand{\dedykacja}[1]{% @@@ -535,25 -391,25 +525,25 @@@ \subsection*{\typosubsection{#1}}% } \newcommand{\naglowekczesc}[1]{% - %\pagebreak + \pagebreak \subsection*{\typosubsection{#1}}% } - \newcommand{\naglowekrozdzial}[1]{% + \newcommand{\srodtytul}[1]{% \subsection*{\typosubsection{#1}}% } \newcommand{\naglowekscena}[1]{% \subsubsection*{\typosubsubsection{#1}}% } - \newcommand{\naglowekpodrozdzial}[1]{% + \newcommand{\naglowekrozdzial}[1]{% \subsubsection*{\typosubsubsection{#1}}% } \newcommand{\naglowekosoba}[1]{% \par{\textsc{#1}}\nopagebreak% } - \newcommand{\srodtytul}[1]{% - \vskip 1em \par{\large \it \noindent #1}\vskip .5em\nopagebreak% + \newcommand{\naglowekpodrozdzial}[1]{% + \par{#1}\nopagebreak% } \newcommand{\miejsceczas}[1]{% @@@ -637,7 -493,6 +627,6 @@@ \begin{center}% \par{*}% \end{center}% - \noindent% } \newcommand{\separatorlinia}{% @@@ -659,11 -514,3 +648,3 @@@ \fi } - \newcommand{\ilustr}[2]{ - - \vspace{1em}% - \begin{center}% - \par{\includegraphics[width=\textwidth]{#1}\\#2}% - \end{center}% - \vspace{1em}% - } diff --combined librarian/pdf/wl2tex.xslt index 58bb68d,97296e9..d3b8faf --- a/librarian/pdf/wl2tex.xslt +++ b/librarian/pdf/wl2tex.xslt @@@ -58,77 -58,62 +58,62 @@@ - - \def\thankyou{% - - Thank you for your contribution, ! - Thank you for all your contributions! - - } - - + mm 210mm - mm - + - - + - + - + + + - \def\coverby{ - Obraz na okładce: + + \def\coverby{Okładka na podstawie: - \href{\datacoversource}{\datacoverby}. + \href{\datacoversource}{\datacoverby} - \datacoverby{}. + \datacoverby{} - } + + \def\editors{} - - - - - - - - - @@@ -170,7 -155,7 +155,7 @@@ \href{http://creativecommons.org/licenses/by-sa/3.0/}{Creative Commons Uznanie Autorstwa – Na Tych Samych Warunkach 3.0 PL}.} - \def\rightsinfo{Ta książka jest udostpęniona na licencji + \def\rightsinfo{Ten utwór jest udostepniony na licencji \href{}{}.} @@@ -180,7 -165,6 +165,7 @@@ \vspace{.6em} } \def\description{} + \def\editors{} @@@ -362,75 -346,6 +347,6 @@@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - tableh! - - - - - - table - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@@ -462,13 -377,10 +378,10 @@@ - - Redakcja techniczna: - - - , - - . + + Opracowanie redakcyjne i przypisy: + + . diff --combined scripts/book2pdf index 37fcb17,68e2d08..11c5c04 --- a/scripts/book2pdf +++ b/scripts/book2pdf @@@ -4,61 -4,21 +4,23 @@@ # This file is part of Librarian, licensed under GNU Affero GPLv3 or later. # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # + from librarian.book2anything import Book2Anything, Option +import os.path +from optparse import OptionParser - from librarian import DirDocProvider, ParseError - from librarian.parser import WLDocument + class Book2Pdf(Book2Anything): + format_name = "PDF" + ext = "pdf" + uses_cover = True + uses_provider = True + transform_args = [ + Option('-t', '--save-tex', dest='save_tex', metavar='FILE', + help='path to save the intermediary LaTeX file to'), + Option('-m', '--morefloats', dest='morefloats', metavar='old/new/none', + help='force morefloats in old (<1.0c), new (>=1.0c) or none') + ] - if __name__ == '__main__': - usage = """Usage: %prog [options] SOURCE [SOURCE...] - Convert SOURCE files to PDF format.""" - - parser = OptionParser(usage) - parser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False, - help='make lots of noise and revert to default interaction in LaTeX') - parser.add_option('-c', '--with-cover', action='store_true', dest='with_cover', default=False, - help='create default cover') - parser.add_option('-d', '--make-dir', action='store_true', dest='make_dir', default=False, - help='create a directory for author and put the PDF in it') - parser.add_option('-t', '--save-tex', dest='save_tex', metavar='FILE', - help='path to save the intermediary LaTeX file to') - parser.add_option('-o', '--output-file', dest='output_file', metavar='FILE', - help='specifies the output file') - parser.add_option('-O', '--output-dir', dest='output_dir', metavar='DIR', - help='specifies the directory for output') - parser.add_option('-m', '--morefloats', dest='morefloats', metavar='old/new/none', - help='force morefloats in old (<1.0c), new (>=1.0c) or none') - (options, args) = parser.parse_args() - - if len(args) < 1: - parser.print_help() - exit(1) - - if options.output_dir and options.output_file: - raise ValueError("Either --output-dir or --output file should be specified") - try: - for main_input in args: - path, fname = os.path.realpath(main_input).rsplit('/', 1) - provider = DirDocProvider(path) - output_file, output_dir = options.output_file, options.output_dir - if not (options.output_file or options.output_dir): - output_file = os.path.splitext(main_input)[0] + '.pdf' - else: - output_file = None - - doc = WLDocument.from_file(main_input, provider=provider) - pdf = doc.as_pdf(save_tex=options.save_tex, - cover=options.with_cover, - morefloats=options.morefloats, verbose=options.verbose) - - doc.save_output_file(pdf, - output_file, options.output_dir, options.make_dir, 'pdf') - except ParseError, e: - print '%(file)s:%(name)s:%(message)s; use -v to see more output' % { - 'file': main_input, - 'name': e.__class__.__name__, - 'message': e - } + if __name__ == '__main__': + Book2Pdf.run()