%PDF- %PDF-
| Direktori : /usr/lib/calibre/calibre/utils/fonts/sfnt/ |
| Current File : //usr/lib/calibre/calibre/utils/fonts/sfnt/head.py |
#!/usr/bin/env python3
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import array
from struct import unpack_from, pack, calcsize
from calibre.utils.fonts.sfnt import UnknownTable, DateTimeProperty, FixedProperty
from calibre.utils.fonts.sfnt.errors import UnsupportedFont
from calibre.utils.fonts.sfnt.loca import read_array
class HeadTable(UnknownTable):
created = DateTimeProperty('_created')
modified = DateTimeProperty('_modified')
version_number = FixedProperty('_version_number')
font_revision = FixedProperty('_font_revision')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
field_types = (
'_version_number' , 'l',
'_font_revision' , 'l',
'checksum_adjustment' , 'L',
'magic_number' , 'L',
'flags' , 'H',
'units_per_em' , 'H',
'_created' , 'q',
'_modified' , 'q',
'x_min' , 'h',
'y_min' , 'h',
'x_max' , 'h',
'y_max' , 'h',
'mac_style' , 'H',
'lowest_rec_ppem' , 'H',
'font_direction_hint' , 'h',
'index_to_loc_format' , 'h',
'glyph_data_format' , 'h'
)
self._fmt = ('>%s'%(''.join(field_types[1::2]))).encode('ascii')
self._fields = field_types[0::2]
for f, val in zip(self._fields, unpack_from(self._fmt, self.raw)):
setattr(self, f, val)
def update(self):
vals = [getattr(self, f) for f in self._fields]
self.raw = pack(self._fmt, *vals)
def read_metrics(raw, num_of_metrics, num_of_glyphs, table_name):
rawsz = 4 * num_of_metrics
if len(raw) < rawsz:
raise UnsupportedFont(f'The {table_name} table has insufficient data')
long_hor_metric = raw[:rawsz]
a = read_array(long_hor_metric)
advances = a[0::2]
a = read_array(long_hor_metric, 'h')
bearings = a[1::2]
if num_of_glyphs > num_of_metrics:
extra = num_of_glyphs - num_of_metrics
raw = raw[rawsz:]
rawsz = 2 * extra
if len(raw) < rawsz:
raise UnsupportedFont(f'The {table_name} table has insufficient data for trailing bearings')
bearings += read_array(raw, 'h')
return advances, bearings
def update_metrics_table(metrics_map, mtx_table):
recs, aw, b = [], array.array('H'), array.array('h')
for glyph_id in sorted(metrics_map):
adv, bearing = metrics_map[glyph_id]
aw.append(adv)
b.append(bearing)
recs.append(pack('>Hh', adv, bearing))
mtx_table.raw = b''.join(recs)
return aw, b
class HorizontalHeader(UnknownTable):
version_number = FixedProperty('_version_number')
field_types = (
'_version_number' , 'l',
'ascender', 'h',
'descender', 'h',
'line_gap', 'h',
'advance_width_max', 'H',
'min_left_side_bearing', 'h',
'min_right_side_bearing', 'h',
'x_max_extent', 'h',
'caret_slope_rise', 'h',
'caret_slop_run', 'h',
'caret_offset', 'h',
'r1', 'h',
'r2', 'h',
'r3', 'h',
'r4', 'h',
'metric_data_format', 'h',
'number_of_h_metrics', 'H',
)
def read_data(self, hmtx, num_glyphs):
self._fmt = ('>%s'%(''.join(self.field_types[1::2]))).encode('ascii')
self._fields = self.field_types[0::2]
for f, val in zip(self._fields, unpack_from(self._fmt, self.raw)):
setattr(self, f, val)
self.advance_widths, self.left_side_bearings = read_metrics(hmtx.raw, self.number_of_h_metrics, num_glyphs, 'hmtx')
def metrics_for(self, glyph_id):
lsb = self.left_side_bearings[glyph_id]
if glyph_id >= len(self.advance_widths):
glyph_id = -1
return self.advance_widths[glyph_id], lsb
def update(self, metrics_map, mtx_table):
aw, b = update_metrics_table(metrics_map, mtx_table)
self.advance_widths = aw
self.left_side_bearings = b
self.number_of_h_metrics = len(metrics_map)
self.advance_width_max = max(aw or (0,))
self.min_left_side_bearing = min(b or (0,))
data = (getattr(self, x) for x in self._fields)
self.raw = pack('>' + ''.join(self.field_types[1::2]), *data)
class VerticalHeader(UnknownTable):
version_number = FixedProperty('_version_number')
field_types = (
'_version_number' , 'l',
'ascender', 'h',
'descender', 'h',
'line_gap', 'h',
'advance_height_max', 'H',
'min_top_side_bearing', 'h',
'min_bottom_side_bearing', 'h',
'y_max_extent', 'h',
'caret_slope_rise', 'h',
'caret_slop_run', 'h',
'caret_offset', 'h',
'r1', 'h',
'r2', 'h',
'r3', 'h',
'r4', 'h',
'metric_data_format', 'h',
'number_of_v_metrics', 'H',
)
def read_data(self, vmtx, num_glyphs):
self._fmt = ('>%s'%(''.join(self.field_types[1::2]))).encode('ascii')
self._fields = self.field_types[0::2]
for f, val in zip(self._fields, unpack_from(self._fmt, self.raw)):
setattr(self, f, val)
self.advance_heights, self.top_side_bearings = read_metrics(vmtx.raw, self.number_of_v_metrics, num_glyphs, 'vmtx')
def metrics_for(self, glyph_id):
tsb = self.top_side_bearings[glyph_id]
if glyph_id >= len(self.advance_heights):
glyph_id = -1
return self.advance_heights[glyph_id], tsb
def update(self, metrics_map, mtx_table):
aw, b = update_metrics_table(metrics_map, mtx_table)
self.advance_heights = aw
self.top_side_bearings = b
self.number_of_v_metrics = len(metrics_map)
self.advance_height_max = max(aw or (0,))
self.min_top_side_bearing = min(b or (0,))
data = (getattr(self, x) for x in self._fields)
self.raw = pack('>' + ''.join(self.field_types[1::2]), *data)
class OS2Table(UnknownTable):
def read_data(self):
if hasattr(self, 'char_width'):
return
ver, = unpack_from(b'>H', self.raw)
field_types = [
'version' , 'H',
'average_char_width', 'h',
'weight_class', 'H',
'width_class', 'H',
'fs_type', 'H',
'subscript_x_size', 'h',
'subscript_y_size', 'h',
'subscript_x_offset', 'h',
'subscript_y_offset', 'h',
'superscript_x_size', 'h',
'superscript_y_size', 'h',
'superscript_x_offset', 'h',
'superscript_y_offset', 'h',
'strikeout_size', 'h',
'strikeout_position', 'h',
'family_class', 'h',
'panose', '10s',
'ranges', '16s',
'vendor_id', '4s',
'selection', 'H',
'first_char_index', 'H',
'last_char_index', 'H',
'typo_ascender', 'h',
'typo_descender', 'h',
'typo_line_gap', 'h',
'win_ascent', 'H',
'win_descent', 'H',
]
if ver > 1:
field_types += [
'code_page_range', '8s',
'x_height', 'h',
'cap_height', 'h',
'default_char', 'H',
'break_char', 'H',
'max_context', 'H',
]
self._fmt = ('>%s'%(''.join(field_types[1::2]))).encode('ascii')
self._fields = field_types[0::2]
for f, val in zip(self._fields, unpack_from(self._fmt, self.raw)):
setattr(self, f, val)
def zero_fstype(self):
prefix = calcsize(b'>HhHH')
self.raw = self.raw[:prefix] + b'\0\0' + self.raw[prefix+2:]
self.fs_type = 0
class PostTable(UnknownTable):
version_number = FixedProperty('_version')
italic_angle = FixedProperty('_italic_angle')
def read_data(self):
if hasattr(self, 'underline_position'):
return
(self._version, self._italic_angle, self.underline_position,
self.underline_thickness) = unpack_from(b'>llhh', self.raw)