mirror of
				https://github.com/kovidgoyal/calibre.git
				synced 2025-10-31 10:37:00 -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,6 +831,9 @@ class EPUB_MOBI(CatalogPlugin): | ||||
|             # Merge opts.exclude_tag with opts.search_text | ||||
| 
 | ||||
|             # What if no exclude tags? | ||||
|             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: | ||||
| @ -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) | ||||
|             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