Example #1
0
def main(args):
  """Subset a font (useful for making small test fonts).

  Args:
    args: list, arguments the user typed.
  """
  parser = argparse.ArgumentParser()
  parser.add_argument('fontfile', help='Input font file')
  parser.add_argument('--subset_postfix', default='',
                      help='Postfix to the subset extension')
  parser.add_argument('--text', default='',
                      help='Text to include in the subset')
  parser.add_argument('--unicodes', default='',
                      help='Comma separated list of Unicode codepoints (hex) '
                      'to include in the subset; eg, "e7,0xe8,U+00e9"')
  parser.add_argument('--glyphs', default='',
                      help='Comma separated list of glyph IDs (decimal) to '
                      'include in the subset; eg, "1,27"')
  parser.add_argument('--hinting', default=False, action='store_true',
                      help='Enable hinting if specified, no hinting if not '
                      'present')

  cmd_args = parser.parse_args(args)

  options = Options()
  # Definitely want the .notdef glyph and outlines.
  options.notdef_glyph = True
  options.notdef_outline = True
  # Get the item. to keep in the subset.
  text = cmd_args.text
  unicodes_str = cmd_args.unicodes.lower().replace('0x', '').replace('u+', '')
  # TODO(bstell) replace this whole files by using the new subset.py code
  unicodes_input = [c for c in unicodes_str.split(',') if c]
  unicodes = []
  for c in unicodes_input:
    if '-' in c:
      uni_range = c.split('-')
      uni_range_expanded = range(int(uni_range[0], 16), int(uni_range[1], 16) + 1)
      unicodes.extend(uni_range_expanded)
    else:
      unicodes.append(int(c, 16))
  #unicodes = [int(c, 16) for c in unicodes_input_expanded]
  glyphs = [int(c) for c in cmd_args.glyphs.split(',') if c]
  fontfile = cmd_args.fontfile
  options.hinting = cmd_args.hinting  # False => no hinting
  options.hinting = True  # hint stripping for CFF is currently broken

  dirname = os.path.dirname(fontfile)
  basename = os.path.basename(fontfile)
  filename, extension = os.path.splitext(basename)
  subset_postfix = cmd_args.subset_postfix
  output_file = dirname + '/' + filename + '_subset' + subset_postfix + extension
  print "output_file =", output_file
  font = load_font(fontfile, options, lazy=False)

  subsetter = Subsetter(options)
  subsetter.populate(text=text, unicodes=unicodes, glyphs=glyphs)
  subsetter.subset(font)
  save_font(font, output_file, options)
Example #2
0
    def run(self, filename, pipedata):
        if 'optimize' in pipedata and not pipedata['optimize']:
            return
        self.bakery.logging_raw('### Optimize TTF {}'.format(filename))
        # copied from https://code.google.com/p/noto/source/browse/nototools/subset.py
        from fontTools.subset import Options, Subsetter, load_font, save_font

        options = Options()
        options.layout_features = "*"
        options.name_IDs = "*"
        options.hinting = True
        options.notdef_outline = True

        font = load_font(op.join(self.builddir, filename), options)
        subsetter = Subsetter(options=options)
        subsetter.populate(glyphs=font.getGlyphOrder())
        subsetter.subset(font)
        save_font(font, op.join(self.builddir, filename + '.opt'), options)

        newsize = op.getsize(op.join(self.builddir, filename + '.opt'))
        origsize = op.getsize(op.join(self.builddir, filename))

        # compare filesizes TODO print analysis of this :)
        comment = "# look at the size savings of that subset process"
        self.bakery.logging_cmd("ls -l '%s'* %s" % (filename, comment))

        statusmessage = "{0}.opt: {1} bytes\n{0}: {2} bytes\n"
        self.bakery.logging_raw(statusmessage.format(filename, newsize, origsize))

        # move ttx files to src
        shutil.move(op.join(self.builddir, filename + '.opt'),
                    op.join(self.builddir, filename),
                    log=self.bakery.logger)
Example #3
0
    def __generateForWeight(self, weight: str, font: Font) -> None:
        package = self.__core.package
        base_dir = self.__core.directories.webfonts
        output_dir = base_dir.joinpath(f"./{package.version}/{weight}")
        font_path = self.__core.findFontfilePath(font)

        output_dir.mkdir(parents=True, exist_ok=True)
        metadata = self.__generateMetadata()

        fake = Faker()
        fake.seed(package.id)
        subset_fontname: str = fake.name()

        options = Options()
        options.font_number = font.number
        options.hinting = False
        options.desubroutinize = True
        options.drop_tables += [
            'FFTM', 'PfEd', 'TeX', 'BDF', 'cvt', 'fpgm', 'prep', 'gasp',
            'VORG', 'CBDT', 'CBLC', 'sbix'
        ]
        for ignored in ['rvrn', 'locl']:
            options.layout_features.remove(ignored)

        for unicodes_file in FILE_DIR.UNICODE_TEXT.glob('./**/*.txt'):
            idx = unicodes_file.stem
            unicodes: List[str] = []

            with open(unicodes_file, 'r') as unicode_read_io:
                for line in unicode_read_io.readlines():
                    unicodes.extend(parse_unicodes(line.split('#')[0]))

            with load_font(font_path, options) as ttfont:
                subsetter = Subsetter(options=options)
                subsetter.populate(unicodes=unicodes)
                subsetter.subset(ttfont)

                for record in ttfont['name'].names:
                    if record.nameID == NAME_ID.COPYRIGHT:
                        record.string = '\n'.join(package.copyrights)
                    elif record.nameID in FAMILY_RELATED_NAME_ID:
                        record.string = subset_fontname

                woff_file = output_dir.joinpath(f"{idx}.woff")
                with open(woff_file, 'wb') as woff_write_io:
                    options.flavor = 'woff'
                    ttfont.flavorData = WOFFFlavorData()
                    ttfont.flavorData.metaData = metadata
                    save_font(ttfont, woff_write_io, options)

                woff2_file = output_dir.joinpath(f"{idx}.woff2")
                with open(woff2_file, 'wb') as woff2_write_io:
                    options.flavor = 'woff2'
                    ttfont.flavorData = WOFF2FlavorData()
                    ttfont.flavorData.metaData = metadata
                    save_font(ttfont, woff2_write_io, options)
Example #4
0
    def run(self, pipedata):
        if 'optimize' in pipedata and not pipedata['optimize']:
            return

        from bakery_cli.utils import ProcessedFile
        filename = ProcessedFile()

        self.bakery.logging_raw('### Optimize TTF {}'.format(filename))
        # copied from https://code.google.com/p/noto/source/browse/nototools/subset.py
        from fontTools.subset import Options, Subsetter, load_font, save_font

        options = Options()
        options.layout_features = ["*"]
        options.name_IDs = ["*"]
        options.hinting = True
        options.legacy_kern = True
        options.notdef_outline = True
        options.no_subset_tables += ['DSIG']
        options.drop_tables = list(
            set(options._drop_tables_default) - set(['DSIG']))

        cmd_options = ('--glyphs=*'
                       ' --layout-features=*'
                       ' --name-IDs=*'
                       ' --hinting'
                       ' --legacy-kern --notdef-outline'
                       ' --no-subset-tables+=DSIG'
                       ' --drop-tables-=DSIG')

        font = load_font(op.join(self.builddir, filename), options)

        cmdline = 'pyftsubset {1} {0}'.format(cmd_options,
                                              op.join(self.builddir, filename))
        self.bakery.logging_cmd(cmdline)

        subsetter = Subsetter(options=options)
        subsetter.populate(glyphs=font.getGlyphOrder())
        subsetter.subset(font)
        save_font(font, op.join(self.builddir, filename + '.fix'), options)

        # compare filesizes TODO print analysis of this :)
        comment = "# look at the size savings of that subset process"
        self.bakery.logging_cmd(comment)
        run(u"ls -la {0} {0}.fix | awk '{{ print $5 \"\t\" $9 }}'".format(
            unicode(op.join(self.builddir, filename))))

        comment = "# copy back optimized ttf to original filename"
        self.bakery.logging_cmd(comment)
        shutil.move(op.join(self.builddir, filename + '.fix'),
                    op.join(self.builddir, filename))
Example #5
0
    def run(self, pipedata):
        if 'optimize' in pipedata and not pipedata['optimize']:
            return

        from bakery_cli.utils import ProcessedFile
        filename = ProcessedFile()

        self.bakery.logging_raw('### Optimize TTF {}'.format(filename))
        # copied from https://code.google.com/p/noto/source/browse/nototools/subset.py
        from fontTools.subset import Options, Subsetter, load_font, save_font

        options = Options()
        options.layout_features = ["*"]
        options.name_IDs = ["*"]
        options.hinting = True
        options.legacy_kern = True
        options.notdef_outline = True
        options.no_subset_tables += ['DSIG']
        options.drop_tables = list(set(options._drop_tables_default) - set(['DSIG']))

        cmd_options = ('--glyphs=*'
                       ' --layout-features=*'
                       ' --name-IDs=*'
                       ' --hinting'
                       ' --legacy-kern --notdef-outline'
                       ' --no-subset-tables+=DSIG'
                       ' --drop-tables-=DSIG')

        font = load_font(op.join(self.builddir, filename), options)

        cmdline = 'pyftsubset {1} {0}'.format(cmd_options, op.join(self.builddir, filename))
        self.bakery.logging_cmd(cmdline)

        subsetter = Subsetter(options=options)
        subsetter.populate(glyphs=font.getGlyphOrder())
        subsetter.subset(font)
        save_font(font, op.join(self.builddir, filename + '.fix'), options)

        # compare filesizes TODO print analysis of this :)
        comment = "# look at the size savings of that subset process"
        self.bakery.logging_cmd(comment)
        run(u"ls -la {0} {0}.fix | awk '{{ print $5 \"\t\" $9 }}'".format(unicode(op.join(self.builddir, filename))))

        comment = "# copy back optimized ttf to original filename"
        self.bakery.logging_cmd(comment)
        shutil.move(op.join(self.builddir, filename + '.fix'),
                    op.join(self.builddir, filename))
Example #6
0
def main(args):
  """Subset a font (useful for making small test fonts).

  Args:
    args: list, arguments the user typed.
  """
  parser = argparse.ArgumentParser()
  parser.add_argument('fontfile', help='Input font file')
  parser.add_argument('--text', default='',
                      help='Text to include in the subset')
  parser.add_argument('--unicodes', default='',
                      help='Comma separated list of Unicode codepoints (hex) '
                      'to include in the subset; eg, "e7,0xe8,U+00e9"')
  parser.add_argument('--glyphs', default='',
                      help='Comma separated list of glyph IDs (decimal) to '
                      'include in the subset; eg, "1,27"')
  parser.add_argument('--hinting', default=False, action='store_true',
                      help='Enable hinting if specified, no hinting if not '
                      'present')

  cmd_args = parser.parse_args(args)

  options = Options()
  # Definitely want the .notdef glyph and outlines.
  options.notdef_glyph = True
  options.notdef_outline = True
  # Get the item. to keep in the subset.
  text = cmd_args.text
  unicodes_str = cmd_args.unicodes.lower().replace('0x', '').replace('u+', '')
  unicodes = [int(c, 16) for c in unicodes_str.split(',') if c]
  glyphs = [int(c) for c in cmd_args.glyphs.split(',') if c]
  fontfile = cmd_args.fontfile
  options.hinting = cmd_args.hinting  # False => no hinting

  dirname = os.path.dirname(fontfile)
  basename = os.path.basename(fontfile)
  filename, extension = os.path.splitext(basename)
  output_file = dirname + '/' + filename + '_subset' + extension
  font = load_font(fontfile, options, lazy=False)

  subsetter = Subsetter(options)
  subsetter.populate(text=text, unicodes=unicodes, glyphs=glyphs)
  subsetter.subset(font)
  save_font(font, output_file, options)
Example #7
0
    def run(self, filename, pipedata):
        if 'optimize' in pipedata and not pipedata['optimize']:
            return

        self.bakery.logging_raw('### Optimize TTF {}'.format(filename))
        # copied from https://code.google.com/p/noto/source/browse/nototools/subset.py
        from fontTools.subset import Options, Subsetter, load_font, save_font

        options = Options()
        options.layout_features = ["*"]
        options.name_IDs = ["*"]
        options.hinting = True
        options.legacy_kern = True
        options.notdef_outline = True
        options.no_subset_tables += ['DSIG']
        options.drop_tables = list(
            set(options._drop_tables_default) - set(['DSIG']))

        font = load_font(op.join(self.builddir, filename), options)
        self.bakery.logging_raw('Before: {}'.format(font.keys()))

        self.bakery.logging_raw('{}'.format(options.__dict__))
        subsetter = Subsetter(options=options)
        subsetter.populate(glyphs=font.getGlyphOrder())
        subsetter.subset(font)
        save_font(font, op.join(self.builddir, filename + '.opt'), options)

        newsize = op.getsize(op.join(self.builddir, filename + '.opt'))
        origsize = op.getsize(op.join(self.builddir, filename))

        # compare filesizes TODO print analysis of this :)
        comment = "# look at the size savings of that subset process"
        self.bakery.logging_cmd("ls -l '%s'* %s" % (filename, comment))

        statusmessage = "{0}.opt: {1} bytes\n{0}: {2} bytes\n"
        self.bakery.logging_raw(
            statusmessage.format(filename, newsize, origsize))

        self.bakery.logging_raw('Now: {}'.format(font.keys()))
        # move ttx files to src
        shutil.move(op.join(self.builddir, filename + '.opt'),
                    op.join(self.builddir, filename),
                    log=self.bakery.logger)
Example #8
0
    def _subset(self, otf, fmt):
        from fontTools.subset import Options, Subsetter

        for name, subset in self.subsets.items():
            logger.info(f"Creating {name}.{fmt.value} subset")
            new = deepcopy(otf)
            options = Options()
            options.name_IDs = ["*"]
            options.name_legacy = True
            options.name_languages = ["*"]
            options.recommended_glyphs = True
            options.layout_features = ["*"]
            options.notdef_outline = True
            options.notdef_glyph = True
            options.glyph_names = True
            options.hinting = True
            options.legacy_kern = True
            options.symbol_cmap = True
            options.layout_closure = False
            options.prune_unicode_ranges = False
            options.passthrough_tables = False
            options.recalc_average_width = True
            options.ignore_missing_glyphs = True
            options.layout_scripts = subset["langsys"]

            options.drop_tables.remove("DSIG")
            options.no_subset_tables += ["DSIG"]

            subsetter = Subsetter(options=options)
            subsetter.populate(subset["glyphlist"])

            with TemporaryLogLevel(logging.WARNING):
                subsetter.subset(new)

            new = self._optimize(new, name, fmt)
            names = subset.get("names")
            if names:
                logger.info(
                    f"Adding name entries to {name}.{fmt.value} susbet")
                self._setnames(new, names)
            self._buildwoff(new, name, fmt)
            self._save(new, name, fmt)
Example #9
0
def main(args):
    """Subset a font (useful for making small test fonts).

  Args:
    args: list, arguments the user typed.
  """
    parser = argparse.ArgumentParser()
    parser.add_argument('fontfile', help='Input font file')
    parser.add_argument('--subset_postfix',
                        default='',
                        help='Postfix to the subset extension')
    parser.add_argument('--text',
                        default='',
                        help='Text to include in the subset')
    parser.add_argument(
        '--unicodes',
        default='',
        help='Comma separated list of Unicode codepoints (hex) '
        'to include in the subset; eg, "e7,0xe8,U+00e9"')
    parser.add_argument('--glyphs',
                        default='',
                        help='Comma separated list of glyph IDs (decimal) to '
                        'include in the subset; eg, "1,27"')
    parser.add_argument('--hinting',
                        default=False,
                        action='store_true',
                        help='Enable hinting if specified, no hinting if not '
                        'present')

    cmd_args = parser.parse_args(args)

    options = Options()
    # Definitely want the .notdef glyph and outlines.
    options.notdef_glyph = True
    options.notdef_outline = True
    # Get the item. to keep in the subset.
    text = cmd_args.text
    unicodes_str = cmd_args.unicodes.lower().replace('0x',
                                                     '').replace('u+', '')
    # TODO(bstell) replace this whole files by using the new subset.py code
    unicodes_input = [c for c in unicodes_str.split(',') if c]
    unicodes = []
    for c in unicodes_input:
        if '-' in c:
            uni_range = c.split('-')
            uni_range_expanded = range(int(uni_range[0], 16),
                                       int(uni_range[1], 16) + 1)
            unicodes.extend(uni_range_expanded)
        else:
            unicodes.append(int(c, 16))
    #unicodes = [int(c, 16) for c in unicodes_input_expanded]
    glyphs = [int(c) for c in cmd_args.glyphs.split(',') if c]
    fontfile = cmd_args.fontfile
    options.hinting = cmd_args.hinting  # False => no hinting
    options.hinting = True  # hint stripping for CFF is currently broken

    dirname = os.path.dirname(fontfile)
    basename = os.path.basename(fontfile)
    filename, extension = os.path.splitext(basename)
    subset_postfix = cmd_args.subset_postfix
    output_file = dirname + '/' + filename + '_subset' + subset_postfix + extension
    print "output_file =", output_file
    font = load_font(fontfile, options, lazy=False)

    subsetter = Subsetter(options)
    subsetter.populate(text=text, unicodes=unicodes, glyphs=glyphs)
    subsetter.subset(font)
    save_font(font, output_file, options)