Merge from trunk

This commit is contained in:
Charles Haley 2013-01-08 10:02:00 +01:00
commit 6331180d96
9 changed files with 188 additions and 71 deletions

View File

@ -1,33 +1,36 @@
from calibre.web.feeds.recipes import BasicNewsRecipe from calibre.web.feeds.recipes import BasicNewsRecipe
class AdvancedUserRecipe1303841067(BasicNewsRecipe): class AdvancedUserRecipe1303841067(BasicNewsRecipe):
title = u'Börse-online' title = u'Börse-online'
__author__ = 'schuster' __author__ = 'schuster, Armin Geller'
oldest_article = 1 oldest_article = 1
max_articles_per_feed = 100 max_articles_per_feed = 100
no_stylesheets = True no_stylesheets = True
use_embedded_content = False use_embedded_content = False
language = 'de' language = 'de'
remove_javascript = True remove_javascript = True
cover_url = 'http://www.dpv.de/images/1995/source.gif' encoding = 'iso-8859-1'
masthead_url = 'http://www.zeitschriften-cover.de/cover/boerse-online-cover-januar-2010-x1387.jpg' timefmt = ' [%a, %d %b %Y]'
extra_css = '''
h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
h4{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;} cover_url = 'http://www.wirtschaftsmedien-shop.de/s/media/coverimages/7576_2013107.jpg'
img {min-width:300px; max-width:600px; min-height:300px; max-height:800px} masthead_url = 'http://upload.wikimedia.org/wikipedia/de/5/56/B%C3%B6rse_Online_Logo.svg'
p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
'''
remove_tags_bevor = [dict(name='h3')]
remove_tags_after = [dict(name='div', attrs={'class':'artikelfuss'})]
remove_tags = [dict(attrs={'class':['moduleTopNav', 'moduleHeaderNav', 'text', 'blau', 'poll1150']}),
dict(id=['newsletterlayer', 'newsletterlayerClose', 'newsletterlayer_body', 'newsletterarray_error', 'newsletterlayer_emailadress', 'newsletterlayer_submit', 'kommentar']),
dict(name=['h2', 'Gesamtranking', 'h3',''])]
remove_tags_after = [dict(name='div', attrs={'class':['artikelfuss', 'rahmen600']})]
remove_tags = [
dict(name='div', attrs={'id':['breadcrumb', 'rightCol', 'clearall']}),
dict(name='div', attrs={'class':['footer', 'artikelfuss']}),
]
keep_only_tags = [
dict(name='div', attrs={'id':['contentWrapper']})
]
feeds = [(u'Börsennachrichten', u'http://www.boerse-online.de/rss/')]
def print_version(self, url): def print_version(self, url):
return url.replace('.html#nv=rss', '.html?mode=print') return url.replace('.html#nv=rss', '.html?mode=print')
feeds = [(u'Börsennachrichten', u'http://www.boerse-online.de/rss/')]

BIN
recipes/icons/libartes.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

69
recipes/libartes.recipe Normal file
View File

@ -0,0 +1,69 @@
__license__ = 'GPL v3'
__copyright__ = '2013, Darko Miletic <darko.miletic at gmail.com>'
'''
libartes.com
'''
import re
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
class Libartes(BasicNewsRecipe):
title = 'Libartes'
__author__ = 'Darko Miletic'
description = 'Elektronski časopis Libartes delo je kulturnih entuzijasta, umetnika i teoretičara umetnosti i književnosti. Časopis Libartes izlazi tromesečno i bavi se različitim granama umetnosti - književnošću, muzikom, filmom, likovnim umetnostima, dizajnom i arhitekturom.'
publisher = 'Libartes'
category = 'literatura, knjizevnost, film, dizajn, arhitektura, muzika'
no_stylesheets = True
INDEX = 'http://libartes.com/'
use_embedded_content = False
encoding = 'utf-8'
language = 'sr'
publication_type = 'magazine'
masthead_url = 'http://libartes.com/index_files/logo.gif'
extra_css = """
@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)}
@font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)}
body{font-family: "Times New Roman",Times,serif1, serif}
img{display:block}
.naslov{font-size: xx-large; font-weight: bold}
.nag{font-size: large; font-weight: bold}
"""
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
remove_tags_before = dict(attrs={'id':'nav'})
remove_tags_after = dict(attrs={'id':'fb' })
keep_only_tags = [dict(name='div', attrs={'id':'center_content'})]
remove_tags = [
dict(name=['object','link','iframe','embed','meta'])
,dict(attrs={'id':'nav'})
]
def parse_index(self):
articles = []
soup = self.index_to_soup(self.INDEX)
for item in soup.findAll(name='a', attrs={'class':'belad'}, href=True):
feed_link = item
if feed_link['href'].startswith(self.INDEX):
url = feed_link['href']
else:
url = self.INDEX + feed_link['href']
title = self.tag_to_string(feed_link)
date = strftime(self.timefmt)
articles.append({
'title' :title
,'date' :date
,'url' :url
,'description':''
})
return [('Casopis Libartes', articles)]

View File

@ -10,7 +10,7 @@ Convert OEB ebook format to PDF.
import glob, os import glob, os
from calibre.constants import iswindows from calibre.constants import iswindows, islinux
from calibre.customize.conversion import (OutputFormatPlugin, from calibre.customize.conversion import (OutputFormatPlugin,
OptionRecommendation) OptionRecommendation)
from calibre.ptempfile import TemporaryDirectory from calibre.ptempfile import TemporaryDirectory
@ -73,13 +73,13 @@ class PDFOutput(OutputFormatPlugin):
' of stretching it to fill the full first page of the' ' of stretching it to fill the full first page of the'
' generated pdf.')), ' generated pdf.')),
OptionRecommendation(name='pdf_serif_family', OptionRecommendation(name='pdf_serif_family',
recommended_value='Times New Roman', help=_( recommended_value='Liberation Serif' if islinux else 'Times New Roman', help=_(
'The font family used to render serif fonts')), 'The font family used to render serif fonts')),
OptionRecommendation(name='pdf_sans_family', OptionRecommendation(name='pdf_sans_family',
recommended_value='Helvetica', help=_( recommended_value='Liberation Sans' if islinux else 'Helvetica', help=_(
'The font family used to render sans-serif fonts')), 'The font family used to render sans-serif fonts')),
OptionRecommendation(name='pdf_mono_family', OptionRecommendation(name='pdf_mono_family',
recommended_value='Courier New', help=_( recommended_value='Liberation Mono' if islinux else 'Courier New', help=_(
'The font family used to render monospaced fonts')), 'The font family used to render monospaced fonts')),
OptionRecommendation(name='pdf_standard_font', choices=['serif', OptionRecommendation(name='pdf_standard_font', choices=['serif',
'sans', 'mono'], 'sans', 'mono'],
@ -102,6 +102,10 @@ class PDFOutput(OutputFormatPlugin):
]) ])
def convert(self, oeb_book, output_path, input_plugin, opts, log): def convert(self, oeb_book, output_path, input_plugin, opts, log):
from calibre.gui2 import must_use_qt, load_builtin_fonts
must_use_qt()
load_builtin_fonts()
self.oeb = oeb_book self.oeb = oeb_book
self.input_plugin, self.opts, self.log = input_plugin, opts, log self.input_plugin, self.opts, self.log = input_plugin, opts, log
self.output_path = output_path self.output_path = output_path
@ -135,7 +139,6 @@ class PDFOutput(OutputFormatPlugin):
If you ever move to Qt WebKit 2.3+ then this will be unnecessary. If you ever move to Qt WebKit 2.3+ then this will be unnecessary.
''' '''
from calibre.ebooks.oeb.base import urlnormalize from calibre.ebooks.oeb.base import urlnormalize
from calibre.gui2 import must_use_qt
from calibre.utils.fonts.utils import remove_embed_restriction from calibre.utils.fonts.utils import remove_embed_restriction
from PyQt4.Qt import QFontDatabase, QByteArray, QRawFont, QFont from PyQt4.Qt import QFontDatabase, QByteArray, QRawFont, QFont
@ -165,7 +168,6 @@ class PDFOutput(OutputFormatPlugin):
raw = remove_embed_restriction(raw) raw = remove_embed_restriction(raw)
except: except:
continue continue
must_use_qt()
fid = QFontDatabase.addApplicationFontFromData(QByteArray(raw)) fid = QFontDatabase.addApplicationFontFromData(QByteArray(raw))
family_name = None family_name = None
if fid > -1: if fid > -1:

View File

@ -239,7 +239,7 @@ class PdfEngine(QPaintEngine):
@store_error @store_error
def drawTextItem(self, point, text_item): def drawTextItem(self, point, text_item):
# super(PdfEngine, self).drawTextItem(point, text_item) # return super(PdfEngine, self).drawTextItem(point, text_item)
self.apply_graphics_state() self.apply_graphics_state()
gi = self.qt_hack.get_glyphs(point, text_item) gi = self.qt_hack.get_glyphs(point, text_item)
if not gi.indices: if not gi.indices:
@ -247,7 +247,10 @@ class PdfEngine(QPaintEngine):
return return
name = hash(bytes(gi.name)) name = hash(bytes(gi.name))
if name not in self.fonts: if name not in self.fonts:
self.fonts[name] = self.create_sfnt(text_item) try:
self.fonts[name] = self.create_sfnt(text_item)
except UnsupportedFont:
return super(PdfEngine, self).drawTextItem(point, text_item)
metrics = self.fonts[name] metrics = self.fonts[name]
for glyph_id in gi.indices: for glyph_id in gi.indices:
try: try:

View File

@ -147,9 +147,10 @@ class PDFWriter(QObject):
opts = self.opts opts = self.opts
page_size = get_page_size(self.opts) page_size = get_page_size(self.opts)
xdpi, ydpi = self.view.logicalDpiX(), self.view.logicalDpiY() xdpi, ydpi = self.view.logicalDpiX(), self.view.logicalDpiY()
# We cannot set the side margins in the webview as there is no right
# margin for the last page (the margins are implemented with
# -webkit-column-gap)
ml, mr = opts.margin_left, opts.margin_right ml, mr = opts.margin_left, opts.margin_right
margin_side = min(ml, mr)
ml, mr = ml - margin_side, mr - margin_side
self.doc = PdfDevice(out_stream, page_size=page_size, left_margin=ml, self.doc = PdfDevice(out_stream, page_size=page_size, left_margin=ml,
top_margin=0, right_margin=mr, bottom_margin=0, top_margin=0, right_margin=mr, bottom_margin=0,
xdpi=xdpi, ydpi=ydpi, errors=self.log.error, xdpi=xdpi, ydpi=ydpi, errors=self.log.error,
@ -162,9 +163,7 @@ class PDFWriter(QObject):
self.total_items = len(items) self.total_items = len(items)
mt, mb = map(self.doc.to_px, (opts.margin_top, opts.margin_bottom)) mt, mb = map(self.doc.to_px, (opts.margin_top, opts.margin_bottom))
ms = self.doc.to_px(margin_side, vertical=False) self.margin_top, self.margin_bottom = map(lambda x:int(floor(x)), (mt, mb))
self.margin_top, self.margin_size, self.margin_bottom = map(
lambda x:int(floor(x)), (mt, ms, mb))
self.painter = QPainter(self.doc) self.painter = QPainter(self.doc)
self.doc.set_metadata(title=pdf_metadata.title, self.doc.set_metadata(title=pdf_metadata.title,
@ -185,7 +184,8 @@ class PDFWriter(QObject):
self.painter.restore() self.painter.restore()
QTimer.singleShot(0, self.render_book) QTimer.singleShot(0, self.render_book)
self.loop.exec_() if self.loop.exec_() == 1:
raise Exception('PDF Output failed, see log for details')
if self.toc is not None and len(self.toc) > 0: if self.toc is not None and len(self.toc) > 0:
self.doc.add_outline(self.toc) self.doc.add_outline(self.toc)
@ -258,7 +258,7 @@ class PDFWriter(QObject):
paged_display.layout(); paged_display.layout();
paged_display.fit_images(); paged_display.fit_images();
py_bridge.value = book_indexing.all_links_and_anchors(); py_bridge.value = book_indexing.all_links_and_anchors();
'''%(self.margin_top, self.margin_size, self.margin_bottom)) '''%(self.margin_top, 0, self.margin_bottom))
amap = self.bridge_value amap = self.bridge_value
if not isinstance(amap, dict): if not isinstance(amap, dict):

View File

@ -11,7 +11,7 @@ from math import sqrt
from collections import namedtuple from collections import namedtuple
from PyQt4.Qt import ( from PyQt4.Qt import (
QBrush, QPen, Qt, QPointF, QTransform, QPainterPath, QPaintEngine, QImage) QBrush, QPen, Qt, QPointF, QTransform, QPaintEngine, QImage)
from calibre.ebooks.pdf.render.common import ( from calibre.ebooks.pdf.render.common import (
Name, Array, fmtnum, Stream, Dictionary) Name, Array, fmtnum, Stream, Dictionary)
@ -248,7 +248,7 @@ class TexturePattern(TilingPattern):
class GraphicsState(object): class GraphicsState(object):
FIELDS = ('fill', 'stroke', 'opacity', 'transform', 'brush_origin', FIELDS = ('fill', 'stroke', 'opacity', 'transform', 'brush_origin',
'clip', 'do_fill', 'do_stroke') 'clip_updated', 'do_fill', 'do_stroke')
def __init__(self): def __init__(self):
self.fill = QBrush() self.fill = QBrush()
@ -256,7 +256,7 @@ class GraphicsState(object):
self.opacity = 1.0 self.opacity = 1.0
self.transform = QTransform() self.transform = QTransform()
self.brush_origin = QPointF() self.brush_origin = QPointF()
self.clip = QPainterPath() self.clip_updated = False
self.do_fill = False self.do_fill = False
self.do_stroke = True self.do_stroke = True
self.qt_pattern_cache = {} self.qt_pattern_cache = {}
@ -274,7 +274,7 @@ class GraphicsState(object):
ans.opacity = self.opacity ans.opacity = self.opacity
ans.transform = self.transform * QTransform() ans.transform = self.transform * QTransform()
ans.brush_origin = QPointF(self.brush_origin) ans.brush_origin = QPointF(self.brush_origin)
ans.clip = self.clip ans.clip_updated = self.clip_updated
ans.do_fill, ans.do_stroke = self.do_fill, self.do_stroke ans.do_fill, ans.do_stroke = self.do_fill, self.do_stroke
return ans return ans
@ -311,7 +311,7 @@ class Graphics(object):
s.opacity = state.opacity() s.opacity = state.opacity()
if flags & QPaintEngine.DirtyClipPath or flags & QPaintEngine.DirtyClipRegion: if flags & QPaintEngine.DirtyClipPath or flags & QPaintEngine.DirtyClipRegion:
s.clip = painter.clipPath() s.clip_updated = True
def reset(self): def reset(self):
self.current_state = GraphicsState() self.current_state = GraphicsState()
@ -326,7 +326,7 @@ class Graphics(object):
ps = self.pending_state ps = self.pending_state
pdf = self.pdf pdf = self.pdf
if (ps.transform != pdf_state.transform or ps.clip != pdf_state.clip): if ps.transform != pdf_state.transform or ps.clip_updated:
pdf.restore_stack() pdf.restore_stack()
pdf.save_stack() pdf.save_stack()
pdf_state = self.base_state pdf_state = self.base_state
@ -341,11 +341,14 @@ class Graphics(object):
pdf_state.brush_origin != ps.brush_origin): pdf_state.brush_origin != ps.brush_origin):
self.apply_fill(ps, pdf_system, painter) self.apply_fill(ps, pdf_system, painter)
if (pdf_state.clip != ps.clip): if ps.clip_updated:
p = convert_path(ps.clip) ps.clip_updated = False
fill_rule = {Qt.OddEvenFill:'evenodd', path = painter.clipPath()
Qt.WindingFill:'winding'}[ps.clip.fillRule()] if not path.isEmpty():
pdf.add_clip(p, fill_rule=fill_rule) p = convert_path(path)
fill_rule = {Qt.OddEvenFill:'evenodd',
Qt.WindingFill:'winding'}[path.fillRule()]
pdf.add_clip(p, fill_rule=fill_rule)
self.current_state = self.pending_state self.current_state = self.pending_state
self.pending_state = None self.pending_state = None

View File

@ -766,6 +766,26 @@ class Translator(QTranslator):
gui_thread = None gui_thread = None
qt_app = None qt_app = None
def load_builtin_fonts():
global _rating_font
# Load the builtin fonts and any fonts added to calibre by the user to
# Qt
for ff in glob.glob(P('fonts/liberation/*.?tf')) + \
[P('fonts/calibreSymbols.otf')] + \
glob.glob(os.path.join(config_dir, 'fonts', '*.?tf')):
if ff.rpartition('.')[-1].lower() in {'ttf', 'otf'}:
with open(ff, 'rb') as s:
# Windows requires font files to be executable for them to be
# loaded successfully, so we use the in memory loader
fid = QFontDatabase.addApplicationFontFromData(s.read())
if fid > -1:
fam = QFontDatabase.applicationFontFamilies(fid)
fam = set(map(unicode, fam))
if u'calibre Symbols' in fam:
_rating_font = u'calibre Symbols'
class Application(QApplication): class Application(QApplication):
def __init__(self, args, force_calibre_style=False, def __init__(self, args, force_calibre_style=False,
@ -798,27 +818,12 @@ class Application(QApplication):
return ret return ret
def load_builtin_fonts(self, scan_for_fonts=False): def load_builtin_fonts(self, scan_for_fonts=False):
global _rating_font
if scan_for_fonts: if scan_for_fonts:
from calibre.utils.fonts.scanner import font_scanner from calibre.utils.fonts.scanner import font_scanner
# Start scanning the users computer for fonts # Start scanning the users computer for fonts
font_scanner font_scanner
# Load the builtin fonts and any fonts added to calibre by the user to load_builtin_fonts()
# Qt
for ff in glob.glob(P('fonts/liberation/*.?tf')) + \
[P('fonts/calibreSymbols.otf')] + \
glob.glob(os.path.join(config_dir, 'fonts', '*.?tf')):
if ff.rpartition('.')[-1].lower() in {'ttf', 'otf'}:
with open(ff, 'rb') as s:
# Windows requires font files to be executable for them to be
# loaded successfully, so we use the in memory loader
fid = QFontDatabase.addApplicationFontFromData(s.read())
if fid > -1:
fam = QFontDatabase.applicationFontFamilies(fid)
fam = set(map(unicode, fam))
if u'calibre Symbols' in fam:
_rating_font = u'calibre Symbols'
def load_calibre_style(self): def load_calibre_style(self):
# On OS X QtCurve resets the palette, so we preserve it explicitly # On OS X QtCurve resets the palette, so we preserve it explicitly

View File

@ -1109,8 +1109,8 @@ not multiple and the destination field is multiple</string>
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>205</width> <width>934</width>
<height>66</height> <height>213</height>
</rect> </rect>
</property> </property>
<layout class="QGridLayout" name="testgrid"> <layout class="QGridLayout" name="testgrid">
@ -1269,8 +1269,8 @@ not multiple and the destination field is multiple</string>
<slot>accept()</slot> <slot>accept()</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>252</x> <x>258</x>
<y>382</y> <y>638</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>157</x> <x>157</x>
@ -1285,8 +1285,8 @@ not multiple and the destination field is multiple</string>
<slot>reject()</slot> <slot>reject()</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>320</x> <x>326</x>
<y>382</y> <y>638</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>286</x> <x>286</x>
@ -1294,5 +1294,37 @@ not multiple and the destination field is multiple</string>
</hint> </hint>
</hints> </hints>
</connection> </connection>
<connection>
<sender>remove_all_tags</sender>
<signal>toggled(bool)</signal>
<receiver>remove_tags</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>888</x>
<y>266</y>
</hint>
<hint type="destinationlabel">
<x>814</x>
<y>268</y>
</hint>
</hints>
</connection>
<connection>
<sender>clear_languages</sender>
<signal>toggled(bool)</signal>
<receiver>languages</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>874</x>
<y>418</y>
</hint>
<hint type="destinationlabel">
<x>817</x>
<y>420</y>
</hint>
</hints>
</connection>
</connections> </connections>
</ui> </ui>