Beispiel #1
0
    def __call__(self, oeb, log, opts):
        self.oeb, self.log, self.opts = oeb, log, opts

        self.find_embedded_fonts()
        if not self.embedded_fonts:
            self.log.debug('No embedded fonts found')
            return
        self.find_style_rules()
        self.find_font_usage()

        totals = [0, 0]

        def remove(font):
            totals[1] += len(font['item'].data)
            self.oeb.manifest.remove(font['item'])
            font['rule'].parentStyleSheet.deleteRule(font['rule'])

        fonts = {}
        for font in self.embedded_fonts:
            item, chars = font['item'], font['chars']
            if item.href in fonts:
                fonts[item.href]['chars'] |= chars
            else:
                fonts[item.href] = font

        for font in fonts.itervalues():
            if not font['chars']:
                self.log('The font %s is unused. Removing it.' % font['src'])
                remove(font)
                continue
            try:
                raw, old_stats, new_stats = subset(font['item'].data,
                                                   font['chars'])
            except NoGlyphs:
                self.log('The font %s has no used glyphs. Removing it.' %
                         font['src'])
                remove(font)
                continue
            except UnsupportedFont as e:
                self.log.warn('The font %s is unsupported for subsetting. %s' %
                              (font['src'], e))
                sz = len(font['item'].data)
                totals[0] += sz
                totals[1] += sz
            else:
                font['item'].data = raw
                nlen = sum(new_stats.itervalues())
                olen = sum(old_stats.itervalues())
                self.log(
                    'Decreased the font %s to %.1f%% of its original size' %
                    (font['src'], nlen / olen * 100))
                totals[0] += nlen
                totals[1] += olen

            font['item'].unload_data_from_memory()

        if totals[0]:
            self.log('Reduced total font size to %.1f%% of original' %
                     (totals[0] / totals[1] * 100))
Beispiel #2
0
def subset_all_fonts(container, font_stats, report):
    remove = set()
    total_old = total_new = 0
    for name, mt in container.mime_map.iteritems():
        if (mt in OEB_FONTS or name.rpartition('.')[-1].lower() in {'otf', 'ttf'}) and mt != guess_type('a.woff'):
            chars = font_stats.get(name, set())
            path = container.name_path_map[name]
            total_old += os.path.getsize(path)
            if not chars:
                remove.add(name)
                report('Removed unused font: %s'%name)
                continue
            with open(path, 'r+b') as f:
                raw = f.read()
                font_name = get_font_names(raw)[-1]
                warnings = []
                container.log('Subsetting font: %s'%(font_name or name))
                try:
                    nraw, old_sizes, new_sizes = subset(raw, chars,
                                                   warnings=warnings)
                except UnsupportedFont as e:
                    container.log.warning(
                        'Unsupported font: %s, ignoring.  Error: %s'%(
                            name, as_unicode(e)))
                    continue

                for w in warnings:
                    container.log.warn(w)
                olen = sum(old_sizes.itervalues())
                nlen = sum(new_sizes.itervalues())
                total_new += len(nraw)
                if nlen == olen:
                    report('The font %s was already subset'%font_name)
                else:
                    report('Decreased the font %s to %.1f%% of its original size'%
                       (font_name, nlen/olen * 100))
                f.seek(0), f.truncate(), f.write(nraw)

    for name in remove:
        container.remove_item(name)

    if remove:
        for name, mt in container.mime_map.iteritems():
            if mt in OEB_STYLES:
                sheet = container.parsed(name)
                if remove_font_face_rules(container, sheet, remove, name):
                    container.dirty(name)
            elif mt in OEB_DOCS:
                for style in XPath('//h:style')(container.parsed(name)):
                    if style.get('type', 'text/css') == 'text/css' and style.text:
                        sheet = container.parse_css(style.text, name)
                        if remove_font_face_rules(container, sheet, remove, name):
                            style.text = sheet.cssText
                            container.dirty(name)
    if total_old > 0:
        report('Reduced total font size to %.1f%% of original'%(
            total_new/total_old*100))
    else:
        report('No embedded fonts found')
Beispiel #3
0
    def __call__(self, oeb, log, opts):
        self.oeb, self.log, self.opts = oeb, log, opts

        self.find_embedded_fonts()
        if not self.embedded_fonts:
            self.log.debug('No embedded fonts found')
            return
        self.find_style_rules()
        self.find_font_usage()

        totals = [0, 0]

        def remove(font):
            totals[1] += len(font['item'].data)
            self.oeb.manifest.remove(font['item'])
            font['rule'].parentStyleSheet.deleteRule(font['rule'])

        fonts = {}
        for font in self.embedded_fonts:
            item, chars = font['item'], font['chars']
            if item.href in fonts:
                fonts[item.href]['chars'] |= chars
            else:
                fonts[item.href] = font

        for font in fonts.itervalues():
            if not font['chars']:
                self.log('The font %s is unused. Removing it.'%font['src'])
                remove(font)
                continue
            try:
                raw, old_stats, new_stats = subset(font['item'].data, font['chars'])
            except NoGlyphs:
                self.log('The font %s has no used glyphs. Removing it.'%font['src'])
                remove(font)
                continue
            except UnsupportedFont as e:
                self.log.warn('The font %s is unsupported for subsetting. %s'%(
                    font['src'], e))
                sz = len(font['item'].data)
                totals[0] += sz
                totals[1] += sz
            else:
                font['item'].data = raw
                nlen = sum(new_stats.itervalues())
                olen = sum(old_stats.itervalues())
                self.log('Decreased the font %s to %.1f%% of its original size'%
                        (font['src'], nlen/olen *100))
                totals[0] += nlen
                totals[1] += olen

            font['item'].unload_data_from_memory()

        if totals[0]:
            self.log('Reduced total font size to %.1f%% of original'%
                    (totals[0]/totals[1] * 100))
Beispiel #4
0
def subset_all_fonts(container, font_stats, report):
    remove = set()
    total_old = total_new = 0
    changed = False
    for name, mt in iter_subsettable_fonts(container):
        chars = font_stats.get(name, set())
        with container.open(name, 'rb') as f:
            f.seek(0, os.SEEK_END)
            total_old += f.tell()
        if not chars:
            remove.add(name)
            report(_('Removed unused font: %s')%name)
            continue
        with container.open(name, 'r+b') as f:
            raw = f.read()
            try:
                font_name = get_font_names(raw)[-1]
            except Exception as e:
                container.log.warning(
                    'Corrupted font: %s, ignoring.  Error: %s'%(
                        name, as_unicode(e)))
                continue
            warnings = []
            container.log('Subsetting font: %s'%(font_name or name))
            try:
                nraw, old_sizes, new_sizes = subset(raw, chars,
                                                warnings=warnings)
            except UnsupportedFont as e:
                container.log.warning(
                    'Unsupported font: %s, ignoring.  Error: %s'%(
                        name, as_unicode(e)))
                continue

            for w in warnings:
                container.log.warn(w)
            olen = sum(old_sizes.itervalues())
            nlen = sum(new_sizes.itervalues())
            total_new += len(nraw)
            if nlen == olen:
                report(_('The font %s was already subset')%font_name)
            else:
                report(_('Decreased the font {0} to {1} of its original size').format(
                    font_name, ('%.1f%%' % (nlen/olen * 100))))
                changed = True
            f.seek(0), f.truncate(), f.write(nraw)

    for name in remove:
        container.remove_item(name)
        changed = True

    if remove:
        for name, mt in container.mime_map.iteritems():
            if mt in OEB_STYLES:
                sheet = container.parsed(name)
                if remove_font_face_rules(container, sheet, remove, name):
                    container.dirty(name)
            elif mt in OEB_DOCS:
                for style in XPath('//h:style')(container.parsed(name)):
                    if style.get('type', 'text/css') == 'text/css' and style.text:
                        sheet = container.parse_css(style.text, name)
                        if remove_font_face_rules(container, sheet, remove, name):
                            style.text = sheet.cssText
                            container.dirty(name)
    if total_old > 0:
        report(_('Reduced total font size to %.1f%% of original')%(
            total_new/total_old*100))
    else:
        report(_('No embedded fonts found'))
    return changed
Beispiel #5
0
def subset_all_fonts(container, font_stats, report):
    remove = set()
    total_old = total_new = 0
    for name, mt in container.mime_map.iteritems():
        if mt in OEB_FONTS or name.rpartition('.')[-1].lower() in {
                'otf', 'ttf'
        }:
            chars = font_stats.get(name, set())
            path = container.name_path_map[name]
            total_old += os.path.getsize(path)
            if not chars:
                remove.add(name)
                report('Removed unused font: %s' % name)
                continue
            with open(path, 'r+b') as f:
                raw = f.read()
                font_name = get_font_names(raw)[-1]
                warnings = []
                container.log('Subsetting font: %s' % (font_name or name))
                try:
                    nraw, old_sizes, new_sizes = subset(raw,
                                                        chars,
                                                        warnings=warnings)
                except UnsupportedFont as e:
                    container.log.warning(
                        'Unsupported font: %s, ignoring.  Error: %s' %
                        (name, as_unicode(e)))
                    continue

                for w in warnings:
                    container.log.warn(w)
                olen = sum(old_sizes.itervalues())
                nlen = sum(new_sizes.itervalues())
                total_new += len(nraw)
                if nlen == olen:
                    report('The font %s was already subset' % font_name)
                else:
                    report(
                        'Decreased the font %s to %.1f%% of its original size'
                        % (font_name, nlen / olen * 100))
                f.seek(0), f.truncate(), f.write(nraw)

    for name in remove:
        container.remove_item(name)

    if remove:
        for name, mt in container.mime_map.iteritems():
            if mt in OEB_STYLES:
                sheet = container.parsed(name)
                if remove_font_face_rules(container, sheet, remove, name):
                    container.dirty(name)
            elif mt in OEB_DOCS:
                for style in XPath('//h:style')(container.parsed(name)):
                    if style.get('type',
                                 'text/css') == 'text/css' and style.text:
                        sheet = container.parse_css(style.text, name)
                        if remove_font_face_rules(container, sheet, remove,
                                                  name):
                            style.text = sheet.cssText
                            container.dirty(name)
    if total_old > 0:
        report('Reduced total font size to %.1f%% of original' %
               (total_new / total_old * 100))
    else:
        report('No embedded fonts found')