From 2974bb4d1efd7959d2c72f8c7a8301e8bf1c881d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 18 Nov 2016 14:09:45 +0530 Subject: [PATCH] Edit Book: Check Book: Add a test to check if the embedded fonts in the book have their embedding permissions enabled --- src/calibre/ebooks/oeb/polish/check/fonts.py | 19 +++++++++++++++++- src/calibre/utils/fonts/utils.py | 21 +++++++++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/calibre/ebooks/oeb/polish/check/fonts.py b/src/calibre/ebooks/oeb/polish/check/fonts.py index 67bd23a43f..0d3566fe53 100644 --- a/src/calibre/ebooks/oeb/polish/check/fonts.py +++ b/src/calibre/ebooks/oeb/polish/check/fonts.py @@ -14,7 +14,7 @@ from calibre.ebooks.oeb.polish.check.base import BaseError, WARN from calibre.ebooks.oeb.polish.container import OEB_FONTS from calibre.ebooks.oeb.polish.pretty import pretty_script_or_style from calibre.ebooks.oeb.polish.fonts import change_font_in_declaration -from calibre.utils.fonts.utils import get_all_font_names +from calibre.utils.fonts.utils import get_all_font_names, is_font_embeddable, UnsupportedFont from tinycss.fonts3 import parse_font_family @@ -32,6 +32,17 @@ def fix_sheet(sheet, css_name, font_name): return changed +class NotEmbeddable(BaseError): + + level = WARN + + def __init__(self, name, fs_type): + BaseError.__init__(self, _('The font {} is not allowed to be embedded').format(name), name) + self.HELP = _('The font has a flag in its metadata ({:09b}) set indicating that it is' + ' not licensed for embedding. You can ignore this warning, if you are' + ' sure you have permission to embed this font.').format(fs_type) + + class FontAliasing(BaseError): level = WARN @@ -83,6 +94,12 @@ def check_fonts(container): errors.append(InvalidFont(_('Not a valid font: %s') % e, name)) continue font_map[name] = name_map.get('family_name', None) or name_map.get('preferred_family_name', None) or name_map.get('wws_family_name', None) + try: + embeddable, fs_type = is_font_embeddable(raw) + except UnsupportedFont: + embeddable = True + if not embeddable: + errors.append(NotEmbeddable(name, fs_type)) sheets = [] for name, mt in container.mime_map.iteritems(): diff --git a/src/calibre/utils/fonts/utils.py b/src/calibre/utils/fonts/utils.py index db3f0ef22c..e28660cbc2 100644 --- a/src/calibre/utils/fonts/utils.py +++ b/src/calibre/utils/fonts/utils.py @@ -328,6 +328,26 @@ def remove_embed_restriction(raw): return raw +def is_font_embeddable(raw): + # https://www.microsoft.com/typography/otspec/os2.htm#fst + ok, sig = is_truetype_font(raw) + if not ok: + raise UnsupportedFont('Not a supported font, sfnt_version: %r'%sig) + + table, table_index, table_offset = get_table(raw, 'os/2')[:3] + if table is None: + raise UnsupportedFont('Not a supported font, has no OS/2 table') + fs_type_offset = struct.calcsize(b'>HhHH') + fs_type = struct.unpack_from(b'>H', table, fs_type_offset)[0] + if fs_type == 0 or fs_type & 0x8: + return True, fs_type + if fs_type & 1: + return False, fs_type + if fs_type & 0x200: + return False, fs_type + return True, fs_type + + def read_bmp_prefix(table, bmp): length, language, segcount = struct.unpack_from(b'>3H', table, bmp+2) array_len = segcount //2 @@ -479,4 +499,3 @@ def main(): if __name__ == '__main__': main() -