Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f4115cb

Browse files
committed
Add kerning to Type 3 font, ASCII strings in PDFs
1 parent 2e248f5 commit f4115cb

File tree

1 file changed

+51
-5
lines changed

1 file changed

+51
-5
lines changed

lib/matplotlib/backends/backend_pdf.py

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2253,6 +2253,40 @@ def encode_string(self, s, fonttype):
22532253
return s.encode('cp1252', 'replace')
22542254
return s.encode('utf-16be', 'replace')
22552255

2256+
def build_kern_sequence(self, string, font, fontsize,
2257+
kern_mode=KERNING_UNFITTED):
2258+
"""
2259+
Return an ordered sequence of contiguous substrings interspersed with
2260+
integer kerning offsets.
2261+
2262+
The return value is compatible with the PDF TJ operator.
2263+
"""
2264+
kern_sequence = [[]]
2265+
prev_glyph_idx = None
2266+
for char in string:
2267+
glyph_idx = font.get_char_index(ord(char))
2268+
2269+
# Absolute kerning in pt for actual font size
2270+
kern = (font.get_kerning(prev_glyph_idx, glyph_idx, kern_mode)
2271+
if prev_glyph_idx is not None else 0) / 64
2272+
2273+
# Transform to thousandths of a unit of PDF text space
2274+
kern *= 1000 / fontsize
2275+
2276+
if kern:
2277+
# Position of char must be adjusted
2278+
kern_sequence[-1] = "".join(kern_sequence[-1])
2279+
kern_sequence.append(-kern) # TJ operands are 'subtracted'
2280+
kern_sequence.append([char]) # Start new sequence
2281+
else:
2282+
# No kerning required, append to running sequence
2283+
kern_sequence[-1].append(char)
2284+
2285+
prev_glyph_idx = glyph_idx
2286+
2287+
return ["".join(subs) if isinstance(subs, list) else subs
2288+
for subs in kern_sequence]
2289+
22562290
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
22572291
# docstring inherited
22582292

@@ -2287,14 +2321,26 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
22872321
}
22882322
self.file._annotations[-1][1].append(link_annotation)
22892323

2290-
# If fonttype != 3 or there are no multibyte characters, emit the whole
2291-
# string at once.
2292-
if fonttype != 3 or all(ord(char) <= 255 for char in s):
2324+
# If fonttype != 3 emit the whole string at once.
2325+
if fonttype != 3:
2326+
self.file.output(Op.begin_text,
2327+
self.file.fontName(prop), fontsize, Op.selectfont)
2328+
self._setup_textpos(x, y, angle)
2329+
self.file.output(self.encode_string(s, fonttype),
2330+
Op.show, Op.end_text)
2331+
2332+
# If fonttype == 3 and there are no multibyte characters, emit the
2333+
# whole string with interspersed kerning info.
2334+
elif all(ord(char) <= 255 for char in s):
2335+
kern_sequence = self.build_kern_sequence(s, font, fontsize)
2336+
kern_s = [self.encode_string(subs, fonttype)
2337+
if isinstance(subs, str) else subs
2338+
for subs in kern_sequence]
2339+
22932340
self.file.output(Op.begin_text,
22942341
self.file.fontName(prop), fontsize, Op.selectfont)
22952342
self._setup_textpos(x, y, angle)
2296-
self.file.output(self.encode_string(s, fonttype), Op.show,
2297-
Op.end_text)
2343+
self.file.output(kern_s, Op.showkern, Op.end_text)
22982344

22992345
# There is no way to access multibyte characters of Type 3 fonts, as
23002346
# they cannot have a CIDMap. Therefore, in this case we break the

0 commit comments

Comments
 (0)