mirror of
				https://github.com/kovidgoyal/calibre.git
				synced 2025-11-03 19:17:02 -05:00 
			
		
		
		
	Switch to using a C extension module to interface with fontconfig. This means that calibre now has a build time dependency on fontconfig as well. You can tell calibre where to find the font config headers and library via the environment variables: FC_INC_DIR and FC_LIB_DIR
This commit is contained in:
		
							parent
							
								
									f43a4467d3
								
							
						
					
					
						commit
						e3fabe843a
					
				@ -254,8 +254,6 @@ _check_symlinks_prescript()
 | 
				
			|||||||
        os.link(os.path.expanduser('~/pdftohtml/pdftohtml'), os.path.join(frameworks_dir, 'pdftohtml'))
 | 
					        os.link(os.path.expanduser('~/pdftohtml/pdftohtml'), os.path.join(frameworks_dir, 'pdftohtml'))
 | 
				
			||||||
        os.link(os.path.expanduser('~/pdftohtml/libpoppler.4.dylib'),
 | 
					        os.link(os.path.expanduser('~/pdftohtml/libpoppler.4.dylib'),
 | 
				
			||||||
                os.path.join(frameworks_dir, 'libpoppler.4.dylib'))
 | 
					                os.path.join(frameworks_dir, 'libpoppler.4.dylib'))
 | 
				
			||||||
        print 'Adding plugins'
 | 
					 | 
				
			||||||
        module_dir = os.path.join(resource_dir, 'lib', 'python2.6', 'lib-dynload')
 | 
					 | 
				
			||||||
        print 'Adding fontconfig'
 | 
					        print 'Adding fontconfig'
 | 
				
			||||||
        for f in glob.glob(os.path.expanduser('~/fontconfig-bundled/*')):
 | 
					        for f in glob.glob(os.path.expanduser('~/fontconfig-bundled/*')):
 | 
				
			||||||
            dest = os.path.join(frameworks_dir, os.path.basename(f))
 | 
					            dest = os.path.join(frameworks_dir, os.path.basename(f))
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										13
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								setup.py
									
									
									
									
									
								
							@ -76,8 +76,21 @@ if __name__ == '__main__':
 | 
				
			|||||||
        print 'WARNING: PoDoFo not found on your system. Various PDF related',
 | 
					        print 'WARNING: PoDoFo not found on your system. Various PDF related',
 | 
				
			||||||
        print 'functionality will not work.'
 | 
					        print 'functionality will not work.'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fc_inc = '/usr/include/fontconfig' if islinux else \
 | 
				
			||||||
 | 
					            r'C:\cygwin\home\kovid\fontconfig\include\fontconfig' if iswindows else \
 | 
				
			||||||
 | 
					            '/Users/kovid/fontconfig/include/fontconfig'
 | 
				
			||||||
 | 
					    fc_lib = '/usr/lib' if islinux else \
 | 
				
			||||||
 | 
					            r'C:\cygwin\home\kovid\fontconfig\lib' if iswindows else \
 | 
				
			||||||
 | 
					            '/Users/kovid/fontconfig/lib'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ext_modules = optional + [
 | 
					    ext_modules = optional + [
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                   Extension('calibre.plugins.fontconfig',
 | 
				
			||||||
 | 
					                       sources = ['src/calibre/utils/fonts/fontconfig.c'],
 | 
				
			||||||
 | 
					                       include_dirs = [os.environ.get('FC_INC_DIR', fc_inc)],
 | 
				
			||||||
 | 
					                       libraries=['fontconfig'],
 | 
				
			||||||
 | 
					                       library_dirs=[os.environ.get('FC_LIB_DIR', fc_lib)]),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                   Extension('calibre.plugins.lzx',
 | 
					                   Extension('calibre.plugins.lzx',
 | 
				
			||||||
                             sources=['src/calibre/utils/lzx/lzxmodule.c',
 | 
					                             sources=['src/calibre/utils/lzx/lzxmodule.c',
 | 
				
			||||||
                                      'src/calibre/utils/lzx/compressor.c',
 | 
					                                      'src/calibre/utils/lzx/compressor.c',
 | 
				
			||||||
 | 
				
			|||||||
@ -59,7 +59,8 @@ if plugins is None:
 | 
				
			|||||||
            plugin_path = getattr(pkg_resources, 'resource_filename')('calibre', 'plugins')
 | 
					            plugin_path = getattr(pkg_resources, 'resource_filename')('calibre', 'plugins')
 | 
				
			||||||
            sys.path.insert(0, plugin_path)
 | 
					            sys.path.insert(0, plugin_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for plugin in ['pictureflow', 'lzx', 'msdes', 'podofo', 'cPalmdoc'] + \
 | 
					        for plugin in ['pictureflow', 'lzx', 'msdes', 'podofo', 'cPalmdoc',
 | 
				
			||||||
 | 
					            'fontconfig'] + \
 | 
				
			||||||
                    (['winutil'] if iswindows else []) + \
 | 
					                    (['winutil'] if iswindows else []) + \
 | 
				
			||||||
                    (['usbobserver'] if isosx else []):
 | 
					                    (['usbobserver'] if isosx else []):
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
 | 
				
			|||||||
@ -35,7 +35,8 @@ class PRS500_PROFILE(object):
 | 
				
			|||||||
    name = 'prs500'
 | 
					    name = 'prs500'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def find_custom_fonts(options, logger):
 | 
					def find_custom_fonts(options, logger):
 | 
				
			||||||
    from calibre.utils.fontconfig import files_for_family
 | 
					    from calibre.utils.fonts import fontconfig
 | 
				
			||||||
 | 
					    files_for_family = fontconfig.files_for_family
 | 
				
			||||||
    fonts = {'serif' : None, 'sans' : None, 'mono' : None}
 | 
					    fonts = {'serif' : None, 'sans' : None, 'mono' : None}
 | 
				
			||||||
    def family(cmd):
 | 
					    def family(cmd):
 | 
				
			||||||
        return cmd.split(',')[-1].strip()
 | 
					        return cmd.split(',')[-1].strip()
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,7 @@ from calibre.gui2.convert import Widget
 | 
				
			|||||||
class PluginWidget(Widget, Ui_Form):
 | 
					class PluginWidget(Widget, Ui_Form):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TITLE = _('Comic Input')
 | 
					    TITLE = _('Comic Input')
 | 
				
			||||||
 | 
					    HELP = _('Options specific to')+' comic '+_('input')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, parent, get_option, get_help, db=None, book_id=None):
 | 
					    def __init__(self, parent, get_option, get_help, db=None, book_id=None):
 | 
				
			||||||
        Widget.__init__(self, parent, 'comic_input',
 | 
					        Widget.__init__(self, parent, 'comic_input',
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,7 @@ from calibre.gui2.convert import Widget
 | 
				
			|||||||
class PluginWidget(Widget, Ui_Form):
 | 
					class PluginWidget(Widget, Ui_Form):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TITLE = _('EPUB Output')
 | 
					    TITLE = _('EPUB Output')
 | 
				
			||||||
 | 
					    HELP  = _('Options specific to')+' EPUB '+_('output')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, parent, get_option, get_help, db=None, book_id=None):
 | 
					    def __init__(self, parent, get_option, get_help, db=None, book_id=None):
 | 
				
			||||||
        Widget.__init__(self, parent, 'epub_output',
 | 
					        Widget.__init__(self, parent, 'epub_output',
 | 
				
			||||||
 | 
				
			|||||||
@ -16,6 +16,7 @@ font_family_model = None
 | 
				
			|||||||
class PluginWidget(Widget, Ui_Form):
 | 
					class PluginWidget(Widget, Ui_Form):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TITLE = _('LRF Output')
 | 
					    TITLE = _('LRF Output')
 | 
				
			||||||
 | 
					    HELP = _('Options specific to')+' LRF '+_('output')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, parent, get_option, get_help, db=None, book_id=None):
 | 
					    def __init__(self, parent, get_option, get_help, db=None, book_id=None):
 | 
				
			||||||
        Widget.__init__(self, parent, 'lrf_output',
 | 
					        Widget.__init__(self, parent, 'lrf_output',
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,8 @@ from calibre.gui2.convert import Widget
 | 
				
			|||||||
class PluginWidget(Widget, Ui_Form):
 | 
					class PluginWidget(Widget, Ui_Form):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TITLE = _('MOBI Output')
 | 
					    TITLE = _('MOBI Output')
 | 
				
			||||||
 | 
					    HELP = _('Options specific to')+' MOBI '+_('output')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, parent, get_option, get_help, db=None, book_id=None):
 | 
					    def __init__(self, parent, get_option, get_help, db=None, book_id=None):
 | 
				
			||||||
        Widget.__init__(self, parent, 'mobi_output',
 | 
					        Widget.__init__(self, parent, 'mobi_output',
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,7 @@ format_model = None
 | 
				
			|||||||
class PluginWidget(Widget, Ui_Form):
 | 
					class PluginWidget(Widget, Ui_Form):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TITLE = _('PDB Output')
 | 
					    TITLE = _('PDB Output')
 | 
				
			||||||
 | 
					    HELP = _('Options specific to')+' PDB '+_('output')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, parent, get_option, get_help, db=None, book_id=None):
 | 
					    def __init__(self, parent, get_option, get_help, db=None, book_id=None):
 | 
				
			||||||
        Widget.__init__(self, parent, 'pdb_output', ['format'])
 | 
					        Widget.__init__(self, parent, 'pdb_output', ['format'])
 | 
				
			||||||
 | 
				
			|||||||
@ -15,6 +15,7 @@ orientation_model = None
 | 
				
			|||||||
class PluginWidget(Widget, Ui_Form):
 | 
					class PluginWidget(Widget, Ui_Form):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TITLE = _('PDF Output')
 | 
					    TITLE = _('PDF Output')
 | 
				
			||||||
 | 
					    HELP = _('Options specific to')+' PDF '+_('output')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, parent, get_option, get_help, db=None, book_id=None):
 | 
					    def __init__(self, parent, get_option, get_help, db=None, book_id=None):
 | 
				
			||||||
        Widget.__init__(self, parent, 'pdf_output', ['paper_size', 'orientation'])
 | 
					        Widget.__init__(self, parent, 'pdf_output', ['paper_size', 'orientation'])
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,7 @@ newline_model = None
 | 
				
			|||||||
class PluginWidget(Widget, Ui_Form):
 | 
					class PluginWidget(Widget, Ui_Form):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TITLE = _('TXT Output')
 | 
					    TITLE = _('TXT Output')
 | 
				
			||||||
 | 
					    HELP = _('Options specific to')+' TXT '+_('output')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, parent, get_option, get_help, db=None, book_id=None):
 | 
					    def __init__(self, parent, get_option, get_help, db=None, book_id=None):
 | 
				
			||||||
        Widget.__init__(self, parent, 'txt_output', ['newline'])
 | 
					        Widget.__init__(self, parent, 'txt_output', ['newline'])
 | 
				
			||||||
 | 
				
			|||||||
@ -38,7 +38,7 @@ class Wizard(QDialog):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def __init__(self, parent=None):
 | 
					    def __init__(self, parent=None):
 | 
				
			||||||
        QDialog.__init__(self, parent)
 | 
					        QDialog.__init__(self, parent)
 | 
				
			||||||
        self.resize(400, 300)
 | 
					        self.resize(440, 480)
 | 
				
			||||||
        self.verticalLayout = QVBoxLayout(self)
 | 
					        self.verticalLayout = QVBoxLayout(self)
 | 
				
			||||||
        self.widget = WizardWidget(self)
 | 
					        self.widget = WizardWidget(self)
 | 
				
			||||||
        self.verticalLayout.addWidget(self.widget)
 | 
					        self.verticalLayout.addWidget(self.widget)
 | 
				
			||||||
 | 
				
			|||||||
@ -1,3 +1,4 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
<ui version="4.0">
 | 
					<ui version="4.0">
 | 
				
			||||||
 <class>Form</class>
 | 
					 <class>Form</class>
 | 
				
			||||||
 <widget class="QWidget" name="Form">
 | 
					 <widget class="QWidget" name="Form">
 | 
				
			||||||
@ -12,8 +13,8 @@
 | 
				
			|||||||
  <property name="windowTitle">
 | 
					  <property name="windowTitle">
 | 
				
			||||||
   <string>Form</string>
 | 
					   <string>Form</string>
 | 
				
			||||||
  </property>
 | 
					  </property>
 | 
				
			||||||
  <layout class="QGridLayout" name="gridLayout" >
 | 
					  <layout class="QVBoxLayout" name="verticalLayout">
 | 
				
			||||||
   <item row="0" column="0" colspan="2" >
 | 
					   <item>
 | 
				
			||||||
    <widget class="QLabel" name="label">
 | 
					    <widget class="QLabel" name="label">
 | 
				
			||||||
     <property name="text">
 | 
					     <property name="text">
 | 
				
			||||||
      <string>Match HTML &tags with tag name:</string>
 | 
					      <string>Match HTML &tags with tag name:</string>
 | 
				
			||||||
@ -23,7 +24,7 @@
 | 
				
			|||||||
     </property>
 | 
					     </property>
 | 
				
			||||||
    </widget>
 | 
					    </widget>
 | 
				
			||||||
   </item>
 | 
					   </item>
 | 
				
			||||||
   <item row="1" column="0" >
 | 
					   <item>
 | 
				
			||||||
    <widget class="QComboBox" name="tag">
 | 
					    <widget class="QComboBox" name="tag">
 | 
				
			||||||
     <property name="editable">
 | 
					     <property name="editable">
 | 
				
			||||||
      <bool>true</bool>
 | 
					      <bool>true</bool>
 | 
				
			||||||
@ -90,7 +91,7 @@
 | 
				
			|||||||
     </item>
 | 
					     </item>
 | 
				
			||||||
    </widget>
 | 
					    </widget>
 | 
				
			||||||
   </item>
 | 
					   </item>
 | 
				
			||||||
   <item row="2" column="0" colspan="2" >
 | 
					   <item>
 | 
				
			||||||
    <widget class="QLabel" name="label_2">
 | 
					    <widget class="QLabel" name="label_2">
 | 
				
			||||||
     <property name="text">
 | 
					     <property name="text">
 | 
				
			||||||
      <string>Having the &attribute:</string>
 | 
					      <string>Having the &attribute:</string>
 | 
				
			||||||
@ -100,10 +101,10 @@
 | 
				
			|||||||
     </property>
 | 
					     </property>
 | 
				
			||||||
    </widget>
 | 
					    </widget>
 | 
				
			||||||
   </item>
 | 
					   </item>
 | 
				
			||||||
   <item row="3" column="0" colspan="2" >
 | 
					   <item>
 | 
				
			||||||
    <widget class="QLineEdit" name="attribute"/>
 | 
					    <widget class="QLineEdit" name="attribute"/>
 | 
				
			||||||
   </item>
 | 
					   </item>
 | 
				
			||||||
   <item row="4" column="0" >
 | 
					   <item>
 | 
				
			||||||
    <widget class="QLabel" name="label_3">
 | 
					    <widget class="QLabel" name="label_3">
 | 
				
			||||||
     <property name="text">
 | 
					     <property name="text">
 | 
				
			||||||
      <string>With &value:</string>
 | 
					      <string>With &value:</string>
 | 
				
			||||||
@ -113,20 +114,20 @@
 | 
				
			|||||||
     </property>
 | 
					     </property>
 | 
				
			||||||
    </widget>
 | 
					    </widget>
 | 
				
			||||||
   </item>
 | 
					   </item>
 | 
				
			||||||
   <item row="5" column="0" >
 | 
					   <item>
 | 
				
			||||||
    <widget class="QLineEdit" name="value" />
 | 
					 | 
				
			||||||
   </item>
 | 
					 | 
				
			||||||
   <item row="5" column="1" >
 | 
					 | 
				
			||||||
    <widget class="QLabel" name="label_4">
 | 
					    <widget class="QLabel" name="label_4">
 | 
				
			||||||
     <property name="text">
 | 
					     <property name="text">
 | 
				
			||||||
      <string>(A regular expression)</string>
 | 
					      <string>(A regular expression)</string>
 | 
				
			||||||
     </property>
 | 
					     </property>
 | 
				
			||||||
    </widget>
 | 
					    </widget>
 | 
				
			||||||
   </item>
 | 
					   </item>
 | 
				
			||||||
   <item row="6" column="0" colspan="2" >
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QLineEdit" name="value"/>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
    <widget class="QLabel" name="label_5">
 | 
					    <widget class="QLabel" name="label_5">
 | 
				
			||||||
     <property name="text">
 | 
					     <property name="text">
 | 
				
			||||||
      <string><p>For example, to match all h2 tags that have class="chapter", set tag to <i>h2</i>, attribute to <i>class</i> and value to <i>chapter</i>.</p><p>Leaving attribute blank will match any attribute and leaving value blank will match any value. Setting tag to * will match any tag.</p><p>To learn more advanced usage of XPath see the <a href="http://calibre.kovidgoyal.net/user_manual/xpath.html">XPath Tutorial</a>.</string>
 | 
					      <string><p>For example, to match all h2 tags that have class="chapter", set tag to <i>h2</i>, attribute to <i>class</i> and value to <i>chapter</i>.</p><p>Leaving attribute blank will match any attribute and leaving value blank will match any value. Setting tag to * will match any tag.</p><p>To learn more advanced usage of XPath see the <a href="http://calibre.kovidgoyal.net/user_manual/xpath.html">XPath Tutorial</a>.</string>
 | 
				
			||||||
     </property>
 | 
					     </property>
 | 
				
			||||||
     <property name="wordWrap">
 | 
					     <property name="wordWrap">
 | 
				
			||||||
      <bool>true</bool>
 | 
					      <bool>true</bool>
 | 
				
			||||||
@ -136,6 +137,19 @@
 | 
				
			|||||||
     </property>
 | 
					     </property>
 | 
				
			||||||
    </widget>
 | 
					    </widget>
 | 
				
			||||||
   </item>
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <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>
 | 
				
			||||||
  </layout>
 | 
					  </layout>
 | 
				
			||||||
 </widget>
 | 
					 </widget>
 | 
				
			||||||
 <resources/>
 | 
					 <resources/>
 | 
				
			||||||
 | 
				
			|||||||
@ -59,7 +59,6 @@ class ConfigTabs(QTabWidget):
 | 
				
			|||||||
                        fromlist=[1])
 | 
					                        fromlist=[1])
 | 
				
			||||||
                pw = input_widget.PluginWidget
 | 
					                pw = input_widget.PluginWidget
 | 
				
			||||||
                pw.ICON = ':/images/forward.svg'
 | 
					                pw.ICON = ':/images/forward.svg'
 | 
				
			||||||
                pw.HELP = _('Options specific to the input format.')
 | 
					 | 
				
			||||||
                self.widgets.append(widget_factory(pw))
 | 
					                self.widgets.append(widget_factory(pw))
 | 
				
			||||||
            except ImportError:
 | 
					            except ImportError:
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
@ -71,14 +70,15 @@ class ConfigTabs(QTabWidget):
 | 
				
			|||||||
                        fromlist=[1])
 | 
					                        fromlist=[1])
 | 
				
			||||||
                pw = output_widget.PluginWidget
 | 
					                pw = output_widget.PluginWidget
 | 
				
			||||||
                pw.ICON = ':/images/forward.svg'
 | 
					                pw.ICON = ':/images/forward.svg'
 | 
				
			||||||
                pw.HELP = _('Options specific to the input format.')
 | 
					 | 
				
			||||||
                self.widgets.append(widget_factory(pw))
 | 
					                self.widgets.append(widget_factory(pw))
 | 
				
			||||||
            except ImportError:
 | 
					            except ImportError:
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for widget in self.widgets:
 | 
					        for i, widget in enumerate(self.widgets):
 | 
				
			||||||
            self.addTab(widget, widget.TITLE.replace('\n', ' ').replace('&',
 | 
					            self.addTab(widget, widget.TITLE.replace('\n', ' ').replace('&',
 | 
				
			||||||
            '&&'))
 | 
					            '&&'))
 | 
				
			||||||
 | 
					            self.setTabToolTip(i, widget.HELP if widget.HELP else widget.TITLE)
 | 
				
			||||||
 | 
					        self.setUsesScrollButtons(True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def commit(self):
 | 
					    def commit(self):
 | 
				
			||||||
        for widget in self.widgets:
 | 
					        for widget in self.widgets:
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@
 | 
				
			|||||||
   <rect>
 | 
					   <rect>
 | 
				
			||||||
    <x>0</x>
 | 
					    <x>0</x>
 | 
				
			||||||
    <y>0</y>
 | 
					    <y>0</y>
 | 
				
			||||||
    <width>738</width>
 | 
					    <width>767</width>
 | 
				
			||||||
    <height>575</height>
 | 
					    <height>575</height>
 | 
				
			||||||
   </rect>
 | 
					   </rect>
 | 
				
			||||||
  </property>
 | 
					  </property>
 | 
				
			||||||
 | 
				
			|||||||
@ -107,7 +107,8 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
 | 
				
			|||||||
        MainWindow.__init__(self, opts, parent)
 | 
					        MainWindow.__init__(self, opts, parent)
 | 
				
			||||||
        # Initialize fontconfig in a separate thread as this can be a lengthy
 | 
					        # Initialize fontconfig in a separate thread as this can be a lengthy
 | 
				
			||||||
        # process if run for the first time on this machine
 | 
					        # process if run for the first time on this machine
 | 
				
			||||||
        self.fc = __import__('calibre.utils.fontconfig', fromlist=1)
 | 
					        from calibre.utils.fonts import fontconfig
 | 
				
			||||||
 | 
					        self.fc = fontconfig
 | 
				
			||||||
        self.listener = Listener(listener)
 | 
					        self.listener = Listener(listener)
 | 
				
			||||||
        self.check_messages_timer = QTimer()
 | 
					        self.check_messages_timer = QTimer()
 | 
				
			||||||
        self.connect(self.check_messages_timer, SIGNAL('timeout()'),
 | 
					        self.connect(self.check_messages_timer, SIGNAL('timeout()'),
 | 
				
			||||||
@ -1735,6 +1736,11 @@ def run_gui(opts, args, actions, listener, app):
 | 
				
			|||||||
    if getattr(main, 'restart_after_quit', False):
 | 
					    if getattr(main, 'restart_after_quit', False):
 | 
				
			||||||
        e = sys.executable if getattr(sys, 'froze', False) else sys.argv[0]
 | 
					        e = sys.executable if getattr(sys, 'froze', False) else sys.argv[0]
 | 
				
			||||||
        print 'Restarting with:', e, sys.argv
 | 
					        print 'Restarting with:', e, sys.argv
 | 
				
			||||||
 | 
					        if hasattr(sys, 'frameworks_dir'):
 | 
				
			||||||
 | 
					            app = os.path.dirname(os.path.dirname(sys.frameworks_dir))
 | 
				
			||||||
 | 
					            import subprocess
 | 
				
			||||||
 | 
					            subprocess.Popen('sleep 3s; open '+app, shell=True)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
            os.execvp(e, sys.argv)
 | 
					            os.execvp(e, sys.argv)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        if iswindows:
 | 
					        if iswindows:
 | 
				
			||||||
@ -1829,7 +1835,9 @@ if __name__ == '__main__':
 | 
				
			|||||||
        logfile = os.path.join(os.path.expanduser('~'), 'calibre.log')
 | 
					        logfile = os.path.join(os.path.expanduser('~'), 'calibre.log')
 | 
				
			||||||
        if os.path.exists(logfile):
 | 
					        if os.path.exists(logfile):
 | 
				
			||||||
            log = open(logfile).read().decode('utf-8', 'ignore')
 | 
					            log = open(logfile).read().decode('utf-8', 'ignore')
 | 
				
			||||||
            d = QErrorMessage(('<b>Error:</b>%s<br><b>Traceback:</b><br>'
 | 
					            d = QErrorMessage()
 | 
				
			||||||
                '%s<b>Log:</b><br>%s')%(unicode(err), unicode(tb), log))
 | 
					            d.showMessage(('<b>Error:</b>%s<br><b>Traceback:</b><br>'
 | 
				
			||||||
            d.exec_()
 | 
					                '%s<b>Log:</b><br>%s')%(unicode(err),
 | 
				
			||||||
 | 
					                    unicode(tb).replace('\n', '<br>'),
 | 
				
			||||||
 | 
					                    log.replace('\n', '<br>')))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,7 @@ from calibre.gui2 import human_readable, NONE, TableView, \
 | 
				
			|||||||
from calibre.gui2.dialogs.job_view_ui import Ui_Dialog
 | 
					from calibre.gui2.dialogs.job_view_ui import Ui_Dialog
 | 
				
			||||||
from calibre.gui2.filename_pattern_ui import Ui_Form
 | 
					from calibre.gui2.filename_pattern_ui import Ui_Form
 | 
				
			||||||
from calibre import fit_image
 | 
					from calibre import fit_image
 | 
				
			||||||
from calibre.utils.fontconfig import find_font_families
 | 
					from calibre.utils.fonts import fontconfig
 | 
				
			||||||
from calibre.ebooks.metadata.meta import metadata_from_filename
 | 
					from calibre.ebooks.metadata.meta import metadata_from_filename
 | 
				
			||||||
from calibre.utils.config import prefs
 | 
					from calibre.utils.config import prefs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -293,7 +293,7 @@ class FontFamilyModel(QAbstractListModel):
 | 
				
			|||||||
    def __init__(self, *args):
 | 
					    def __init__(self, *args):
 | 
				
			||||||
        QAbstractListModel.__init__(self, *args)
 | 
					        QAbstractListModel.__init__(self, *args)
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            self.families = find_font_families()
 | 
					            self.families = fontconfig.find_font_families()
 | 
				
			||||||
        except:
 | 
					        except:
 | 
				
			||||||
            self.families = []
 | 
					            self.families = []
 | 
				
			||||||
            print 'WARNING: Could not load fonts'
 | 
					            print 'WARNING: Could not load fonts'
 | 
				
			||||||
 | 
				
			|||||||
@ -23,6 +23,7 @@ from calibre.gui2.wizard.library_ui import Ui_WizardPage as LibraryUI
 | 
				
			|||||||
from calibre.gui2.wizard.finish_ui import Ui_WizardPage as FinishUI
 | 
					from calibre.gui2.wizard.finish_ui import Ui_WizardPage as FinishUI
 | 
				
			||||||
from calibre.gui2.wizard.kindle_ui import Ui_WizardPage as KindleUI
 | 
					from calibre.gui2.wizard.kindle_ui import Ui_WizardPage as KindleUI
 | 
				
			||||||
from calibre.gui2.wizard.stanza_ui import Ui_WizardPage as StanzaUI
 | 
					from calibre.gui2.wizard.stanza_ui import Ui_WizardPage as StanzaUI
 | 
				
			||||||
 | 
					from calibre.gui2 import min_available_height, available_width
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from calibre.utils.config import dynamic, prefs
 | 
					from calibre.utils.config import dynamic, prefs
 | 
				
			||||||
from calibre.gui2 import NONE, choose_dir, error_dialog
 | 
					from calibre.gui2 import NONE, choose_dir, error_dialog
 | 
				
			||||||
@ -483,6 +484,15 @@ class Wizard(QWizard):
 | 
				
			|||||||
        self.setPage(self.stanza_page.ID, self.stanza_page)
 | 
					        self.setPage(self.stanza_page.ID, self.stanza_page)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.device_extra_page = None
 | 
					        self.device_extra_page = None
 | 
				
			||||||
 | 
					        nh, nw = min_available_height()-75, available_width()-30
 | 
				
			||||||
 | 
					        if nh < 0:
 | 
				
			||||||
 | 
					            nh = 580
 | 
				
			||||||
 | 
					        if nw < 0:
 | 
				
			||||||
 | 
					            nw = 400
 | 
				
			||||||
 | 
					        nh = min(400, nh)
 | 
				
			||||||
 | 
					        nw = min(580, nw)
 | 
				
			||||||
 | 
					        self.resize(nw, nh)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def accept(self):
 | 
					    def accept(self):
 | 
				
			||||||
        self.device_page.commit()
 | 
					        self.device_page.commit()
 | 
				
			||||||
 | 
				
			|||||||
@ -27,7 +27,6 @@ entry_points = {
 | 
				
			|||||||
             'librarything       = calibre.ebooks.metadata.library_thing:main',
 | 
					             'librarything       = calibre.ebooks.metadata.library_thing:main',
 | 
				
			||||||
             'calibre-debug      = calibre.debug:main',
 | 
					             'calibre-debug      = calibre.debug:main',
 | 
				
			||||||
             'calibredb          = calibre.library.cli:main',
 | 
					             'calibredb          = calibre.library.cli:main',
 | 
				
			||||||
             'calibre-fontconfig = calibre.utils.fontconfig:main',
 | 
					 | 
				
			||||||
             'calibre-parallel   = calibre.utils.ipc.worker:main',
 | 
					             'calibre-parallel   = calibre.utils.ipc.worker:main',
 | 
				
			||||||
             'calibre-customize  = calibre.customize.ui:main',
 | 
					             'calibre-customize  = calibre.customize.ui:main',
 | 
				
			||||||
             'calibre-complete   = calibre.utils.complete:main',
 | 
					             'calibre-complete   = calibre.utils.complete:main',
 | 
				
			||||||
 | 
				
			|||||||
@ -1,400 +0,0 @@
 | 
				
			|||||||
#!/usr/bin/env  python
 | 
					 | 
				
			||||||
__license__   = 'GPL v3'
 | 
					 | 
				
			||||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
 | 
					 | 
				
			||||||
__docformat__ = 'restructuredtext en'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
'''
 | 
					 | 
				
			||||||
:mod:`fontconfig` -- Query system fonts
 | 
					 | 
				
			||||||
=============================================
 | 
					 | 
				
			||||||
.. module:: fontconfig
 | 
					 | 
				
			||||||
   :platform: Unix, Windows, OS X
 | 
					 | 
				
			||||||
   :synopsis: Query system fonts
 | 
					 | 
				
			||||||
.. moduleauthor:: Kovid Goyal <kovid@kovidgoyal.net>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
A ctypes based wrapper around the `fontconfig <http://fontconfig.org>`_ library.
 | 
					 | 
				
			||||||
It can be used to find all fonts available on the system as well as the closest
 | 
					 | 
				
			||||||
match to a given font specification. The main functions in this module are:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.. autofunction:: find_font_families
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.. autofunction:: files_for_family
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.. autofunction:: match
 | 
					 | 
				
			||||||
'''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import sys, os, locale, codecs, subprocess, re
 | 
					 | 
				
			||||||
from ctypes import cdll, c_void_p, Structure, c_int, POINTER, c_ubyte, c_char, util, \
 | 
					 | 
				
			||||||
                   pointer, byref, create_string_buffer, Union, c_char_p, c_double
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
try:
 | 
					 | 
				
			||||||
    preferred_encoding = locale.getpreferredencoding()
 | 
					 | 
				
			||||||
    codecs.lookup(preferred_encoding)
 | 
					 | 
				
			||||||
except:
 | 
					 | 
				
			||||||
    preferred_encoding = 'utf-8'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
iswindows = 'win32' in sys.platform or 'win64' in sys.platform
 | 
					 | 
				
			||||||
isosx     = 'darwin' in sys.platform
 | 
					 | 
				
			||||||
isbsd     = 'bsd' in sys.platform
 | 
					 | 
				
			||||||
DISABLED  = False 
 | 
					 | 
				
			||||||
#if isosx:
 | 
					 | 
				
			||||||
#    libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('c'))
 | 
					 | 
				
			||||||
#    size = ctypes.c_uint(0)
 | 
					 | 
				
			||||||
#    ok   = libc.sysctlbyname("hw.cpu64bit_capable", None, byref(size), None, 0)
 | 
					 | 
				
			||||||
#    if ok != 0:
 | 
					 | 
				
			||||||
#        is64bit = False
 | 
					 | 
				
			||||||
#    else:
 | 
					 | 
				
			||||||
#        buf = ctypes.c_char_p("\0" * size.value)
 | 
					 | 
				
			||||||
#        ok = libc.sysctlbyname("hw.cpu64bit_capable", buf, byref(size), None, 0)
 | 
					 | 
				
			||||||
#        if ok != 0:
 | 
					 | 
				
			||||||
#            is64bit = False
 | 
					 | 
				
			||||||
#        else:
 | 
					 | 
				
			||||||
#            is64bit = '1' in buf.value
 | 
					 | 
				
			||||||
#    DISABLED = is64bit
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def load_library():
 | 
					 | 
				
			||||||
    if isosx:
 | 
					 | 
				
			||||||
        lib = os.path.join(getattr(sys, 'frameworks_dir'), 'libfontconfig.1.dylib') \
 | 
					 | 
				
			||||||
                  if hasattr(sys, 'frameworks_dir') else util.find_library('fontconfig')
 | 
					 | 
				
			||||||
        return cdll.LoadLibrary(lib)
 | 
					 | 
				
			||||||
    elif iswindows:
 | 
					 | 
				
			||||||
        return cdll.LoadLibrary('libfontconfig-1')
 | 
					 | 
				
			||||||
    elif isbsd:
 | 
					 | 
				
			||||||
        raw = subprocess.Popen('pkg-config --libs-only-L fontconfig'.split(), 
 | 
					 | 
				
			||||||
                         stdout=subprocess.PIPE).stdout.read().strip()
 | 
					 | 
				
			||||||
        match = re.search(r'-L([^\s,]+)', raw)
 | 
					 | 
				
			||||||
        if not match:
 | 
					 | 
				
			||||||
            return cdll.LoadLibrary('libfontconfig.so')
 | 
					 | 
				
			||||||
        return cdll.LoadLibrary(match.group(1)+'/libfontconfig.so')
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            return cdll.LoadLibrary(util.find_library('fontconfig'))
 | 
					 | 
				
			||||||
        except:
 | 
					 | 
				
			||||||
            try:
 | 
					 | 
				
			||||||
                return cdll.LoadLibrary('libfontconfig.so')
 | 
					 | 
				
			||||||
            except:
 | 
					 | 
				
			||||||
                return cdll.LoadLibrary('libfontconfig.so.1')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class FcPattern(Structure):
 | 
					 | 
				
			||||||
    _fields_ = [
 | 
					 | 
				
			||||||
                ('num', c_int),
 | 
					 | 
				
			||||||
                ('size', c_int),
 | 
					 | 
				
			||||||
                ('elts_offset', c_void_p),
 | 
					 | 
				
			||||||
                ('ref', c_int)
 | 
					 | 
				
			||||||
                ]
 | 
					 | 
				
			||||||
class FcFontSet(Structure):
 | 
					 | 
				
			||||||
    _fields_ = [
 | 
					 | 
				
			||||||
                ('nfont', c_int),
 | 
					 | 
				
			||||||
                ('sfont', c_int),
 | 
					 | 
				
			||||||
                ('fonts', POINTER(POINTER(FcPattern)))
 | 
					 | 
				
			||||||
                ]
 | 
					 | 
				
			||||||
(
 | 
					 | 
				
			||||||
    FcTypeVoid,
 | 
					 | 
				
			||||||
    FcTypeInteger,
 | 
					 | 
				
			||||||
    FcTypeDouble,
 | 
					 | 
				
			||||||
    FcTypeString,
 | 
					 | 
				
			||||||
    FcTypeBool,
 | 
					 | 
				
			||||||
    FcTypeMatrix,
 | 
					 | 
				
			||||||
    FcTypeCharSet,
 | 
					 | 
				
			||||||
    FcTypeFTFace,
 | 
					 | 
				
			||||||
    FcTypeLangSet
 | 
					 | 
				
			||||||
) = map(c_int, range(9))
 | 
					 | 
				
			||||||
(FcMatchPattern, FcMatchFont, FcMatchScan) = map(c_int, range(3))
 | 
					 | 
				
			||||||
(
 | 
					 | 
				
			||||||
FcResultMatch, FcResultNoMatch, FcResultTypeMismatch, FcResultNoId,
 | 
					 | 
				
			||||||
    FcResultOutOfMemory
 | 
					 | 
				
			||||||
) = map(c_int, range(5))
 | 
					 | 
				
			||||||
FcFalse, FcTrue = c_int(0), c_int(1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class _FcValue(Union):
 | 
					 | 
				
			||||||
    _fields_ = [
 | 
					 | 
				
			||||||
                ('s', c_char_p),
 | 
					 | 
				
			||||||
                ('i', c_int),
 | 
					 | 
				
			||||||
                ('b', c_int),
 | 
					 | 
				
			||||||
                ('d', c_double),
 | 
					 | 
				
			||||||
                ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class FcValue(Structure):
 | 
					 | 
				
			||||||
    _fields_ = [
 | 
					 | 
				
			||||||
                ('type', c_int),
 | 
					 | 
				
			||||||
                ('u', _FcValue)
 | 
					 | 
				
			||||||
                ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class FcObjectSet(Structure): pass
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
lib = load_library()
 | 
					 | 
				
			||||||
lib.FcPatternBuild.restype = POINTER(FcPattern)
 | 
					 | 
				
			||||||
lib.FcPatternCreate.restype   = c_void_p
 | 
					 | 
				
			||||||
lib.FcObjectSetCreate.restype = POINTER(FcObjectSet)
 | 
					 | 
				
			||||||
lib.FcFontSetDestroy.argtypes = [POINTER(FcFontSet)]
 | 
					 | 
				
			||||||
lib.FcFontList.restype = POINTER(FcFontSet)
 | 
					 | 
				
			||||||
lib.FcNameUnparse.argtypes = [POINTER(FcPattern)]
 | 
					 | 
				
			||||||
lib.FcNameUnparse.restype = POINTER(c_ubyte)
 | 
					 | 
				
			||||||
lib.FcPatternGetString.argtypes = [POINTER(FcPattern), POINTER(c_char), c_int, c_void_p]
 | 
					 | 
				
			||||||
lib.FcPatternGetString.restype = c_int
 | 
					 | 
				
			||||||
lib.FcPatternAdd.argtypes = [c_void_p, POINTER(c_char), FcValue, c_int]
 | 
					 | 
				
			||||||
lib.FcPatternGetInteger.argtypes = [POINTER(FcPattern), POINTER(c_char), c_int, POINTER(c_int)]
 | 
					 | 
				
			||||||
lib.FcPatternGetInteger.restype = c_int
 | 
					 | 
				
			||||||
lib.FcNameParse.argtypes = [c_char_p]
 | 
					 | 
				
			||||||
lib.FcNameParse.restype = POINTER(FcPattern)
 | 
					 | 
				
			||||||
lib.FcDefaultSubstitute.argtypes = [POINTER(FcPattern)]
 | 
					 | 
				
			||||||
lib.FcConfigSubstitute.argtypes = [c_void_p, POINTER(FcPattern), c_int]
 | 
					 | 
				
			||||||
lib.FcFontSetCreate.restype = POINTER(FcFontSet)
 | 
					 | 
				
			||||||
lib.FcFontMatch.argtypes = [c_void_p, POINTER(FcPattern), POINTER(c_int)]
 | 
					 | 
				
			||||||
lib.FcFontMatch.restype = POINTER(FcPattern)
 | 
					 | 
				
			||||||
lib.FcFontSetAdd.argtypes = [POINTER(FcFontSet), POINTER(FcPattern)]
 | 
					 | 
				
			||||||
lib.FcFontSort.argtypes = [c_void_p, POINTER(FcPattern), c_int, c_void_p, POINTER(c_int)]
 | 
					 | 
				
			||||||
lib.FcFontSort.restype = POINTER(FcFontSet)
 | 
					 | 
				
			||||||
lib.FcFontRenderPrepare.argtypes = [c_void_p, POINTER(FcPattern), POINTER(FcPattern)]
 | 
					 | 
				
			||||||
lib.FcFontRenderPrepare.restype = POINTER(FcPattern)
 | 
					 | 
				
			||||||
lib.FcConfigCreate.restype = c_void_p
 | 
					 | 
				
			||||||
lib.FcConfigSetCurrent.argtypes = [c_void_p]
 | 
					 | 
				
			||||||
lib.FcConfigSetCurrent.restype = c_int
 | 
					 | 
				
			||||||
lib.FcConfigParseAndLoad.argtypes = [c_void_p, POINTER(c_char), c_int]
 | 
					 | 
				
			||||||
lib.FcConfigParseAndLoad.restype = c_int
 | 
					 | 
				
			||||||
lib.FcConfigBuildFonts.argtypes = [c_void_p]
 | 
					 | 
				
			||||||
lib.FcConfigBuildFonts.restype  = c_int
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
_init_error  = None 
 | 
					 | 
				
			||||||
_initialized = False
 | 
					 | 
				
			||||||
from threading import Thread
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class FontScanner(Thread):
 | 
					 | 
				
			||||||
    def run(self):
 | 
					 | 
				
			||||||
        # Initialize the fontconfig library. This has to be done manually
 | 
					 | 
				
			||||||
        # for the OS X bundle as it may have its own private fontconfig.
 | 
					 | 
				
			||||||
        if getattr(sys, 'frameworks_dir', False):# and not os.path.exists('/usr/X11/lib/libfontconfig.1.dylib'):
 | 
					 | 
				
			||||||
            config_dir = os.path.join(os.path.dirname(getattr(sys, 'frameworks_dir')), 'Resources', 'fonts')
 | 
					 | 
				
			||||||
            if isinstance(config_dir, unicode):
 | 
					 | 
				
			||||||
                config_dir = config_dir.encode(sys.getfilesystemencoding())
 | 
					 | 
				
			||||||
            config = lib.FcConfigCreate()
 | 
					 | 
				
			||||||
            if not lib.FcConfigParseAndLoad(config, os.path.join(config_dir, 'fonts.conf'), 1):
 | 
					 | 
				
			||||||
                _init_error = 'Could not parse the fontconfig configuration'
 | 
					 | 
				
			||||||
                return
 | 
					 | 
				
			||||||
            if not lib.FcConfigBuildFonts(config):
 | 
					 | 
				
			||||||
                _init_error = 'Could not build fonts'
 | 
					 | 
				
			||||||
                return
 | 
					 | 
				
			||||||
            if not lib.FcConfigSetCurrent(config):
 | 
					 | 
				
			||||||
                _init_error = 'Could not set font config'
 | 
					 | 
				
			||||||
                return
 | 
					 | 
				
			||||||
        elif not lib.FcInit():
 | 
					 | 
				
			||||||
            _init_error = _('Could not initialize the fontconfig library')
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
        global _initialized
 | 
					 | 
				
			||||||
        _initialized = True
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
if not DISABLED:
 | 
					 | 
				
			||||||
    _scanner = FontScanner()
 | 
					 | 
				
			||||||
    _scanner.start()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def join():
 | 
					 | 
				
			||||||
    _scanner.join(120)
 | 
					 | 
				
			||||||
    if _scanner.isAlive():
 | 
					 | 
				
			||||||
        raise RuntimeError('Scanning for system fonts seems to have hung. Try again in a little while.')
 | 
					 | 
				
			||||||
    if _init_error is not None:
 | 
					 | 
				
			||||||
        raise RuntimeError(_init_error)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def find_font_families(allowed_extensions=['ttf', 'otf']):
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    Return an alphabetically sorted list of font families available on the system.
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    `allowed_extensions`: A list of allowed extensions for font file types. Defaults to
 | 
					 | 
				
			||||||
    `['ttf', 'otf']`. If it is empty, it is ignored.
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    if DISABLED:
 | 
					 | 
				
			||||||
        return []
 | 
					 | 
				
			||||||
    join()
 | 
					 | 
				
			||||||
    allowed_extensions = [i.lower() for i in allowed_extensions]
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    empty_pattern = lib.FcPatternCreate()
 | 
					 | 
				
			||||||
    oset = lib.FcObjectSetCreate()
 | 
					 | 
				
			||||||
    if not lib.FcObjectSetAdd(oset, 'file'):
 | 
					 | 
				
			||||||
        raise RuntimeError('Allocation failure')
 | 
					 | 
				
			||||||
    if not lib.FcObjectSetAdd(oset, 'family'):
 | 
					 | 
				
			||||||
        raise RuntimeError('Allocation failure')
 | 
					 | 
				
			||||||
    fs = lib.FcFontList(0, empty_pattern, oset)
 | 
					 | 
				
			||||||
    font_set = fs.contents
 | 
					 | 
				
			||||||
    file = pointer(create_string_buffer(chr(0), 5000))
 | 
					 | 
				
			||||||
    family = pointer(create_string_buffer(chr(0), 200))
 | 
					 | 
				
			||||||
    font_families = []
 | 
					 | 
				
			||||||
    for i in range(font_set.nfont):
 | 
					 | 
				
			||||||
        pat = font_set.fonts[i]
 | 
					 | 
				
			||||||
        if lib.FcPatternGetString(pat, 'file', 0, byref(file)) != FcResultMatch.value:
 | 
					 | 
				
			||||||
            raise RuntimeError('Error processing pattern')
 | 
					 | 
				
			||||||
        path = str(file.contents.value)
 | 
					 | 
				
			||||||
        ext = os.path.splitext(path)[1]
 | 
					 | 
				
			||||||
        if ext:
 | 
					 | 
				
			||||||
            ext = ext[1:].lower()
 | 
					 | 
				
			||||||
        if (not allowed_extensions) or (allowed_extensions and ext in allowed_extensions):
 | 
					 | 
				
			||||||
            if lib.FcPatternGetString(pat, 'family', 0, byref(family)) != FcResultMatch.value:
 | 
					 | 
				
			||||||
                raise RuntimeError('Error processing pattern')
 | 
					 | 
				
			||||||
            font_families.append(str(family.contents.value))
 | 
					 | 
				
			||||||
         
 | 
					 | 
				
			||||||
    lib.FcObjectSetDestroy(oset)
 | 
					 | 
				
			||||||
    lib.FcPatternDestroy(empty_pattern)
 | 
					 | 
				
			||||||
    lib.FcFontSetDestroy(fs)
 | 
					 | 
				
			||||||
    font_families = list(set(font_families))
 | 
					 | 
				
			||||||
    font_families.sort()
 | 
					 | 
				
			||||||
    return font_families
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
def files_for_family(family, normalize=True):
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    Find all the variants in the font family `family`. 
 | 
					 | 
				
			||||||
    Returns a dictionary of tuples. Each tuple is of the form (Full font name, path to font file).
 | 
					 | 
				
			||||||
    The keys of the dictionary depend on `normalize`. If `normalize` is `False`,
 | 
					 | 
				
			||||||
    they are a tuple (slant, weight) otherwise they are strings from the set 
 | 
					 | 
				
			||||||
    `('normal', 'bold', 'italic', 'bi', 'light', 'li')`
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    if DISABLED:
 | 
					 | 
				
			||||||
        return {}
 | 
					 | 
				
			||||||
    join()
 | 
					 | 
				
			||||||
    if isinstance(family, unicode):
 | 
					 | 
				
			||||||
        family = family.encode(preferred_encoding)
 | 
					 | 
				
			||||||
    family_pattern = lib.FcPatternBuild(0, 'family', FcTypeString, family, None)
 | 
					 | 
				
			||||||
    if not family_pattern:
 | 
					 | 
				
			||||||
        raise RuntimeError('Allocation failure')
 | 
					 | 
				
			||||||
    #lib.FcPatternPrint(family_pattern)
 | 
					 | 
				
			||||||
    oset = lib.FcObjectSetCreate()
 | 
					 | 
				
			||||||
    if not lib.FcObjectSetAdd(oset, 'file'):
 | 
					 | 
				
			||||||
        raise RuntimeError('Allocation failure')
 | 
					 | 
				
			||||||
    if not lib.FcObjectSetAdd(oset, 'weight'):
 | 
					 | 
				
			||||||
        raise RuntimeError('Allocation failure')
 | 
					 | 
				
			||||||
    if not lib.FcObjectSetAdd(oset, 'fullname'):
 | 
					 | 
				
			||||||
        raise RuntimeError('Allocation failure')
 | 
					 | 
				
			||||||
    if not lib.FcObjectSetAdd(oset, 'slant'):
 | 
					 | 
				
			||||||
        raise RuntimeError('Allocation failure')
 | 
					 | 
				
			||||||
    if not lib.FcObjectSetAdd(oset, 'style'):
 | 
					 | 
				
			||||||
        raise RuntimeError('Allocation failure')
 | 
					 | 
				
			||||||
    fonts = {}
 | 
					 | 
				
			||||||
    fs = lib.FcFontList(0, family_pattern, oset)
 | 
					 | 
				
			||||||
    font_set = fs.contents
 | 
					 | 
				
			||||||
    file  = pointer(create_string_buffer(5000))
 | 
					 | 
				
			||||||
    full_name  = pointer(create_string_buffer(200))
 | 
					 | 
				
			||||||
    weight = c_int(0)
 | 
					 | 
				
			||||||
    slant = c_int(0)
 | 
					 | 
				
			||||||
    fname = ''
 | 
					 | 
				
			||||||
    for i in range(font_set.nfont):
 | 
					 | 
				
			||||||
        pat = font_set.fonts[i]
 | 
					 | 
				
			||||||
        #lib.FcPatternPrint(pat)
 | 
					 | 
				
			||||||
        pat = font_set.fonts[i]
 | 
					 | 
				
			||||||
        if lib.FcPatternGetString(pat, 'file', 0, byref(file)) != FcResultMatch.value:
 | 
					 | 
				
			||||||
            raise RuntimeError('Error processing pattern')
 | 
					 | 
				
			||||||
        if lib.FcPatternGetInteger(pat, 'weight', 0, byref(weight)) != FcResultMatch.value:
 | 
					 | 
				
			||||||
            raise RuntimeError('Error processing pattern')
 | 
					 | 
				
			||||||
        if lib.FcPatternGetString(pat, 'fullname', 0, byref(full_name)) != FcResultMatch.value:
 | 
					 | 
				
			||||||
            if lib.FcPatternGetString(pat, 'fullname', 0, byref(full_name)) == FcResultNoMatch.value:
 | 
					 | 
				
			||||||
                if lib.FcPatternGetString(pat, 'style', 0, byref(full_name)) != FcResultMatch.value:
 | 
					 | 
				
			||||||
                    raise RuntimeError('Error processing pattern')
 | 
					 | 
				
			||||||
                fname = family + ' ' + full_name.contents.value
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                raise RuntimeError('Error processing pattern')
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            fname = full_name.contents.value
 | 
					 | 
				
			||||||
        if lib.FcPatternGetInteger(pat, 'slant', 0, byref(slant)) != FcResultMatch.value:
 | 
					 | 
				
			||||||
            raise RuntimeError('Error processing pattern')
 | 
					 | 
				
			||||||
        style = (slant.value, weight.value) 
 | 
					 | 
				
			||||||
        if normalize:
 | 
					 | 
				
			||||||
            italic = slant.value > 0
 | 
					 | 
				
			||||||
            normal = weight.value == 80
 | 
					 | 
				
			||||||
            bold = weight.value > 80
 | 
					 | 
				
			||||||
            if italic:
 | 
					 | 
				
			||||||
                style = 'italic' if normal else 'bi' if bold else 'li' 
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                style = 'normal' if normal else 'bold' if bold else 'light'
 | 
					 | 
				
			||||||
        fonts[style] = (file.contents.value, fname)
 | 
					 | 
				
			||||||
    lib.FcObjectSetDestroy(oset)
 | 
					 | 
				
			||||||
    lib.FcPatternDestroy(family_pattern)
 | 
					 | 
				
			||||||
    if not iswindows:
 | 
					 | 
				
			||||||
        lib.FcFontSetDestroy(fs)
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    return  fonts
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def match(name, sort=False, verbose=False):
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    Find the system font that most closely matches `name`, where `name` is a specification
 | 
					 | 
				
			||||||
    of the form::
 | 
					 | 
				
			||||||
      familyname-<pointsize>:<property1=value1>:<property2=value2>...
 | 
					 | 
				
			||||||
      
 | 
					 | 
				
			||||||
    For example, `verdana:weight=bold:slant=italic`
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    Returns a list of dictionaries. Each dictionary has the keys: 'weight', 'slant', 'family', 'file'
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    `sort`: If `True` return a sorted list of matching fonts, where the sort id in order of
 | 
					 | 
				
			||||||
    decreasing closeness of matching.
 | 
					 | 
				
			||||||
    `verbose`: If `True` print debugging information to stdout
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    if DISABLED:
 | 
					 | 
				
			||||||
        return []
 | 
					 | 
				
			||||||
    join()
 | 
					 | 
				
			||||||
    if isinstance(name, unicode):
 | 
					 | 
				
			||||||
        name = name.encode(preferred_encoding)
 | 
					 | 
				
			||||||
    pat = lib.FcNameParse(name)
 | 
					 | 
				
			||||||
    if not pat:
 | 
					 | 
				
			||||||
        raise ValueError('Could not parse font name')
 | 
					 | 
				
			||||||
    if verbose:
 | 
					 | 
				
			||||||
        print 'Searching for pattern'
 | 
					 | 
				
			||||||
        lib.FcPatternPrint(pat)
 | 
					 | 
				
			||||||
    if not lib.FcConfigSubstitute(0, pat, FcMatchPattern):
 | 
					 | 
				
			||||||
        raise RuntimeError('Allocation failure')
 | 
					 | 
				
			||||||
    lib.FcDefaultSubstitute(pat)
 | 
					 | 
				
			||||||
    fs = lib.FcFontSetCreate()
 | 
					 | 
				
			||||||
    result = c_int(0)
 | 
					 | 
				
			||||||
    matches = []
 | 
					 | 
				
			||||||
    if sort:
 | 
					 | 
				
			||||||
        font_patterns = lib.FcFontSort(0, pat, FcFalse, 0, byref(result))
 | 
					 | 
				
			||||||
        if not font_patterns:
 | 
					 | 
				
			||||||
            raise RuntimeError('Allocation failed')
 | 
					 | 
				
			||||||
        fps = font_patterns.contents
 | 
					 | 
				
			||||||
        for j in range(fps.nfont):
 | 
					 | 
				
			||||||
            fpat = fps.fonts[j]
 | 
					 | 
				
			||||||
            fp = lib.FcFontRenderPrepare(0, pat, fpat)
 | 
					 | 
				
			||||||
            if fp:
 | 
					 | 
				
			||||||
                lib.FcFontSetAdd(fs, fp)
 | 
					 | 
				
			||||||
        lib.FcFontSetDestroy(font_patterns)
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        match_pat = lib.FcFontMatch(0, pat, byref(result))
 | 
					 | 
				
			||||||
        if pat:
 | 
					 | 
				
			||||||
            lib.FcFontSetAdd(fs, match_pat)
 | 
					 | 
				
			||||||
        if result.value != FcResultMatch.value:
 | 
					 | 
				
			||||||
            lib.FcPatternDestroy(pat)
 | 
					 | 
				
			||||||
            return matches
 | 
					 | 
				
			||||||
    font_set = fs.contents
 | 
					 | 
				
			||||||
     
 | 
					 | 
				
			||||||
    file    = pointer(create_string_buffer(chr(0), 5000))
 | 
					 | 
				
			||||||
    family  = pointer(create_string_buffer(chr(0), 200))
 | 
					 | 
				
			||||||
    weight  = c_int(0)
 | 
					 | 
				
			||||||
    slant   = c_int(0)
 | 
					 | 
				
			||||||
    for j in range(font_set.nfont):
 | 
					 | 
				
			||||||
        fpat = font_set.fonts[j]
 | 
					 | 
				
			||||||
        #lib.FcPatternPrint(fpat)
 | 
					 | 
				
			||||||
        if lib.FcPatternGetString(fpat, 'file', 0, byref(file)) != FcResultMatch.value:
 | 
					 | 
				
			||||||
            raise RuntimeError('Error processing pattern')
 | 
					 | 
				
			||||||
        if lib.FcPatternGetString(fpat, 'family', 0, byref(family)) != FcResultMatch.value:
 | 
					 | 
				
			||||||
            raise RuntimeError('Error processing pattern')
 | 
					 | 
				
			||||||
        if lib.FcPatternGetInteger(fpat, 'weight', 0, byref(weight)) != FcResultMatch.value:
 | 
					 | 
				
			||||||
            raise RuntimeError('Error processing pattern')
 | 
					 | 
				
			||||||
        if lib.FcPatternGetInteger(fpat, 'slant', 0, byref(slant)) != FcResultMatch.value:
 | 
					 | 
				
			||||||
            raise RuntimeError('Error processing pattern')
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        matches.append({
 | 
					 | 
				
			||||||
                        'file'    : file.contents.value,
 | 
					 | 
				
			||||||
                        'family'  : family.contents.value,
 | 
					 | 
				
			||||||
                        'weight'  : weight.value,
 | 
					 | 
				
			||||||
                        'slant'   : slant.value,
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                       )
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    lib.FcPatternDestroy(pat)
 | 
					 | 
				
			||||||
    lib.FcFontSetDestroy(fs)
 | 
					 | 
				
			||||||
    return matches
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def main(args=sys.argv):
 | 
					 | 
				
			||||||
    print find_font_families()
 | 
					 | 
				
			||||||
    if len(args) > 1:
 | 
					 | 
				
			||||||
        print
 | 
					 | 
				
			||||||
        print files_for_family(args[1])
 | 
					 | 
				
			||||||
        print
 | 
					 | 
				
			||||||
        print match(args[1], verbose=True)
 | 
					 | 
				
			||||||
    return 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if __name__ == '__main__':
 | 
					 | 
				
			||||||
    sys.exit(main())
 | 
					 | 
				
			||||||
							
								
								
									
										150
									
								
								src/calibre/utils/fonts/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								src/calibre/utils/fonts/__init__.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,150 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
 | 
				
			||||||
 | 
					from __future__ import with_statement
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__license__   = 'GPL v3'
 | 
				
			||||||
 | 
					__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
 | 
				
			||||||
 | 
					__docformat__ = 'restructuredtext en'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os, sys
 | 
				
			||||||
 | 
					from threading import Thread
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from calibre.constants import plugins
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_fc, _fc_err = plugins['fontconfig']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if _fc is None:
 | 
				
			||||||
 | 
					    raise RuntimeError('Failed to load fontconfig with error:'+_fc_err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FontConfig(Thread):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        Thread.__init__(self)
 | 
				
			||||||
 | 
					        self.daemon = True
 | 
				
			||||||
 | 
					        self.failed = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run(self):
 | 
				
			||||||
 | 
					        config = None
 | 
				
			||||||
 | 
					        if getattr(sys, 'frameworks_dir', False):
 | 
				
			||||||
 | 
					            config_dir = os.path.join(os.path.dirname(
 | 
				
			||||||
 | 
					                getattr(sys, 'frameworks_dir')), 'Resources', 'fonts')
 | 
				
			||||||
 | 
					            if isinstance(config_dir, unicode):
 | 
				
			||||||
 | 
					                config_dir = config_dir.encode(sys.getfilesystemencoding())
 | 
				
			||||||
 | 
					            config = os.path.join(config_dir, 'fonts.conf')
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            _fc.initialize(config)
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            import traceback
 | 
				
			||||||
 | 
					            traceback.print_exc()
 | 
				
			||||||
 | 
					            self.failed = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def wait(self):
 | 
				
			||||||
 | 
					        self.join()
 | 
				
			||||||
 | 
					        if self.failed:
 | 
				
			||||||
 | 
					            raise RuntimeError('Failed to initialize fontconfig')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def find_font_families(self, allowed_extensions=['ttf', 'otf']):
 | 
				
			||||||
 | 
					        '''
 | 
				
			||||||
 | 
					        Return an alphabetically sorted list of font families available on the system.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        `allowed_extensions`: A list of allowed extensions for font file types. Defaults to
 | 
				
			||||||
 | 
					        `['ttf', 'otf']`. If it is empty, it is ignored.
 | 
				
			||||||
 | 
					        '''
 | 
				
			||||||
 | 
					        self.wait()
 | 
				
			||||||
 | 
					        ans = _fc.find_font_families([bytes('.'+x) for x in allowed_extensions])
 | 
				
			||||||
 | 
					        ans = sorted(set(ans), cmp=lambda x,y:cmp(x.lower(), y.lower()))
 | 
				
			||||||
 | 
					        ans2 = []
 | 
				
			||||||
 | 
					        for x in ans:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                ans2.append(x.decode('utf-8'))
 | 
				
			||||||
 | 
					            except UnicodeDecodeError:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					        return ans2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def files_for_family(self, family, normalize=True):
 | 
				
			||||||
 | 
					        '''
 | 
				
			||||||
 | 
					        Find all the variants in the font family `family`.
 | 
				
			||||||
 | 
					        Returns a dictionary of tuples. Each tuple is of the form (Full font name, path to font file).
 | 
				
			||||||
 | 
					        The keys of the dictionary depend on `normalize`. If `normalize` is `False`,
 | 
				
			||||||
 | 
					        they are a tuple (slant, weight) otherwise they are strings from the set
 | 
				
			||||||
 | 
					        `('normal', 'bold', 'italic', 'bi', 'light', 'li')`
 | 
				
			||||||
 | 
					        '''
 | 
				
			||||||
 | 
					        self.wait()
 | 
				
			||||||
 | 
					        if isinstance(family, unicode):
 | 
				
			||||||
 | 
					            family = family.encode('utf-8')
 | 
				
			||||||
 | 
					        fonts = {}
 | 
				
			||||||
 | 
					        ofamily = str(family).decode('utf-8')
 | 
				
			||||||
 | 
					        for fullname, path, style, nfamily, weight, slant in \
 | 
				
			||||||
 | 
					            _fc.files_for_family(str(family)):
 | 
				
			||||||
 | 
					            style = (slant, weight)
 | 
				
			||||||
 | 
					            if normalize:
 | 
				
			||||||
 | 
					                italic = slant > 0
 | 
				
			||||||
 | 
					                normal = weight == 80
 | 
				
			||||||
 | 
					                bold = weight > 80
 | 
				
			||||||
 | 
					                if italic:
 | 
				
			||||||
 | 
					                    style = 'italic' if normal else 'bi' if bold else 'li'
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    style = 'normal' if normal else 'bold' if bold else 'light'
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                fullname, path = fullname.decode('utf-8'), path.decode('utf-8')
 | 
				
			||||||
 | 
					                nfamily = nfamily.decode('utf-8')
 | 
				
			||||||
 | 
					            except UnicodeDecodeError:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            if style in fonts:
 | 
				
			||||||
 | 
					                if nfamily.lower().strip() == ofamily.lower().strip() \
 | 
				
			||||||
 | 
					                and 'Condensed' not in fullname and 'ExtraLight' not in fullname:
 | 
				
			||||||
 | 
					                    fonts[style] = (path, fullname)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                fonts[style] = (path, fullname)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return fonts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def match(self, name, all=False, verbose=False):
 | 
				
			||||||
 | 
					        '''
 | 
				
			||||||
 | 
					        Find the system font that most closely matches `name`, where `name` is a specification
 | 
				
			||||||
 | 
					        of the form::
 | 
				
			||||||
 | 
					        familyname-<pointsize>:<property1=value1>:<property2=value2>...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        For example, `verdana:weight=bold:slant=italic`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Returns a list of dictionaries, or a single dictionary.
 | 
				
			||||||
 | 
					        Each dictionary has the keys:
 | 
				
			||||||
 | 
					        'weight', 'slant', 'family', 'file', 'fullname', 'style'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        `all`: If `True` return a sorted list of matching fonts, where the sort
 | 
				
			||||||
 | 
					        is in order of decreasing closeness of matching. If `False` only the
 | 
				
			||||||
 | 
					        best match is returned.        '''
 | 
				
			||||||
 | 
					        self.wait()
 | 
				
			||||||
 | 
					        if isinstance(name, unicode):
 | 
				
			||||||
 | 
					            name = name.encode('utf-8')
 | 
				
			||||||
 | 
					        fonts = []
 | 
				
			||||||
 | 
					        for fullname, path, style, family, weight, slant in \
 | 
				
			||||||
 | 
					            _fc.match(str(name), bool(all), bool(verbose)):
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                fullname = fullname.decode('utf-8')
 | 
				
			||||||
 | 
					                path = path.decode('utf-8')
 | 
				
			||||||
 | 
					                style = style.decode('utf-8')
 | 
				
			||||||
 | 
					                family = family.decode('utf-8')
 | 
				
			||||||
 | 
					                fonts.append({
 | 
				
			||||||
 | 
					                    'fullname' : fullname,
 | 
				
			||||||
 | 
					                    'path'     : path,
 | 
				
			||||||
 | 
					                    'style'    : style,
 | 
				
			||||||
 | 
					                    'family'   : family,
 | 
				
			||||||
 | 
					                    'weight'   : weight,
 | 
				
			||||||
 | 
					                    'slant'    : slant
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					            except UnicodeDecodeError:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					        return fonts if all else fonts[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fontconfig = FontConfig()
 | 
				
			||||||
 | 
					fontconfig.start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test():
 | 
				
			||||||
 | 
					    from pprint import pprint;
 | 
				
			||||||
 | 
					    pprint(fontconfig.find_font_families());
 | 
				
			||||||
 | 
					    pprint(fontconfig.files_for_family('liberation serif'));
 | 
				
			||||||
 | 
					    pprint(fontconfig.match('liberation serif:slant=italic:weight=bold', verbose=True))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    test()
 | 
				
			||||||
							
								
								
									
										331
									
								
								src/calibre/utils/fonts/fontconfig.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										331
									
								
								src/calibre/utils/fonts/fontconfig.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,331 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					:mod:`fontconfig` -- Pythonic interface to fontconfig
 | 
				
			||||||
 | 
					=====================================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. module:: fontconfig
 | 
				
			||||||
 | 
					    :platform: All
 | 
				
			||||||
 | 
					    :synopsis: Pythonic interface to the fontconfig library
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. moduleauthor:: Kovid Goyal <kovid@kovidgoyal.net> Copyright 2009
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PY_SSIZE_T_CLEAN
 | 
				
			||||||
 | 
					#include <Python.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <fontconfig.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static PyObject *
 | 
				
			||||||
 | 
					fontconfig_initialize(PyObject *self, PyObject *args) {
 | 
				
			||||||
 | 
					    char *path;
 | 
				
			||||||
 | 
					    FcBool ok;
 | 
				
			||||||
 | 
					    FcConfig *config;
 | 
				
			||||||
 | 
					    PyThreadState *_save;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!PyArg_ParseTuple(args, "z", &path))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					    if (path == NULL) {
 | 
				
			||||||
 | 
					        _save = PyEval_SaveThread();
 | 
				
			||||||
 | 
					        ok = FcInit();
 | 
				
			||||||
 | 
					        PyEval_RestoreThread(_save);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        config = FcConfigCreate();
 | 
				
			||||||
 | 
					        if (config == NULL) return PyErr_NoMemory();
 | 
				
			||||||
 | 
					        _save = PyEval_SaveThread();
 | 
				
			||||||
 | 
					        ok = FcConfigParseAndLoad(config, path, FcTrue);
 | 
				
			||||||
 | 
					        if (ok) ok = FcConfigBuildFonts(config);
 | 
				
			||||||
 | 
					        if (ok) ok = FcConfigSetCurrent(config);
 | 
				
			||||||
 | 
					        PyEval_RestoreThread(_save);
 | 
				
			||||||
 | 
					        if (!ok) return PyErr_NoMemory();     
 | 
				
			||||||
 | 
					        ok = 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (ok) Py_RETURN_TRUE;
 | 
				
			||||||
 | 
					    Py_RETURN_FALSE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static
 | 
				
			||||||
 | 
					fontconfig_cleanup_find(FcPattern *p, FcObjectSet *oset, FcFontSet *fs) {
 | 
				
			||||||
 | 
					    if (p != NULL) FcPatternDestroy(p);
 | 
				
			||||||
 | 
					    if (oset != NULL) FcObjectSetDestroy(oset);
 | 
				
			||||||
 | 
					    if (fs != NULL) FcFontSetDestroy(fs);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static PyObject *
 | 
				
			||||||
 | 
					fontconfig_find_font_families(PyObject *self, PyObject *args) {
 | 
				
			||||||
 | 
					    int i; 
 | 
				
			||||||
 | 
					    size_t flen;
 | 
				
			||||||
 | 
					    char *ext;
 | 
				
			||||||
 | 
					    Py_ssize_t l, j, extlen;
 | 
				
			||||||
 | 
					    FcBool ok;
 | 
				
			||||||
 | 
					    FcPattern *pat, *temp;
 | 
				
			||||||
 | 
					    FcObjectSet *oset;
 | 
				
			||||||
 | 
					    FcFontSet *fs;
 | 
				
			||||||
 | 
					    FcValue v, w;
 | 
				
			||||||
 | 
					    PyObject *ans, *exts, *t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ans = PyList_New(0);
 | 
				
			||||||
 | 
					    fs = NULL; oset = NULL; pat = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ans == NULL) return PyErr_NoMemory();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!PyArg_ParseTuple(args, "O", &exts))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!PySequence_Check(exts)) { 
 | 
				
			||||||
 | 
					        PyErr_SetString(PyExc_ValueError, "Must pass sequence of extensions");
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    l = PySequence_Size(exts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pat = FcPatternCreate();
 | 
				
			||||||
 | 
					    if (pat == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    oset = FcObjectSetCreate();
 | 
				
			||||||
 | 
					    if (oset == NULL)  { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 | 
				
			||||||
 | 
					    if (!FcObjectSetAdd(oset, FC_FILE))  { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 | 
				
			||||||
 | 
					    if (!FcObjectSetAdd(oset, FC_FAMILY)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fs = FcFontList(FcConfigGetCurrent(), pat, oset);
 | 
				
			||||||
 | 
					    if (fs == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < fs->nfont; i++) {
 | 
				
			||||||
 | 
					        temp = fs->fonts[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (temp == NULL) continue;
 | 
				
			||||||
 | 
					        if (FcPatternGet(temp, FC_FILE, 0, &v) != FcResultMatch) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (v.type == FcTypeString) {
 | 
				
			||||||
 | 
					            flen = strlen((char *)v.u.s);
 | 
				
			||||||
 | 
					            ok = FcFalse;
 | 
				
			||||||
 | 
					            if (l == 0) ok = FcTrue;
 | 
				
			||||||
 | 
					            for ( j = 0; j < l && !ok; j++) {
 | 
				
			||||||
 | 
					                ext = PyBytes_AS_STRING(PySequence_ITEM(exts, j));
 | 
				
			||||||
 | 
					                extlen = PyBytes_GET_SIZE(PySequence_ITEM(exts, j));
 | 
				
			||||||
 | 
					                ok = flen > extlen && extlen > 0 && 
 | 
				
			||||||
 | 
					                    PyOS_strnicmp(ext, v.u.s + (flen - extlen), extlen) == 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (ok) {
 | 
				
			||||||
 | 
					                if (FcPatternGet(temp, FC_FAMILY, 0, &w) != FcResultMatch) continue;
 | 
				
			||||||
 | 
					                if (w.type != FcTypeString) continue;
 | 
				
			||||||
 | 
					                t = PyString_FromString(w.u.s);
 | 
				
			||||||
 | 
					                if (t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					                if (PyList_Append(ans, t) != 0)
 | 
				
			||||||
 | 
					                    { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fontconfig_cleanup_find(pat, oset, fs);
 | 
				
			||||||
 | 
					    Py_INCREF(ans);
 | 
				
			||||||
 | 
					    return ans;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static PyObject *
 | 
				
			||||||
 | 
					fontconfig_files_for_family(PyObject *self, PyObject *args) {
 | 
				
			||||||
 | 
					    char *family; int i;
 | 
				
			||||||
 | 
					    FcPattern *pat, *tp;
 | 
				
			||||||
 | 
					    FcObjectSet *oset;
 | 
				
			||||||
 | 
					    FcFontSet *fs;
 | 
				
			||||||
 | 
					    FcValue file, weight, fullname, style, slant, family2;
 | 
				
			||||||
 | 
					    PyObject *ans, *temp, *t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!PyArg_ParseTuple(args, "s", &family))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ans = PyList_New(0);
 | 
				
			||||||
 | 
					    if (ans == NULL) return PyErr_NoMemory();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fs = NULL; oset = NULL; pat = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pat = FcPatternBuild(0, FC_FAMILY, FcTypeString, family, (char *) 0);
 | 
				
			||||||
 | 
					    if (pat == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    oset = FcObjectSetCreate();
 | 
				
			||||||
 | 
					    if (oset == NULL)  { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 | 
				
			||||||
 | 
					    if (!FcObjectSetAdd(oset, FC_FILE))  { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 | 
				
			||||||
 | 
					    if (!FcObjectSetAdd(oset, FC_STYLE)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 | 
				
			||||||
 | 
					    if (!FcObjectSetAdd(oset, FC_SLANT)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 | 
				
			||||||
 | 
					    if (!FcObjectSetAdd(oset, FC_WEIGHT)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 | 
				
			||||||
 | 
					    if (!FcObjectSetAdd(oset, FC_FAMILY)) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 | 
				
			||||||
 | 
					    if (!FcObjectSetAdd(oset, "fullname")) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fs = FcFontList(FcConfigGetCurrent(), pat, oset);
 | 
				
			||||||
 | 
					    if (fs == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < fs->nfont; i++) {
 | 
				
			||||||
 | 
					        tp = fs->fonts[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (tp == NULL) continue;
 | 
				
			||||||
 | 
					        if (FcPatternGet(tp, FC_FILE, 0, &file) != FcResultMatch) continue;
 | 
				
			||||||
 | 
					        if (FcPatternGet(tp, FC_STYLE, 0, &style) != FcResultMatch) continue;
 | 
				
			||||||
 | 
					        if (FcPatternGet(tp, FC_WEIGHT, 0, &weight) != FcResultMatch) continue;
 | 
				
			||||||
 | 
					        if (FcPatternGet(tp, FC_SLANT, 0, &slant) != FcResultMatch) continue;
 | 
				
			||||||
 | 
					        if (FcPatternGet(tp, FC_FAMILY, 0, &family2) != FcResultMatch) continue;
 | 
				
			||||||
 | 
					        if (FcPatternGet(tp, "fullname", 0, &fullname) != FcResultMatch) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        temp = PyTuple_New(6);
 | 
				
			||||||
 | 
					        if(temp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					        t = PyBytes_FromString(fullname.u.s);
 | 
				
			||||||
 | 
					        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					        PyTuple_SET_ITEM(temp, 0, t);
 | 
				
			||||||
 | 
					        t = PyBytes_FromString(file.u.s);
 | 
				
			||||||
 | 
					        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					        PyTuple_SET_ITEM(temp, 1, t);
 | 
				
			||||||
 | 
					        t = PyBytes_FromString(style.u.s);
 | 
				
			||||||
 | 
					        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					        PyTuple_SET_ITEM(temp, 2, t);
 | 
				
			||||||
 | 
					        t = PyBytes_FromString(family2.u.s);
 | 
				
			||||||
 | 
					        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					        PyTuple_SET_ITEM(temp, 3, t);
 | 
				
			||||||
 | 
					        t = PyInt_FromLong((long)weight.u.i);
 | 
				
			||||||
 | 
					        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					        PyTuple_SET_ITEM(temp, 4, t);
 | 
				
			||||||
 | 
					        t = PyInt_FromLong((long)slant.u.i);
 | 
				
			||||||
 | 
					        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					        PyTuple_SET_ITEM(temp, 5, t);
 | 
				
			||||||
 | 
					        if (PyList_Append(ans, temp) != 0)
 | 
				
			||||||
 | 
					            { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fontconfig_cleanup_find(pat, oset, fs);
 | 
				
			||||||
 | 
					    Py_INCREF(ans);
 | 
				
			||||||
 | 
					    return ans;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static PyObject *
 | 
				
			||||||
 | 
					fontconfig_match(PyObject *self, PyObject *args) {
 | 
				
			||||||
 | 
					    char *namespec; int i;
 | 
				
			||||||
 | 
					    FcPattern *pat, *tp;
 | 
				
			||||||
 | 
					    FcObjectSet *oset;
 | 
				
			||||||
 | 
					    FcFontSet *fs, *fs2;
 | 
				
			||||||
 | 
					    FcValue file, weight, fullname, style, slant, family;
 | 
				
			||||||
 | 
					    FcResult res;
 | 
				
			||||||
 | 
					    PyObject *ans, *temp, *t, *all, *verbose;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!PyArg_ParseTuple(args, "sOO", &namespec, &all, &verbose))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ans = PyList_New(0);
 | 
				
			||||||
 | 
					    if (ans == NULL) return PyErr_NoMemory();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fs = NULL; oset = NULL; pat = NULL; fs2 = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pat = FcNameParse(namespec);
 | 
				
			||||||
 | 
					    if (pat == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					    if (PyObject_IsTrue(verbose)) FcPatternPrint(pat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!FcConfigSubstitute(FcConfigGetCurrent(), pat, FcMatchPattern)) 
 | 
				
			||||||
 | 
					        { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); } 
 | 
				
			||||||
 | 
					    FcDefaultSubstitute(pat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fs = FcFontSetCreate();
 | 
				
			||||||
 | 
					    if (fs == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					    if (PyObject_IsTrue(all)) {
 | 
				
			||||||
 | 
					        fs2 = FcFontSort(FcConfigGetCurrent(), pat, FcTrue, NULL, &res);
 | 
				
			||||||
 | 
					        if (fs2 == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (i = 0; i < fs2->nfont; i++) {
 | 
				
			||||||
 | 
					            tp = fs2->fonts[i];
 | 
				
			||||||
 | 
					            if (tp == NULL) continue;
 | 
				
			||||||
 | 
					            tp = FcFontRenderPrepare(FcConfigGetCurrent(), pat, tp);
 | 
				
			||||||
 | 
					            if (tp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					            if (!FcFontSetAdd(fs, tp)) 
 | 
				
			||||||
 | 
					                { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (fs2 != NULL) FcFontSetDestroy(fs2);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        tp = FcFontMatch(FcConfigGetCurrent(), pat, &res);
 | 
				
			||||||
 | 
					        if (tp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					        if (!FcFontSetAdd(fs, tp)) 
 | 
				
			||||||
 | 
					            { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < fs->nfont; i++) {
 | 
				
			||||||
 | 
					        tp = fs->fonts[i];
 | 
				
			||||||
 | 
					        if (tp == NULL) continue;
 | 
				
			||||||
 | 
					        if (FcPatternGet(tp, FC_FILE, 0, &file) != FcResultMatch) continue;
 | 
				
			||||||
 | 
					        if (FcPatternGet(tp, FC_STYLE, 0, &style) != FcResultMatch) continue;
 | 
				
			||||||
 | 
					        if (FcPatternGet(tp, FC_WEIGHT, 0, &weight) != FcResultMatch) continue;
 | 
				
			||||||
 | 
					        if (FcPatternGet(tp, FC_SLANT, 0, &slant) != FcResultMatch) continue;
 | 
				
			||||||
 | 
					        if (FcPatternGet(tp, FC_FAMILY, 0, &family) != FcResultMatch) continue;
 | 
				
			||||||
 | 
					        if (FcPatternGet(tp, "fullname", 0, &fullname) != FcResultMatch) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        temp = PyTuple_New(6);
 | 
				
			||||||
 | 
					        if(temp == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					        t = PyBytes_FromString(fullname.u.s);
 | 
				
			||||||
 | 
					        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					        PyTuple_SET_ITEM(temp, 0, t);
 | 
				
			||||||
 | 
					        t = PyBytes_FromString(file.u.s);
 | 
				
			||||||
 | 
					        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					        PyTuple_SET_ITEM(temp, 1, t);
 | 
				
			||||||
 | 
					        t = PyBytes_FromString(style.u.s);
 | 
				
			||||||
 | 
					        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					        PyTuple_SET_ITEM(temp, 2, t);
 | 
				
			||||||
 | 
					        t = PyBytes_FromString(family.u.s);
 | 
				
			||||||
 | 
					        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					        PyTuple_SET_ITEM(temp, 3, t);
 | 
				
			||||||
 | 
					        t = PyInt_FromLong((long)weight.u.i);
 | 
				
			||||||
 | 
					        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					        PyTuple_SET_ITEM(temp, 4, t);
 | 
				
			||||||
 | 
					        t = PyInt_FromLong((long)slant.u.i);
 | 
				
			||||||
 | 
					        if(t == NULL) { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					        PyTuple_SET_ITEM(temp, 5, t);
 | 
				
			||||||
 | 
					        if (PyList_Append(ans, temp) != 0)
 | 
				
			||||||
 | 
					            { fontconfig_cleanup_find(pat, oset, fs); return PyErr_NoMemory(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fontconfig_cleanup_find(pat, oset, fs);
 | 
				
			||||||
 | 
					    Py_INCREF(ans);
 | 
				
			||||||
 | 
					    return ans;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static 
 | 
				
			||||||
 | 
					PyMethodDef fontconfig_methods[] = {
 | 
				
			||||||
 | 
					    {"initialize", fontconfig_initialize, METH_VARARGS,
 | 
				
			||||||
 | 
					    "initialize(path_to_config_file)\n\n"
 | 
				
			||||||
 | 
					    		"Initialize the library. If path to config file is specified it is used instead of the "
 | 
				
			||||||
 | 
					            "default configuration. Returns True iff the initialization succeeded."
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {"find_font_families", fontconfig_find_font_families, METH_VARARGS,
 | 
				
			||||||
 | 
					    "find_font_families(allowed_extensions)\n\n"
 | 
				
			||||||
 | 
					    		"Find all font families on the system for fonts of the specified types. If no "
 | 
				
			||||||
 | 
					            "types are specified all font families are returned."
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {"files_for_family", fontconfig_files_for_family, METH_VARARGS,
 | 
				
			||||||
 | 
					    "files_for_family(family, normalize)\n\n"
 | 
				
			||||||
 | 
					    		"Find all the variants in the font family `family`. "
 | 
				
			||||||
 | 
					            "Returns a list of tuples. Each tuple is of the form "
 | 
				
			||||||
 | 
					            "(fullname, path, style, family, weight, slant). "
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {"match", fontconfig_match, METH_VARARGS,
 | 
				
			||||||
 | 
					    "match(namespec,all,verbose)\n\n"
 | 
				
			||||||
 | 
					    		"Find all system fonts that match namespec, in decreasing order "
 | 
				
			||||||
 | 
					            "of closeness. "
 | 
				
			||||||
 | 
					            "Returns a list of tuples. Each tuple is of the form "
 | 
				
			||||||
 | 
					            "(fullname, path, style, family, weight, slant). "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {NULL, NULL, 0, NULL}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PyMODINIT_FUNC
 | 
				
			||||||
 | 
					initfontconfig(void) {
 | 
				
			||||||
 | 
					    PyObject *m;
 | 
				
			||||||
 | 
					    m = Py_InitModule3(
 | 
				
			||||||
 | 
					            "fontconfig", fontconfig_methods,
 | 
				
			||||||
 | 
					            "Find fonts."
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    if (m == NULL) return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user