def restrict_format_0(self, raw, glyph_ids): if self._version == 0: version, length, coverage, npairs = unpack_from(b'>4H', raw) headerfmt = b'>3H' else: length, coverage, tuple_index, npairs = unpack_from(b'>L3H', raw) headerfmt = b'>L2H' offset = calcsize(headerfmt + b'4H') entries = [] entrysz = calcsize(b'>2Hh') for i in xrange(npairs): try: left, right, value = unpack_from(b'>2Hh', raw, offset) except struct_error: offset = len(raw) break # Buggy kern table if left in glyph_ids and right in glyph_ids: entries.append(pack(b'>2Hh', left, right, value)) offset += entrysz if offset != len(raw): raise UnsupportedFont('This font has extra data at the end of' ' a Format 0 kern subtable') npairs = len(entries) if npairs == 0: return b'' entry_selector = max_power_of_two(npairs) search_range = (2 ** entry_selector) * 6 range_shift = (npairs - (2 ** entry_selector)) * 6
def set_character_map(self, cmap): self.version, self.num_tables = 0, 1 fmt = b'>7H' codes = list(cmap.iterkeys()) codes.sort() if not codes: start_code = [0xffff] end_code = [0xffff] else: last_code = codes[0] end_code = [] start_code = [last_code] for code in codes[1:]: if code == last_code + 1: last_code = code continue start, end = split_range(start_code[-1], last_code, cmap) start_code.extend(start) end_code.extend(end) start_code.append(code) last_code = code end_code.append(last_code) start_code.append(0xffff) end_code.append(0xffff) id_delta = [] id_range_offset = [] glyph_index_array = [] for i in xrange(len(end_code)-1): # skip the closing codes (0xffff) indices = [] for char_code in xrange(start_code[i], end_code[i] + 1): indices.append(cmap[char_code]) if (indices == xrange(indices[0], indices[0] + len(indices))): id_delta_temp = set_id_delta(indices[0] - start_code[i]) id_delta.append(id_delta_temp) id_range_offset.append(0) else: id_delta.append(0) id_range_offset.append(2 * (len(end_code) + len(glyph_index_array) - i)) glyph_index_array.extend(indices) id_delta.append(1) # 0xffff + 1 == 0. So this end code maps to .notdef id_range_offset.append(0) seg_count = len(end_code) max_exponent = max_power_of_two(seg_count) search_range = 2 * (2 ** max_exponent) entry_selector = max_exponent range_shift = 2 * seg_count - search_range
def __call__(self, stream=None): stream = BytesIO() if stream is None else stream def spack(*args): stream.write(pack(*args)) stream.seek(0) # Write header num_tables = len(self.tables) ln2 = max_power_of_two(num_tables) srange = (2**ln2) * 16 spack(b'>4s4H', self.sfnt_version, num_tables, srange, ln2, num_tables * 16 - srange) # Write tables head_offset = None table_data = [] offset = stream.tell() + (calcsize(b'>4s3L') * num_tables) sizes = OrderedDict() for tag in self: table = self.tables[tag] raw = table() table_len = len(raw) if tag == b'head': head_offset = offset raw = raw[:8] + b'\0\0\0\0' + raw[12:] raw = align_block(raw) checksum = checksum_of_block(raw) spack(b'>4s3L', tag, checksum, offset, table_len) offset += len(raw) table_data.append(raw) sizes[tag] = table_len for x in table_data: stream.write(x) checksum = checksum_of_block(stream.getvalue()) q = (0xB1B0AFBA - checksum) & 0xffffffff stream.seek(head_offset + 8) spack(b'>L', q) return stream.getvalue(), sizes
def restrict_format_0(self, raw, glyph_ids): if self._version == 0: version, length, coverage, npairs = unpack_from(b'>4H', raw) headerfmt = b'>3H' else: length, coverage, tuple_index, npairs = unpack_from(b'>L3H', raw) headerfmt = b'>L2H' offset = calcsize(headerfmt + b'4H') entries = [] entrysz = calcsize(b'>2Hh') for i in range(npairs): try: left, right, value = unpack_from(b'>2Hh', raw, offset) except struct_error: offset = len(raw) break # Buggy kern table if left in glyph_ids and right in glyph_ids: entries.append(pack(b'>2Hh', left, right, value)) offset += entrysz if offset != len(raw): raise UnsupportedFont('This font has extra data at the end of' ' a Format 0 kern subtable') npairs = len(entries) if npairs == 0: return b'' entry_selector = max_power_of_two(npairs) search_range = (2**entry_selector) * 6 range_shift = (npairs - (2**entry_selector)) * 6 entries = b''.join(entries) length = calcsize(headerfmt + b'4H') + len(entries) if self._version == 0: header = pack(headerfmt, version, length, coverage) else: header = pack(headerfmt, length, coverage, tuple_index) return header + pack(b'>4H', npairs, search_range, entry_selector, range_shift) + entries
def set_character_map(self, cmap): self.version, self.num_tables = 0, 1 fmt = b'>7H' codes = list(cmap.iterkeys()) codes.sort() if not codes: start_code = [0xffff] end_code = [0xffff] else: last_code = codes[0] end_code = [] start_code = [last_code] for code in codes[1:]: if code == last_code + 1: last_code = code continue start, end = split_range(start_code[-1], last_code, cmap) start_code.extend(start) end_code.extend(end) start_code.append(code) last_code = code end_code.append(last_code) start_code.append(0xffff) end_code.append(0xffff) id_delta = [] id_range_offset = [] glyph_index_array = [] for i in xrange(len(end_code) - 1): # skip the closing codes (0xffff) indices = list(cmap[char_code] for char_code in xrange(start_code[i], end_code[i] + 1)) if indices == list(xrange(indices[0], indices[0] + len(indices))): # indices is a contiguous list id_delta_temp = set_id_delta(indices[0] - start_code[i]) id_delta.append(id_delta_temp) id_range_offset.append(0) else: id_delta.append(0) id_range_offset.append( 2 * (len(end_code) + len(glyph_index_array) - i)) glyph_index_array.extend(indices) id_delta.append(1) # 0xffff + 1 == 0. So this end code maps to .notdef id_range_offset.append(0) seg_count = len(end_code) max_exponent = max_power_of_two(seg_count) search_range = 2 * (2**max_exponent) entry_selector = max_exponent range_shift = 2 * seg_count - search_range char_code_array = end_code + [0] + start_code char_code_array = pack(b'>%dH' % len(char_code_array), *char_code_array) id_delta_array = pack(b'>%dh' % len(id_delta), *id_delta) rest_array = id_range_offset + glyph_index_array rest_array = pack(b'>%dH' % len(rest_array), *rest_array) data = char_code_array + id_delta_array + rest_array length = calcsize(fmt) + len(data) header = pack(fmt, 4, length, 0, 2 * seg_count, search_range, entry_selector, range_shift) self.bmp_table = header + data fmt = b'>4HL' offset = calcsize(fmt) self.raw = pack(fmt, self.version, self.num_tables, 3, 1, offset) + self.bmp_table
def set_character_map(self, cmap): self.version, self.num_tables = 0, 1 fmt = b'>7H' codes = sorted(cmap) if not codes: start_code = [0xffff] end_code = [0xffff] else: last_code = codes[0] end_code = [] start_code = [last_code] for code in codes[1:]: if code == last_code + 1: last_code = code continue start, end = split_range(start_code[-1], last_code, cmap) start_code.extend(start) end_code.extend(end) start_code.append(code) last_code = code end_code.append(last_code) start_code.append(0xffff) end_code.append(0xffff) id_delta = [] id_range_offset = [] glyph_index_array = [] for i in range(len(end_code)-1): # skip the closing codes (0xffff) indices = list(cmap[char_code] for char_code in range(start_code[i], end_code[i] + 1)) if indices == list(range(indices[0], indices[0] + len(indices))): # indices is a contiguous list id_delta_temp = set_id_delta(indices[0] - start_code[i]) id_delta.append(id_delta_temp) id_range_offset.append(0) else: id_delta.append(0) id_range_offset.append(2 * (len(end_code) + len(glyph_index_array) - i)) glyph_index_array.extend(indices) id_delta.append(1) # 0xffff + 1 == 0. So this end code maps to .notdef id_range_offset.append(0) seg_count = len(end_code) max_exponent = max_power_of_two(seg_count) search_range = 2 * (2 ** max_exponent) entry_selector = max_exponent range_shift = 2 * seg_count - search_range char_code_array = end_code + [0] + start_code char_code_array = pack(b'>%dH'%len(char_code_array), *char_code_array) id_delta_array = pack(b'>%dh'%len(id_delta), *id_delta) rest_array = id_range_offset + glyph_index_array rest_array = pack(b'>%dH'%len(rest_array), *rest_array) data = char_code_array + id_delta_array + rest_array length = calcsize(fmt) + len(data) header = pack(fmt, 4, length, 0, 2*seg_count, search_range, entry_selector, range_shift) self.bmp_table = header + data fmt = b'>4HL' offset = calcsize(fmt) self.raw = pack(fmt, self.version, self.num_tables, 3, 1, offset) + self.bmp_table