mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
MOBI Output: Make font used for generated masthead images user customizable. Various catalog fixes.
This commit is contained in:
commit
bae592ae3a
@ -42,6 +42,7 @@ def gui_catalog(fmt, title, dbspec, ids, out_file_name, sync, fmt_options,
|
||||
opts, args = parser.parse_args()
|
||||
|
||||
# Populate opts
|
||||
# opts.gui_search_text = something
|
||||
opts.catalog_title = title
|
||||
opts.ids = ids
|
||||
opts.search_text = None
|
||||
|
@ -6,9 +6,14 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from PyQt4.Qt import Qt
|
||||
|
||||
from calibre.gui2.convert.mobi_output_ui import Ui_Form
|
||||
from calibre.gui2.convert import Widget
|
||||
from calibre.gui2.widgets import FontFamilyModel
|
||||
from calibre.utils.fonts import fontconfig
|
||||
|
||||
font_family_model = None
|
||||
|
||||
class PluginWidget(Widget, Ui_Form):
|
||||
|
||||
@ -19,8 +24,35 @@ class PluginWidget(Widget, Ui_Form):
|
||||
def __init__(self, parent, get_option, get_help, db=None, book_id=None):
|
||||
Widget.__init__(self, parent, 'mobi_output',
|
||||
['prefer_author_sort', 'rescale_images', 'toc_title',
|
||||
'dont_compress', 'no_inline_toc']
|
||||
'dont_compress', 'no_inline_toc', 'masthead_font']
|
||||
)
|
||||
self.db, self.book_id = db, book_id
|
||||
|
||||
global font_family_model
|
||||
if font_family_model is None:
|
||||
font_family_model = FontFamilyModel()
|
||||
try:
|
||||
font_family_model.families = fontconfig.find_font_families(allowed_extensions=['ttf'])
|
||||
except:
|
||||
import traceback
|
||||
font_family_model.families = []
|
||||
print 'WARNING: Could not load fonts'
|
||||
traceback.print_exc()
|
||||
font_family_model.families.sort()
|
||||
font_family_model.families[:0] = [_('Default')]
|
||||
|
||||
self.font_family_model = font_family_model
|
||||
self.opt_masthead_font.setModel(self.font_family_model)
|
||||
|
||||
self.initialize_options(get_option, get_help, db, book_id)
|
||||
|
||||
def set_value_handler(self, g, val):
|
||||
if unicode(g.objectName()) in 'opt_masthead_font':
|
||||
idx = -1
|
||||
if val:
|
||||
idx = g.findText(val, Qt.MatchFixedString)
|
||||
if idx < 0:
|
||||
idx = 0
|
||||
g.setCurrentIndex(idx)
|
||||
return True
|
||||
return False
|
||||
|
@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<width>421</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -41,19 +41,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="opt_dont_compress">
|
||||
<property name="text">
|
||||
@ -68,6 +55,51 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Kindle options</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Masthead font:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="opt_masthead_font"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>55</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
@ -403,10 +403,15 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
right = EPUB_MOBI.NumberToText(strings[1]).text
|
||||
self.text = '%s-%s' % (left, right)
|
||||
|
||||
# Test for $xx,xxx
|
||||
elif re.search('[$,]', self.number):
|
||||
self.number_as_float = re.sub('[$,]','',self.number)
|
||||
self.text = EPUB_MOBI.NumberToText(self.number_as_float).text
|
||||
|
||||
# Test for comma
|
||||
elif re.search(',', self.number):
|
||||
self.number_as_float = re.sub(',','',self.number)
|
||||
self.text = EPUB_MOBI.NumberToText(self.number.replace(',','')).text
|
||||
self.text = EPUB_MOBI.NumberToText(self.number_as_float).text
|
||||
|
||||
# Test for hybrid e.g., 'K2'
|
||||
elif re.search('[\D]+', self.number):
|
||||
@ -482,11 +487,6 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
catalog.createDirectoryStructure()
|
||||
catalog.copyResources()
|
||||
catalog.buildSources()
|
||||
|
||||
- To do:
|
||||
*** generateThumbnails() creates a default book image from book.svg, but the background
|
||||
is black instead of white. This needs to be fixed (approx line #1418)
|
||||
|
||||
'''
|
||||
|
||||
# Number of discrete steps to catalog creation
|
||||
@ -811,7 +811,7 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
# If failure, default mastheadImage.gif should still be in place
|
||||
if self.generateForKindle:
|
||||
try:
|
||||
self.generate_masthead_image(os.path.join(self.catalogPath,
|
||||
self.generateMastheadImage(os.path.join(self.catalogPath,
|
||||
'images/mastheadImage.gif'))
|
||||
except:
|
||||
pass
|
||||
@ -831,11 +831,14 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
# Merge opts.exclude_tag with opts.search_text
|
||||
|
||||
# What if no exclude tags?
|
||||
exclude_tags = self.opts.exclude_tags.split(',')
|
||||
search_terms = []
|
||||
for tag in exclude_tags:
|
||||
search_terms.append("tag:%s" % tag)
|
||||
search_phrase = "not (%s)" % " or ".join(search_terms)
|
||||
empty_exclude_tags = False if len(self.opts.exclude_tags) else True
|
||||
search_phrase = ''
|
||||
if not empty_exclude_tags:
|
||||
exclude_tags = self.opts.exclude_tags.split(',')
|
||||
search_terms = []
|
||||
for tag in exclude_tags:
|
||||
search_terms.append("tag:%s" % tag)
|
||||
search_phrase = "not (%s)" % " or ".join(search_terms)
|
||||
|
||||
# If a list of ids are provided, don't use search_text
|
||||
if self.opts.ids:
|
||||
@ -846,6 +849,7 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
else:
|
||||
self.opts.search_text = search_phrase
|
||||
|
||||
#print "fetchBooksByTitle(): opts.search_text: %s" % self.opts.search_text
|
||||
# Fetch the database as a dictionary
|
||||
data = self.plugin.search_sort_db(self.db, self.opts)
|
||||
|
||||
@ -1455,7 +1459,6 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
|
||||
self.updateProgressFullStep("'Genres'")
|
||||
|
||||
# filtered_tags = {friendly:normalized, }
|
||||
self.genre_tags_dict = self.filterDbTags(self.db.all_tags())
|
||||
|
||||
# Extract books matching filtered_tags
|
||||
@ -2202,11 +2205,11 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
|
||||
# GwR *** Can this be optimized?
|
||||
normalized_tag = None
|
||||
for genre_tag in self.genre_tags_dict:
|
||||
if self.genre_tags_dict[genre_tag] == genre['tag']:
|
||||
normalized_tag = self.genre_tags_dict[genre_tag]
|
||||
for friendly_tag in self.genre_tags_dict:
|
||||
if self.genre_tags_dict[friendly_tag] == genre['tag']:
|
||||
normalized_tag = self.genre_tags_dict[friendly_tag]
|
||||
break
|
||||
textTag.insert(0, self.formatNCXText(NavigableString(genre_tag)))
|
||||
textTag.insert(0, self.formatNCXText(NavigableString(friendly_tag)))
|
||||
navLabelTag.insert(0,textTag)
|
||||
navPointVolumeTag.insert(0,navLabelTag)
|
||||
contentTag = Tag(ncx_soup, "content")
|
||||
@ -2312,14 +2315,6 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
if not os.path.isdir(images_path):
|
||||
os.makedirs(images_path)
|
||||
|
||||
def getMarkerTags(self):
|
||||
''' Return a list of special marker tags to be excluded from genre list '''
|
||||
markerTags = []
|
||||
markerTags.extend(self.opts.exclude_tags.split(','))
|
||||
markerTags.extend(self.opts.note_tag.split(','))
|
||||
markerTags.extend(self.opts.read_tag.split(','))
|
||||
return markerTags
|
||||
|
||||
def filterDbTags(self, tags):
|
||||
# Remove the special marker tags from the database's tag list,
|
||||
# return sorted list of normalized genre tags
|
||||
@ -2337,7 +2332,6 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
normalized_tags.append(re.sub('\W','',tag).lower())
|
||||
friendly_tags.append(tag)
|
||||
|
||||
|
||||
genre_tags_dict = dict(zip(friendly_tags,normalized_tags))
|
||||
|
||||
# Test for multiple genres resolving to same normalized form
|
||||
@ -2405,10 +2399,10 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
btc += 1
|
||||
|
||||
# Find the first instance of friendly_tag matching genre
|
||||
# GwR *** optimize
|
||||
for friendly_tag in self.genre_tags_dict:
|
||||
if self.genre_tags_dict[friendly_tag] == genre:
|
||||
break
|
||||
|
||||
titleTag = body.find(attrs={'class':'title'})
|
||||
titleTag.insert(0,NavigableString('<b><i>%s</i></b>' % escape(friendly_tag)))
|
||||
|
||||
@ -2570,8 +2564,22 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
titleTag.insert(0,escape(NavigableString(title)))
|
||||
return soup
|
||||
|
||||
def generate_masthead_image(self, out_path):
|
||||
font_path = P('fonts/liberation/LiberationSerif-Bold.ttf')
|
||||
def generateMastheadImage(self, out_path):
|
||||
from calibre.ebooks.conversion.config import load_defaults
|
||||
from calibre.utils.fonts import fontconfig
|
||||
font_path = default_font = P('fonts/liberation/LiberationSerif-Bold.ttf')
|
||||
recs = load_defaults('mobi_output')
|
||||
masthead_font_family = recs.get('masthead_font', 'Default')
|
||||
|
||||
if masthead_font_family != 'Default':
|
||||
masthead_font = fontconfig.files_for_family(masthead_font_family)
|
||||
# Assume 'normal' always in dict, else use default
|
||||
# {'normal': (path_to_font, friendly name)}
|
||||
if 'normal' in masthead_font:
|
||||
font_path = masthead_font['normal'][0]
|
||||
|
||||
if not font_path or not os.access(font_path, os.R_OK):
|
||||
font_path = default_font
|
||||
|
||||
MI_WIDTH = 600
|
||||
MI_HEIGHT = 60
|
||||
@ -2584,7 +2592,11 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
|
||||
img = Image.new('RGB', (MI_WIDTH, MI_HEIGHT), 'white')
|
||||
draw = ImageDraw.Draw(img)
|
||||
font = ImageFont.truetype(font_path, 48)
|
||||
try:
|
||||
font = ImageFont.truetype(font_path, 48)
|
||||
except:
|
||||
self.opts.log.error(" Failed to load user-specifed font '%s'" % font_path)
|
||||
font = ImageFont.truetype(default_font, 48)
|
||||
text = self.title.encode('utf-8')
|
||||
width, height = draw.textsize(text, font=font)
|
||||
left = max(int((MI_WIDTH - width)/2.), 0)
|
||||
@ -2682,6 +2694,14 @@ class EPUB_MOBI(CatalogPlugin):
|
||||
else:
|
||||
return char
|
||||
|
||||
def getMarkerTags(self):
|
||||
''' Return a list of special marker tags to be excluded from genre list '''
|
||||
markerTags = []
|
||||
markerTags.extend(self.opts.exclude_tags.split(','))
|
||||
markerTags.extend(self.opts.note_tag.split(','))
|
||||
markerTags.extend(self.opts.read_tag.split(','))
|
||||
return markerTags
|
||||
|
||||
def processSpecialTags(self, tags, this_title, opts):
|
||||
tag_list = []
|
||||
for tag in tags:
|
||||
|
@ -989,6 +989,22 @@ class BasicNewsRecipe(Recipe):
|
||||
MI_HEIGHT = 60
|
||||
|
||||
def default_masthead_image(self, out_path):
|
||||
from calibre.ebooks.conversion.config import load_defaults
|
||||
from calibre.utils.fonts import fontconfig
|
||||
font_path = default_font = P('fonts/liberation/LiberationSerif-Bold.ttf')
|
||||
recs = load_defaults('mobi_output')
|
||||
masthead_font_family = recs.get('masthead_font', 'Default')
|
||||
|
||||
if masthead_font_family != 'Default':
|
||||
masthead_font = fontconfig.files_for_family(masthead_font_family)
|
||||
# Assume 'normal' always in dict, else use default
|
||||
# {'normal': (path_to_font, friendly name)}
|
||||
if 'normal' in masthead_font:
|
||||
font_path = masthead_font['normal'][0]
|
||||
|
||||
if not font_path or not os.access(font_path, os.R_OK):
|
||||
font_path = default_font
|
||||
|
||||
try:
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
Image, ImageDraw, ImageFont
|
||||
@ -997,7 +1013,10 @@ class BasicNewsRecipe(Recipe):
|
||||
|
||||
img = Image.new('RGB', (self.MI_WIDTH, self.MI_HEIGHT), 'white')
|
||||
draw = ImageDraw.Draw(img)
|
||||
font = ImageFont.truetype(P('fonts/liberation/LiberationSerif-Bold.ttf'), 48)
|
||||
try:
|
||||
font = ImageFont.truetype(font_path, 48)
|
||||
except:
|
||||
font = ImageFont.truetype(default_font, 48)
|
||||
text = self.get_masthead_title().encode('utf-8')
|
||||
width, height = draw.textsize(text, font=font)
|
||||
left = max(int((self.MI_WIDTH - width)/2.), 0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user