def add_font_face(self, rule_descriptors, url_fetcher): if self.font_map is None: return for font_type, url in rule_descriptors['src']: if url is None: continue if font_type in ('external', 'local'): config = self._fontconfig_config fetch_as_url = True if font_type == 'local': font_name = url.encode('utf-8') pattern = ffi.gc(fontconfig.FcPatternCreate(), fontconfig.FcPatternDestroy) fontconfig.FcConfigSubstitute(config, pattern, fontconfig.FcMatchFont) fontconfig.FcDefaultSubstitute(pattern) fontconfig.FcPatternAddString(pattern, b'fullname', font_name) fontconfig.FcPatternAddString(pattern, b'postscriptname', font_name) family = ffi.new('FcChar8 **') postscript = ffi.new('FcChar8 **') result = ffi.new('FcResult *') matching_pattern = fontconfig.FcFontMatch( config, pattern, result) # prevent RuntimeError, see issue #677 if matching_pattern == ffi.NULL: LOGGER.debug( 'Failed to get matching local font for %r', font_name.decode('utf-8')) continue # TODO: do many fonts have multiple family values? fontconfig.FcPatternGetString(matching_pattern, b'fullname', 0, family) fontconfig.FcPatternGetString(matching_pattern, b'postscriptname', 0, postscript) family = ffi.string(family[0]) postscript = ffi.string(postscript[0]) if font_name.lower() in (family.lower(), postscript.lower()): filename = ffi.new('FcChar8 **') fontconfig.FcPatternGetString(matching_pattern, b'file', 0, filename) path = ffi.string( filename[0]).decode(FILESYSTEM_ENCODING) url = pathlib.Path(path).as_uri() else: LOGGER.debug('Failed to load local font "%s"', font_name.decode('utf-8')) continue try: if fetch_as_url: with fetch(url_fetcher, url) as result: if 'string' in result: font = result['string'] else: font = result['file_obj'].read() else: with open(url, 'rb') as fd: font = fd.read() if font[:3] == b'wOF': out = io.BytesIO() if font[3:4] == b'F': # woff font ttfont = TTFont(io.BytesIO(font)) ttfont.flavor = ttfont.flavorData = None ttfont.save(out) elif font[3:4] == b'2': # woff2 font woff2.decompress(io.BytesIO(font), out) font = out.getvalue() except Exception as exc: LOGGER.debug('Failed to load font at %r (%s)', url, exc) continue font_features = { rules[0][0].replace('-', '_'): rules[0][1] for rules in rule_descriptors.get('font_variant', []) } if 'font_feature_settings' in rule_descriptors: font_features['font_feature_settings'] = ( rule_descriptors['font_feature_settings']) features_string = '' for key, value in get_font_features(**font_features).items(): features_string += f'<string>{key} {value}</string>' fd = tempfile.NamedTemporaryFile('wb', dir=self._tempdir, delete=False) font_filename = fd.name fd.write(font) fd.close() self._filenames.append(font_filename) fontconfig_style = FONTCONFIG_STYLE_CONSTANTS[ rule_descriptors.get('font_style', 'normal')] fontconfig_weight = FONTCONFIG_WEIGHT_CONSTANTS[ rule_descriptors.get('font_weight', 'normal')] fontconfig_stretch = FONTCONFIG_STRETCH_CONSTANTS[ rule_descriptors.get('font_stretch', 'normal')] xml = f'''<?xml version="1.0"?> <!DOCTYPE fontconfig SYSTEM "fonts.dtd"> <fontconfig> <match target="scan"> <test name="file" compare="eq"> <string>{font_filename}</string> </test> <edit name="family" mode="assign_replace"> <string>{rule_descriptors['font_family']}</string> </edit> <edit name="slant" mode="assign_replace"> <const>{fontconfig_style}</const> </edit> <edit name="weight" mode="assign_replace"> <const>{fontconfig_weight}</const> </edit> <edit name="width" mode="assign_replace"> <const>{fontconfig_stretch}</const> </edit> </match> <match target="font"> <test name="file" compare="eq"> <string>{font_filename}</string> </test> <edit name="fontfeatures" mode="assign_replace">{features_string}</edit> </match> </fontconfig>''' fd = tempfile.NamedTemporaryFile('w', dir=self._tempdir, delete=False) fd.write(xml) fd.close() self._filenames.append(fd.name) fontconfig.FcConfigParseAndLoad( config, fd.name.encode(FILESYSTEM_ENCODING), True) font_added = fontconfig.FcConfigAppFontAddFile( config, font_filename.encode(FILESYSTEM_ENCODING)) if font_added: # TODO: We should mask local fonts with the same name # too as explained in Behdad's blog entry. # TODO: What about pango_fc_font_map_config_changed() # as suggested in Behdad's blog entry? # Though it seems to work without… return font_filename else: LOGGER.debug('Failed to load font at %r', url) LOGGER.warning('Font-face %r cannot be loaded', rule_descriptors['font_family'])
import fontTools.ttLib.woff2 as wf2 import base64 import os import re from pathlib import Path Current_dir = Path(__file__).parent os.chdir(Current_dir) files = Current_dir.rglob('css/*.css') regxy = r"url\('data:application\/octet-stream;base64,(.+)'\) format" for fll in files: fily = open(fll, 'r', encoding='utf-8') matches = re.finditer(regxy, fily.read(), re.MULTILINE) match = next(matches).group(1) debased = base64.b64decode(match) woff2 = Path(f'{Current_dir}/woff2/{fll.name}.woff2') open(woff2, 'wb').write(debased) otf = Path(f'{Current_dir}/otf/{fll.name}.otf') wf2.decompress(woff2, otf) # fily = open('fily.txt', 'r', encoding='utf-8') # daty = base64.b64decode(fily.read()) # open('fily.woff2', 'wb').write(daty) # wf2.decompress('fily.woff2', 'fily.otf')