mirror of
https://github.com/gryf/ebook-converter.git
synced 2026-01-04 01:44:11 +01:00
Here is the first batch of modules, which are needed for converting several formats to LRF. Some of the logic has been change, more cleanups will follow.
123 lines
4.3 KiB
Python
123 lines
4.3 KiB
Python
#!/usr/bin/env python2
|
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
|
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
|
|
|
__license__ = 'GPL v3'
|
|
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
|
|
__docformat__ = 'restructuredtext en'
|
|
|
|
from io import BytesIO
|
|
from struct import calcsize, unpack, unpack_from
|
|
from collections import namedtuple
|
|
|
|
from ebook_converter.utils.fonts.utils import get_font_names2, get_font_characteristics
|
|
from ebook_converter.polyglot.builtins import range, unicode_type
|
|
|
|
|
|
class UnsupportedFont(ValueError):
|
|
pass
|
|
|
|
|
|
FontCharacteristics = namedtuple('FontCharacteristics',
|
|
'weight, is_italic, is_bold, is_regular, fs_type, panose, width, is_oblique, is_wws, os2_version')
|
|
FontNames = namedtuple('FontNames',
|
|
'family_name, subfamily_name, full_name, preferred_family_name, preferred_subfamily_name, wws_family_name, wws_subfamily_name')
|
|
|
|
|
|
class FontMetadata(object):
|
|
|
|
def __init__(self, bytes_or_stream):
|
|
if not hasattr(bytes_or_stream, 'read'):
|
|
bytes_or_stream = BytesIO(bytes_or_stream)
|
|
f = bytes_or_stream
|
|
f.seek(0)
|
|
header = f.read(4)
|
|
if header not in {b'\x00\x01\x00\x00', b'OTTO'}:
|
|
raise UnsupportedFont('Not a supported sfnt variant')
|
|
|
|
self.is_otf = header == b'OTTO'
|
|
self.read_table_metadata(f)
|
|
self.read_names(f)
|
|
self.read_characteristics(f)
|
|
|
|
f.seek(0)
|
|
self.font_family = self.names.family_name
|
|
wt = self.characteristics.weight
|
|
if wt == 400:
|
|
wt = 'normal'
|
|
elif wt == 700:
|
|
wt = 'bold'
|
|
else:
|
|
wt = unicode_type(wt)
|
|
self.font_weight = wt
|
|
|
|
self.font_stretch = ('ultra-condensed', 'extra-condensed',
|
|
'condensed', 'semi-condensed', 'normal', 'semi-expanded',
|
|
'expanded', 'extra-expanded', 'ultra-expanded')[
|
|
self.characteristics.width-1]
|
|
if self.characteristics.is_oblique:
|
|
self.font_style = 'oblique'
|
|
elif self.characteristics.is_italic:
|
|
self.font_style = 'italic'
|
|
else:
|
|
self.font_style = 'normal'
|
|
|
|
def read_table_metadata(self, f):
|
|
f.seek(4)
|
|
num_tables = unpack(b'>H', f.read(2))[0]
|
|
# Start of table record entries
|
|
f.seek(4 + 4*2)
|
|
table_record = b'>4s3L'
|
|
sz = calcsize(table_record)
|
|
self.tables = {}
|
|
block = f.read(sz * num_tables)
|
|
for i in range(num_tables):
|
|
table_tag, table_checksum, table_offset, table_length = \
|
|
unpack_from(table_record, block, i*sz)
|
|
self.tables[table_tag.lower()] = (table_offset, table_length,
|
|
table_checksum)
|
|
|
|
def read_names(self, f):
|
|
if b'name' not in self.tables:
|
|
raise UnsupportedFont('This font has no name table')
|
|
toff, tlen = self.tables[b'name'][:2]
|
|
f.seek(toff)
|
|
table = f.read(tlen)
|
|
if len(table) != tlen:
|
|
raise UnsupportedFont('This font has a name table of incorrect length')
|
|
vals = get_font_names2(table, raw_is_table=True)
|
|
self.names = FontNames(*vals)
|
|
|
|
def read_characteristics(self, f):
|
|
if b'os/2' not in self.tables:
|
|
raise UnsupportedFont('This font has no OS/2 table')
|
|
toff, tlen = self.tables[b'os/2'][:2]
|
|
f.seek(toff)
|
|
table = f.read(tlen)
|
|
if len(table) != tlen:
|
|
raise UnsupportedFont('This font has an OS/2 table of incorrect length')
|
|
vals = get_font_characteristics(table, raw_is_table=True)
|
|
self.characteristics = FontCharacteristics(*vals)
|
|
|
|
def to_dict(self):
|
|
ans = {
|
|
'is_otf':self.is_otf,
|
|
'font-family':self.font_family,
|
|
'font-weight':self.font_weight,
|
|
'font-style':self.font_style,
|
|
'font-stretch':self.font_stretch
|
|
}
|
|
for f in self.names._fields:
|
|
ans[f] = getattr(self.names, f)
|
|
for f in self.characteristics._fields:
|
|
ans[f] = getattr(self.characteristics, f)
|
|
return ans
|
|
|
|
|
|
if __name__ == '__main__':
|
|
import sys
|
|
with open(sys.argv[-1], 'rb') as f:
|
|
fm = FontMetadata(f)
|
|
import pprint
|
|
pprint.pprint(fm.to_dict())
|