diff --git a/src/calibre/ebooks/conversion/config.py b/src/calibre/ebooks/conversion/config.py index db30f2859b..168a68af6c 100644 --- a/src/calibre/ebooks/conversion/config.py +++ b/src/calibre/ebooks/conversion/config.py @@ -278,7 +278,7 @@ OPTIONS = { 'epub': ( 'dont_split_on_page_breaks', 'flow_size', 'no_default_epub_cover', 'no_svg_cover', 'epub_inline_toc', 'epub_toc_at_end', 'toc_title', - 'preserve_cover_aspect_ratio', 'epub_flatten', 'epub_version'), + 'preserve_cover_aspect_ratio', 'epub_flatten', 'epub_version', 'epub_max_image_size',), 'fb2': ('sectionize', 'fb2_genre'), diff --git a/src/calibre/ebooks/conversion/plugins/epub_output.py b/src/calibre/ebooks/conversion/plugins/epub_output.py index 012eb512b0..a6ed8e0b51 100644 --- a/src/calibre/ebooks/conversion/plugins/epub_output.py +++ b/src/calibre/ebooks/conversion/plugins/epub_output.py @@ -124,6 +124,17 @@ class EPUBOutput(OutputFormatPlugin): ' actually need it.') ), + OptionRecommendation(name='epub_max_image_size', recommended_value='none', + help=_('The maximum image size (width x height). A value of {0} means use the screen size from the output' + ' profile. A value of {1} means no maximum size is specified. For example, a value of {2}' + ' will cause all images to be resized so that their width is no more than {3} pixels and' + ' their height is no more than {4} pixels. Note that this only affects the size of the actual' + ' image files themselves. Any given image may be rendered at a different size depending on the styling' + ' applied to it in the document.' + ).format('none', 'profile', '100x200', 100, 200) + ), + + } recommendations = {('pretty_print', True, OptionRecommendation.HIGH)} @@ -196,8 +207,9 @@ class EPUBOutput(OutputFormatPlugin): self.workaround_ade_quirks() self.workaround_webkit_quirks() self.upshift_markup() + from calibre.ebooks.oeb.transforms.rescale import RescaleImages - RescaleImages(check_colorspaces=True)(oeb, opts) + RescaleImages(check_colorspaces=True)(oeb, opts, max_size=self.opts.epub_max_image_size) from calibre.ebooks.oeb.transforms.split import Split split = Split(not self.opts.dont_split_on_page_breaks, @@ -385,7 +397,6 @@ class EPUBOutput(OutputFormatPlugin): from calibre.ebooks.oeb.base import XPath, XHTML, barename, urlunquote stylesheet = self.oeb.manifest.main_stylesheet - # ADE cries big wet tears when it encounters an invalid fragment # identifier in the NCX toc. frag_pat = re.compile(r'[-A-Za-z0-9_:.]+$') diff --git a/src/calibre/ebooks/conversion/plumber.py b/src/calibre/ebooks/conversion/plumber.py index 667efa5c8b..b3a6945bad 100644 --- a/src/calibre/ebooks/conversion/plumber.py +++ b/src/calibre/ebooks/conversion/plumber.py @@ -140,7 +140,7 @@ OptionRecommendation(name='output_profile', choices=[x.short_name for x in output_profiles()], help=_('Specify the output profile. The output profile ' 'tells the conversion system how to optimize the ' - 'created document for the specified device (such as by resizing images for the device screen size). In some cases, ' + 'created document for the specified device. In some cases, ' 'an output profile can be used to optimize the output for a particular device, but this is rarely necessary. ' 'Choices are:') + ', '.join([ x.short_name for x in output_profiles()]) diff --git a/src/calibre/ebooks/oeb/transforms/rescale.py b/src/calibre/ebooks/oeb/transforms/rescale.py index 958a013316..dc7bc12475 100644 --- a/src/calibre/ebooks/oeb/transforms/rescale.py +++ b/src/calibre/ebooks/oeb/transforms/rescale.py @@ -15,11 +15,11 @@ class RescaleImages: def __init__(self, check_colorspaces=False): self.check_colorspaces = check_colorspaces - def __call__(self, oeb, opts): + def __call__(self, oeb, opts, max_size: str = 'profile'): self.oeb, self.opts, self.log = oeb, opts, oeb.log - self.rescale() + self.rescale(max_size) - def rescale(self): + def rescale(self, max_size: str = 'profile'): from PIL import Image from io import BytesIO @@ -32,6 +32,23 @@ class RescaleImages: page_width -= (self.opts.margin_left + self.opts.margin_right) * self.opts.dest.dpi/72 page_height -= (self.opts.margin_top + self.opts.margin_bottom) * self.opts.dest.dpi/72 + no_scale_size = 99999999999 + if max_size == 'none': + page_width = page_height = no_scale_size + elif max_size != 'profile': + w, __, h = max_size.strip().lower().partition('x') + try: + page_width = int(w.strip()) + except Exception: + page_width = no_scale_size + if page_width <= 0: + page_width = no_scale_size + try: + page_height = int(h.strip()) + except Exception: + page_height = no_scale_size + if page_height <= 0: + page_height = no_scale_size for item in self.oeb.manifest: if item.media_type.startswith('image'): ext = item.media_type.split('/')[-1].upper() diff --git a/src/calibre/gui2/convert/epub_output.ui b/src/calibre/gui2/convert/epub_output.ui index 448c6385b8..3370315b8b 100644 --- a/src/calibre/gui2/convert/epub_output.ui +++ b/src/calibre/gui2/convert/epub_output.ui @@ -14,10 +14,27 @@ Form - - + + - Preserve cover &aspect ratio + EP&UB version: + + + opt_epub_version + + + + + + + No default &cover + + + + + + + Insert inline &Table of Contents @@ -31,6 +48,46 @@ + + + + Qt::Vertical + + + + 20 + 262 + + + + + + + + No &SVG cover + + + + + + + + + + &Flatten EPUB file structure + + + + + + + &Title for inserted ToC: + + + opt_toc_title + + + @@ -50,47 +107,6 @@ - - - - Qt::Vertical - - - - 20 - 262 - - - - - - - - No default &cover - - - - - - - No &SVG cover - - - - - - - Insert inline &Table of Contents - - - - - - - Do not &split on page breaks - - - @@ -98,20 +114,17 @@ - - + + - &Flatten EPUB file structure + Preserve cover &aspect ratio - - + + - &Title for inserted ToC: - - - opt_toc_title + Do not &split on page breaks @@ -123,17 +136,17 @@ - + - EP&UB version: + Shrink &images larger than: - opt_epub_version + opt_epub_max_image_size - + diff --git a/src/pyj/book_list/conversion_widgets.pyj b/src/pyj/book_list/conversion_widgets.pyj index 49eb7346db..d7b94f5314 100644 --- a/src/pyj/book_list/conversion_widgets.pyj +++ b/src/pyj/book_list/conversion_widgets.pyj @@ -540,6 +540,7 @@ def epub_output(container): g.appendChild(checkbox('epub_toc_at_end', _('Put inserted Table of Contents at the &end of the book'))) g.appendChild(lineedit('toc_title', _('&Title for inserted ToC:'))) g.appendChild(int_spin('flow_size', _('Split files &larger than:'), unit='KB', max=1000000, step=20)) + g.appendChild(lineedit('epub_max_image_size', _('Shrink &images larger than:'))) g.appendChild(choices('epub_version', _('EP&UB version:'), ui_data.versions)) # }}}