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))
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')
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))
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
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')