mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Conversion: Add an option to embed a font family into the book. The embedded font is used as the base font for all text that does not specify its own font family in the input document. Works only with output formats that support font embedding, principally EPUB/AZW3. Option is found under Look & Feel in the conversion dialog
This commit is contained in:
parent
21f8c69496
commit
7e96216b58
@ -132,7 +132,7 @@ def add_pipeline_options(parser, plumber):
|
|||||||
_('Options to control the look and feel of the output'),
|
_('Options to control the look and feel of the output'),
|
||||||
[
|
[
|
||||||
'base_font_size', 'disable_font_rescaling',
|
'base_font_size', 'disable_font_rescaling',
|
||||||
'font_size_mapping',
|
'font_size_mapping', 'embed_font_family',
|
||||||
'line_height', 'minimum_line_height',
|
'line_height', 'minimum_line_height',
|
||||||
'linearize_tables',
|
'linearize_tables',
|
||||||
'extra_css', 'filter_css',
|
'extra_css', 'filter_css',
|
||||||
|
@ -193,6 +193,17 @@ OptionRecommendation(name='line_height',
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
|
OptionRecommendation(name='embed_font_family',
|
||||||
|
recommended_value=None, level=OptionRecommendation.LOW,
|
||||||
|
help=_(
|
||||||
|
'Embed the specified font family into the book. This specifies '
|
||||||
|
'the "base" font used for the book. If the input document '
|
||||||
|
'specifies its own fonts, they may override this base font. '
|
||||||
|
'You can use the filter style information option to remove fonts from the '
|
||||||
|
'input document. Note that font embedding only works '
|
||||||
|
'with some output formats, principally EPUB and AZW3.')
|
||||||
|
),
|
||||||
|
|
||||||
OptionRecommendation(name='linearize_tables',
|
OptionRecommendation(name='linearize_tables',
|
||||||
recommended_value=False, level=OptionRecommendation.LOW,
|
recommended_value=False, level=OptionRecommendation.LOW,
|
||||||
help=_('Some badly designed documents use tables to control the '
|
help=_('Some badly designed documents use tables to control the '
|
||||||
|
@ -14,9 +14,11 @@ from lxml import etree
|
|||||||
import cssutils
|
import cssutils
|
||||||
from cssutils.css import Property
|
from cssutils.css import Property
|
||||||
|
|
||||||
|
from calibre import guess_type
|
||||||
from calibre.ebooks.oeb.base import (XHTML, XHTML_NS, CSS_MIME, OEB_STYLES,
|
from calibre.ebooks.oeb.base import (XHTML, XHTML_NS, CSS_MIME, OEB_STYLES,
|
||||||
namespace, barename, XPath)
|
namespace, barename, XPath)
|
||||||
from calibre.ebooks.oeb.stylizer import Stylizer
|
from calibre.ebooks.oeb.stylizer import Stylizer
|
||||||
|
from calibre.utils.filenames import ascii_filename
|
||||||
|
|
||||||
COLLAPSE = re.compile(r'[ \t\r\n\v]+')
|
COLLAPSE = re.compile(r'[ \t\r\n\v]+')
|
||||||
STRIPNUM = re.compile(r'[-0-9]+$')
|
STRIPNUM = re.compile(r'[-0-9]+$')
|
||||||
@ -144,11 +146,61 @@ class CSSFlattener(object):
|
|||||||
cssutils.replaceUrls(item.data, item.abshref,
|
cssutils.replaceUrls(item.data, item.abshref,
|
||||||
ignoreImportRules=True)
|
ignoreImportRules=True)
|
||||||
|
|
||||||
|
self.body_font_family, self.embed_font_rules = self.get_embed_font_info(
|
||||||
|
self.opts.embed_font_family)
|
||||||
self.stylize_spine()
|
self.stylize_spine()
|
||||||
self.sbase = self.baseline_spine() if self.fbase else None
|
self.sbase = self.baseline_spine() if self.fbase else None
|
||||||
self.fmap = FontMapper(self.sbase, self.fbase, self.fkey)
|
self.fmap = FontMapper(self.sbase, self.fbase, self.fkey)
|
||||||
self.flatten_spine()
|
self.flatten_spine()
|
||||||
|
|
||||||
|
def get_embed_font_info(self, family, failure_critical=True):
|
||||||
|
efi = []
|
||||||
|
body_font_family = None
|
||||||
|
if not family:
|
||||||
|
return body_font_family, efi
|
||||||
|
from calibre.utils.fonts import fontconfig
|
||||||
|
from calibre.utils.fonts.utils import (get_font_characteristics,
|
||||||
|
panose_to_css_generic_family, get_font_names)
|
||||||
|
faces = fontconfig.fonts_for_family(family)
|
||||||
|
if not faces or not u'normal' in faces:
|
||||||
|
msg = (u'No embeddable fonts found for family: %r'%self.opts.embed_font_family)
|
||||||
|
if failure_critical:
|
||||||
|
raise ValueError(msg)
|
||||||
|
self.oeb.log.warn(msg)
|
||||||
|
return body_font_family, efi
|
||||||
|
|
||||||
|
for k, v in faces.iteritems():
|
||||||
|
ext, data = v[0::2]
|
||||||
|
weight, is_italic, is_bold, is_regular, fs_type, panose = \
|
||||||
|
get_font_characteristics(data)
|
||||||
|
generic_family = panose_to_css_generic_family(panose)
|
||||||
|
family_name, subfamily_name, full_name = get_font_names(data)
|
||||||
|
if k == u'normal':
|
||||||
|
body_font_family = u"'%s',%s"%(family_name, generic_family)
|
||||||
|
if family_name.lower() != family.lower():
|
||||||
|
self.oeb.log.warn(u'Failed to find an exact match for font:'
|
||||||
|
u' %r, using %r instead'%(family, family_name))
|
||||||
|
else:
|
||||||
|
self.oeb.log(u'Embedding font: %s'%family_name)
|
||||||
|
font = {u'font-family':u'"%s"'%family_name}
|
||||||
|
if is_italic:
|
||||||
|
font[u'font-style'] = u'italic'
|
||||||
|
if is_bold:
|
||||||
|
font[u'font-weight'] = u'bold'
|
||||||
|
fid, href = self.oeb.manifest.generate(id=u'font',
|
||||||
|
href=u'%s.%s'%(ascii_filename(full_name).replace(u' ', u'-'), ext))
|
||||||
|
item = self.oeb.manifest.add(fid, href,
|
||||||
|
guess_type(full_name+'.'+ext)[0],
|
||||||
|
data=data)
|
||||||
|
item.unload_data_from_memory()
|
||||||
|
font[u'src'] = u'url(%s)'%item.href
|
||||||
|
rule = '@font-face { %s }'%('; '.join(u'%s:%s'%(k, v) for k, v in
|
||||||
|
font.iteritems()))
|
||||||
|
rule = cssutils.parseString(rule)
|
||||||
|
efi.append(rule)
|
||||||
|
|
||||||
|
return body_font_family, efi
|
||||||
|
|
||||||
def stylize_spine(self):
|
def stylize_spine(self):
|
||||||
self.stylizers = {}
|
self.stylizers = {}
|
||||||
profile = self.context.source
|
profile = self.context.source
|
||||||
@ -170,6 +222,8 @@ class CSSFlattener(object):
|
|||||||
bs.extend(['page-break-before: always'])
|
bs.extend(['page-break-before: always'])
|
||||||
if self.context.change_justification != 'original':
|
if self.context.change_justification != 'original':
|
||||||
bs.append('text-align: '+ self.context.change_justification)
|
bs.append('text-align: '+ self.context.change_justification)
|
||||||
|
if self.body_font_family:
|
||||||
|
bs.append(u'font-family: '+self.body_font_family)
|
||||||
body.set('style', '; '.join(bs))
|
body.set('style', '; '.join(bs))
|
||||||
stylizer = Stylizer(html, item.href, self.oeb, self.context, profile,
|
stylizer = Stylizer(html, item.href, self.oeb, self.context, profile,
|
||||||
user_css=self.context.extra_css,
|
user_css=self.context.extra_css,
|
||||||
@ -450,7 +504,8 @@ class CSSFlattener(object):
|
|||||||
items.sort()
|
items.sort()
|
||||||
css = ';\n'.join("%s: %s" % (key, val) for key, val in items)
|
css = ';\n'.join("%s: %s" % (key, val) for key, val in items)
|
||||||
css = ('@page {\n%s\n}\n'%css) if items else ''
|
css = ('@page {\n%s\n}\n'%css) if items else ''
|
||||||
rules = [r.cssText for r in stylizer.font_face_rules]
|
rules = [r.cssText for r in stylizer.font_face_rules +
|
||||||
|
self.embed_font_rules]
|
||||||
raw = '\n\n'.join(rules)
|
raw = '\n\n'.join(rules)
|
||||||
css += '\n\n' + raw
|
css += '\n\n' + raw
|
||||||
global_css[css].append(item)
|
global_css[css].append(item)
|
||||||
|
@ -32,6 +32,7 @@ class LookAndFeelWidget(Widget, Ui_Form):
|
|||||||
Widget.__init__(self, parent,
|
Widget.__init__(self, parent,
|
||||||
['change_justification', 'extra_css', 'base_font_size',
|
['change_justification', 'extra_css', 'base_font_size',
|
||||||
'font_size_mapping', 'line_height', 'minimum_line_height',
|
'font_size_mapping', 'line_height', 'minimum_line_height',
|
||||||
|
'embed_font_family',
|
||||||
'smarten_punctuation', 'unsmarten_punctuation',
|
'smarten_punctuation', 'unsmarten_punctuation',
|
||||||
'disable_font_rescaling', 'insert_blank_line',
|
'disable_font_rescaling', 'insert_blank_line',
|
||||||
'remove_paragraph_spacing',
|
'remove_paragraph_spacing',
|
||||||
|
@ -14,6 +14,26 @@
|
|||||||
<string>Form</string>
|
<string>Form</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="3" column="4">
|
||||||
|
<widget class="QDoubleSpinBox" name="opt_line_height">
|
||||||
|
<property name="suffix">
|
||||||
|
<string> pt</string>
|
||||||
|
</property>
|
||||||
|
<property name="decimals">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="3">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Line &height:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_line_height</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QLabel" name="label_6">
|
<widget class="QLabel" name="label_6">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -37,26 +57,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>Line &height:</string>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
|
||||||
<cstring>opt_line_height</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="1">
|
|
||||||
<widget class="QDoubleSpinBox" name="opt_line_height">
|
|
||||||
<property name="suffix">
|
|
||||||
<string> pt</string>
|
|
||||||
</property>
|
|
||||||
<property name="decimals">
|
|
||||||
<number>1</number>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QDoubleSpinBox" name="opt_base_font_size">
|
<widget class="QDoubleSpinBox" name="opt_base_font_size">
|
||||||
<property name="suffix">
|
<property name="suffix">
|
||||||
@ -140,14 +140,14 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="0" colspan="2">
|
<item row="7" column="0" colspan="2">
|
||||||
<widget class="QCheckBox" name="opt_remove_paragraph_spacing">
|
<widget class="QCheckBox" name="opt_remove_paragraph_spacing">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Remove &spacing between paragraphs</string>
|
<string>Remove &spacing between paragraphs</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="3">
|
<item row="7" column="3">
|
||||||
<widget class="QLabel" name="label_4">
|
<widget class="QLabel" name="label_4">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Indent size:</string>
|
<string>&Indent size:</string>
|
||||||
@ -160,7 +160,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="4">
|
<item row="7" column="4">
|
||||||
<widget class="QDoubleSpinBox" name="opt_remove_paragraph_spacing_indent_size">
|
<widget class="QDoubleSpinBox" name="opt_remove_paragraph_spacing_indent_size">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><p>When calibre removes inter paragraph spacing, it automatically sets a paragraph indent, to ensure that paragraphs can be easily distinguished. This option controls the width of that indent.</string>
|
<string><p>When calibre removes inter paragraph spacing, it automatically sets a paragraph indent, to ensure that paragraphs can be easily distinguished. This option controls the width of that indent.</string>
|
||||||
@ -182,72 +182,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="7" column="0" colspan="2">
|
<item row="12" column="0" colspan="5">
|
||||||
<widget class="QCheckBox" name="opt_insert_blank_line">
|
|
||||||
<property name="text">
|
|
||||||
<string>Insert &blank line between paragraphs</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="7" column="4">
|
|
||||||
<widget class="QDoubleSpinBox" name="opt_insert_blank_line_size">
|
|
||||||
<property name="suffix">
|
|
||||||
<string> em</string>
|
|
||||||
</property>
|
|
||||||
<property name="decimals">
|
|
||||||
<number>1</number>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="8" column="0">
|
|
||||||
<widget class="QLabel" name="label_5">
|
|
||||||
<property name="text">
|
|
||||||
<string>Text &justification:</string>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
|
||||||
<cstring>opt_change_justification</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="8" column="2" colspan="3">
|
|
||||||
<widget class="QComboBox" name="opt_change_justification"/>
|
|
||||||
</item>
|
|
||||||
<item row="9" column="0">
|
|
||||||
<widget class="QCheckBox" name="opt_smarten_punctuation">
|
|
||||||
<property name="text">
|
|
||||||
<string>Smarten &punctuation</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="9" column="1" colspan="4">
|
|
||||||
<widget class="QCheckBox" name="opt_asciiize">
|
|
||||||
<property name="text">
|
|
||||||
<string>&Transliterate unicode characters to ASCII</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="10" column="0">
|
|
||||||
<widget class="QCheckBox" name="opt_unsmarten_punctuation">
|
|
||||||
<property name="text">
|
|
||||||
<string>&UnSmarten punctuation</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="10" column="1" colspan="2">
|
|
||||||
<widget class="QCheckBox" name="opt_keep_ligatures">
|
|
||||||
<property name="text">
|
|
||||||
<string>Keep &ligatures</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="10" column="3">
|
|
||||||
<widget class="QCheckBox" name="opt_linearize_tables">
|
|
||||||
<property name="text">
|
|
||||||
<string>&Linearize tables</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="11" column="0" colspan="5">
|
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
@ -365,10 +300,68 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
<item row="8" column="0" colspan="2">
|
||||||
<widget class="QCheckBox" name="opt_disable_font_rescaling">
|
<widget class="QCheckBox" name="opt_insert_blank_line">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Disable font size rescaling</string>
|
<string>Insert &blank line between paragraphs</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="4">
|
||||||
|
<widget class="QDoubleSpinBox" name="opt_insert_blank_line_size">
|
||||||
|
<property name="suffix">
|
||||||
|
<string> em</string>
|
||||||
|
</property>
|
||||||
|
<property name="decimals">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="9" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Text &justification:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_change_justification</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="9" column="2" colspan="3">
|
||||||
|
<widget class="QComboBox" name="opt_change_justification"/>
|
||||||
|
</item>
|
||||||
|
<item row="10" column="0">
|
||||||
|
<widget class="QCheckBox" name="opt_smarten_punctuation">
|
||||||
|
<property name="text">
|
||||||
|
<string>Smarten &punctuation</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="10" column="1" colspan="4">
|
||||||
|
<widget class="QCheckBox" name="opt_asciiize">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Transliterate unicode characters to ASCII</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="11" column="0">
|
||||||
|
<widget class="QCheckBox" name="opt_unsmarten_punctuation">
|
||||||
|
<property name="text">
|
||||||
|
<string>&UnSmarten punctuation</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="11" column="1" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="opt_keep_ligatures">
|
||||||
|
<property name="text">
|
||||||
|
<string>Keep &ligatures</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="11" column="3">
|
||||||
|
<widget class="QCheckBox" name="opt_linearize_tables">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Linearize tables</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -382,7 +375,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="7" column="3">
|
<item row="8" column="3">
|
||||||
<widget class="QLabel" name="label_7">
|
<widget class="QLabel" name="label_7">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Line size:</string>
|
<string>&Line size:</string>
|
||||||
@ -395,6 +388,26 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QLabel" name="label_10">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Embed font family:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_embed_font_family</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0" colspan="5">
|
||||||
|
<widget class="QCheckBox" name="opt_disable_font_rescaling">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Disable font size rescaling</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="1" colspan="2">
|
||||||
|
<widget class="FontFamilyChooser" name="opt_embed_font_family"/>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
@ -403,6 +416,11 @@
|
|||||||
<extends>QComboBox</extends>
|
<extends>QComboBox</extends>
|
||||||
<header>widgets.h</header>
|
<header>widgets.h</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>FontFamilyChooser</class>
|
||||||
|
<extends>QComboBox</extends>
|
||||||
|
<header>calibre/gui2/font_family_chooser.h</header>
|
||||||
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../../../../resources/images.qrc"/>
|
<include location="../../../../resources/images.qrc"/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user