diff --git a/resources/default_tweaks.py b/resources/default_tweaks.py index 2303c6c108..38c1685b7c 100644 --- a/resources/default_tweaks.py +++ b/resources/default_tweaks.py @@ -349,3 +349,9 @@ public_smtp_relay_delay = 301 # after a restart of calibre. draw_hidden_section_indicators = True +#: The maximum width and height for covers saved in the calibre library +# All covers in the calibre library will be resized, preserving aspect ratio, +# to fit within this size. This is to prevent slowdowns caused by extremely +# large covers +maximum_cover_size = (1200, 1600) + diff --git a/resources/recipes/leduc.recipe b/resources/recipes/leduc.recipe index 79ab693115..1412551801 100644 --- a/resources/recipes/leduc.recipe +++ b/resources/recipes/leduc.recipe @@ -1,40 +1,52 @@ from calibre.web.feeds.news import BasicNewsRecipe class AdvancedUserRecipe1292550626(BasicNewsRecipe): - title = 'Leduc - Wetaskiwin Pipestone Flyer' - __author__ = 'Brian Hahn' - description = 'News from Alberta, Canada' - oldest_article = 56 - max_articles_per_feed = 100 - no_stylesheets = True - #delay = 1 - use_embedded_content = False - publisher = 'Pipestone Publishing' - category = 'News, Alberta, Canada' - language = 'en_CA' - encoding = 'iso-8859-1' - cover_url = 'http://www.pipestoneflyer.ca/images/calibre-cover.jpg' - remove_tags_before = dict(id='ContentPanel') - remove_tags_after = dict(id='ContentPanel') - remove_tags = [dict(name='div', attrs={'id':'StoryNav'}),dict(name='div', attrs={'id':'BottomAds'}),dict(name='div', attrs={'id':'MoreStoryLinks'})] - extra_css = 'img { margin:5px }' - feeds = [ -('Feature', 'http://www.pipestoneflyer.ca/Feature.rss'), -('Editors Desk', 'http://www.pipestoneflyer.ca/Editor%27s%20Desk.rss'), -('Letters', 'http://www.pipestoneflyer.ca/Letters.rss'), -('A Loco Viewpoint', 'http://www.pipestoneflyer.ca/A%20Loco%20Viewpoint.rss'), -('Lifes Doorway', 'http://www.pipestoneflyer.ca/Life%27s%20Doorway.rss'), -('From the Otherside', 'http://www.pipestoneflyer.ca/From%20the%20Otherside.rss'), -('Opinion', 'http://www.pipestoneflyer.ca/Opinion.rss'), -('Community', 'http://www.pipestoneflyer.ca/Community.rss'), -('Sports', 'http://www.pipestoneflyer.ca/Sports.rss'), -('Chambers', 'http://www.pipestoneflyer.ca/Chambers.rss'), -('Government', 'http://www.pipestoneflyer.ca/Government.rss'), -('Environment', 'http://www.pipestoneflyer.ca/Environment.rss'), -('Health', 'http://www.pipestoneflyer.ca/Health.rss'), -('Funnies', 'http://www.pipestoneflyer.ca/Funnies.rss'), -('Faith', 'http://www.pipestoneflyer.ca/Faith.rss'), -('News and Views', 'http://www.pipestoneflyer.ca/News%20and%20Views.rss'), -('Obituaries', 'http://www.pipestoneflyer.ca/Obituaries.rss'), -('Police Blotter', 'http://www.pipestoneflyer.ca/Police%20Blotter.rss'), -] + title = 'Leduc - Wetaskiwin Pipestone Flyer' + __author__ = 'Brian Hahn' + description = '''Provides news from central Alberta, Canada. This is a + weekly publication that provides coverage from the Cities of Leduc and + Wetaskiwin, including news from two complete counties, plus the towns and + villages within. The counties of Leduc and Wetaskiwin provide news + coverage of agriculture, sports, government, family, events and opinion. + This publication updated weekly every Thursday.''' + oldest_article = 13 + max_articles_per_feed = 100 + no_stylesheets = True + #delay = 1 + use_embedded_content = False + publisher = 'Pipestone Publishing' + category = 'News, Alberta, Canada' + language = 'en_CA' + encoding = 'iso-8859-1' + cover_url = 'http://www.pipestoneflyer.ca/images/calibre-cover.jpg' + remove_tags_before = dict(id='ContentPanel') + remove_tags_after = dict(id='ContentPanel') + remove_tags = [dict(name='div', + attrs={'id':'StoryNav'}),dict(name='div', + attrs={'id':'BottomAds'}),dict(name='div', attrs={'id':'MoreStoryLinks'})] + extra_css = 'img { margin:5px }' + feeds = [ + ('Feature', 'http://www.pipestoneflyer.ca/Feature.rss'), + ('Editors Desk', 'http://www.pipestoneflyer.ca/Editor%27s%20Desk.rss'), + ('Letters', 'http://www.pipestoneflyer.ca/Letters.rss'), + ('A Loco Viewpoint', + 'http://www.pipestoneflyer.ca/A%20Loco%20Viewpoint.rss'), + ('Lifes Doorway', 'http://www.pipestoneflyer.ca/Life%27s%20Doorway.rss'), + ('From the Otherside', + 'http://www.pipestoneflyer.ca/From%20the%20Otherside.rss'), + ('Opinion', 'http://www.pipestoneflyer.ca/Opinion.rss'), + ('Community', 'http://www.pipestoneflyer.ca/Community.rss'), + ('Sports', 'http://www.pipestoneflyer.ca/Sports.rss'), + ('Chambers', 'http://www.pipestoneflyer.ca/Chambers.rss'), + ('Government', 'http://www.pipestoneflyer.ca/Government.rss'), + ('Travel ', 'http://www.pipestoneflyer.ca/Travel%20.rss'), + ('Environment', 'http://www.pipestoneflyer.ca/Environment.rss'), + ('Health', 'http://www.pipestoneflyer.ca/Health.rss'), + ('Funnies', 'http://www.pipestoneflyer.ca/Funnies.rss'), + ('Events', 'http://www.pipestoneflyer.ca/Events.rss'), + ('Faith', 'http://www.pipestoneflyer.ca/Faith.rss'), + ('News and Views', 'http://www.pipestoneflyer.ca/News%20and%20Views.rss'), + ('Obituaries', 'http://www.pipestoneflyer.ca/Obituaries.rss'), + ('Police Blotter', 'http://www.pipestoneflyer.ca/Police%20Blotter.rss'), + ('Careers', 'http://www.pipestoneflyer.ca/Careers.rss'), + ] diff --git a/src/calibre/ebooks/pdf/reflow.cpp b/src/calibre/ebooks/pdf/reflow.cpp index 0c569fe0d1..e444c126ab 100644 --- a/src/calibre/ebooks/pdf/reflow.cpp +++ b/src/calibre/ebooks/pdf/reflow.cpp @@ -887,7 +887,7 @@ vector* Reflow::render_first_page(bool use_crop_box, double x_res, } pg_w *= x_res/72.; - pg_h *= x_res/72.; + pg_h *= y_res/72.; int x=0, y=0; this->doc->displayPageSlice(out, pg, x_res, y_res, 0, diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 2554df93e6..e7d55da9df 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -37,7 +37,7 @@ from calibre.utils.config import prefs, tweaks, from_json, to_json from calibre.utils.icu import sort_key from calibre.utils.search_query_parser import saved_searches, set_saved_searches from calibre.ebooks import BOOK_EXTENSIONS, check_ebook_format -from calibre.utils.magick.draw import save_cover_data_to +from calibre.utils.magick.draw import minify_image, save_cover_data_to from calibre.utils.recycle_bin import delete_file, delete_tree from calibre.utils.formatter_functions import load_user_template_functions @@ -951,6 +951,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): if callable(getattr(data, 'read', None)): data = data.read() try: + data = minify_image(data, tweaks['maximum_cover_size']) save_cover_data_to(data, path) except (IOError, OSError): time.sleep(0.2) diff --git a/src/calibre/utils/magick/draw.py b/src/calibre/utils/magick/draw.py index 04cce5efe3..615aab9bd0 100644 --- a/src/calibre/utils/magick/draw.py +++ b/src/calibre/utils/magick/draw.py @@ -12,6 +12,34 @@ from calibre.constants import __appname__, __version__ from calibre.utils.config import tweaks from calibre import fit_image +def _data_to_image(data): + if isinstance(data, Image): + img = data + else: + img = Image() + img.load(data) + return img + +def minify_image(data, minify_to=(1200, 1600), preserve_aspect_ratio=True): + ''' + Minify image to specified size if image is bigger than specified + size and return minified image, otherwise, original image is + returned. + + :param data: Image data as bytestring or Image object + :param minify_to: A tuple (width, height) to specify target size + :param preserve_aspect_ratio: whether preserve original aspect ratio + ''' + img = _data_to_image(data) + owidth, oheight = img.size + nwidth, nheight = minify_to + if owidth <= nwidth and oheight <= nheight: + return img + if preserve_aspect_ratio: + scaled, nwidth, nheight = fit_image(owidth, oheight, nwidth, nheight) + img.size = (nwidth, nheight) + return img + def normalize_format_name(fmt): fmt = fmt.lower() if fmt == 'jpeg': @@ -35,11 +63,7 @@ def save_cover_data_to(data, path, bgcolor='#ffffff', resize_to=None, ''' changed = False - if isinstance(data, Image): - img = data - else: - img = Image() - img.load(data) + img = _data_to_image(data) orig_fmt = normalize_format_name(img.format) fmt = os.path.splitext(path)[1] fmt = normalize_format_name(fmt[1:])