13
13
from struct import unpack_from, calcsize, pack
14
14
from collections import OrderedDict
16
from calibre.utils.fonts.utils import get_bmp_glyph_ids, read_bmp_prefix
16
from calibre.utils.fonts.utils import read_bmp_prefix
17
17
from calibre.utils.fonts.sfnt import UnknownTable, max_power_of_two
18
18
from calibre.utils.fonts.sfnt.errors import UnsupportedFont
120
class BMPTable(object):
122
def __init__(self, raw):
124
(self.start_count, self.end_count, self.range_offset, self.id_delta,
125
self.glyph_id_len, self.glyph_id_map, self.array_len) = \
126
read_bmp_prefix(raw, 0)
128
def get_glyph_ids(self, codes):
131
for i, ec in enumerate(self.end_count):
133
sc = self.start_count[i]
136
ro = self.range_offset[i]
138
glyph_id = self.id_delta[i] + code
140
idx = ro//2 + (code - sc) + i - self.array_len
141
glyph_id = self.glyph_id_map[idx]
143
glyph_id += self.id_delta[i]
144
yield glyph_id % 0x1000
149
def get_glyph_map(self, glyph_ids):
151
for i, ec in enumerate(self.end_count):
152
sc = self.start_count[i]
153
for code in xrange(sc, ec+1):
154
ro = self.range_offset[i]
156
glyph_id = self.id_delta[i] + code
158
idx = ro//2 + (code - sc) + i - self.array_len
159
glyph_id = self.glyph_id_map[idx]
161
glyph_id += self.id_delta[i]
163
if glyph_id in glyph_ids and code not in ans:
120
167
class CmapTable(UnknownTable):
122
169
def __init__(self, *args, **kwargs):
148
195
fmt = unpack_from(b'>H', table)[0]
149
196
if platform == 3 and encoding == 1 and fmt == 4:
150
self.bmp_table = table
197
self.bmp_table = BMPTable(table)
152
199
def get_character_map(self, chars):
159
206
chars = list(set(chars))
161
208
ans = OrderedDict()
162
for i, glyph_id in enumerate(get_bmp_glyph_ids(self.bmp_table, 0,
209
for i, glyph_id in enumerate(self.bmp_table.get_glyph_ids(chars)):
165
211
ans[chars[i]] = glyph_id
168
def get_char_codes(self, glyph_ids):
214
def get_glyph_map(self, glyph_ids):
216
Get a mapping of character codes to glyph ids for the specified glyph
169
219
if self.bmp_table is None:
170
220
raise UnsupportedFont('This font has no Windows BMP cmap subtable.'
171
221
' Most likely a special purpose font.')
173
(start_count, end_count, range_offset, id_delta, glyph_id_len,
174
glyph_id_map, array_len) = read_bmp_prefix(self.bmp_table, 0)
176
222
glyph_ids = frozenset(glyph_ids)
178
for i, ec in enumerate(end_count):
181
for code in xrange(sc, ec+1):
183
glyph_id = id_delta[i] + code
185
idx = ro//2 + (code - sc) + i - array_len
186
glyph_id = glyph_id_map[idx]
188
glyph_id += id_delta[i]
190
if glyph_id in glyph_ids:
223
return self.bmp_table.get_glyph_map(glyph_ids)
195
225
def set_character_map(self, cmap):
196
226
self.version, self.num_tables = 0, 1