Esempio n. 1
0
    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')