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

Skip to content

Commit bb6b76b

Browse files
committed
Emit Type 42 text with TJ and kerning in PDF
The commit applies the same kerning algorithm used for Type 3 fonts also to Type 42 fonts. A string is split into chunks with kerning between the chunks.
1 parent 76b3b6e commit bb6b76b

File tree

1 file changed

+28
-15
lines changed

1 file changed

+28
-15
lines changed

lib/matplotlib/backends/backend_pdf.py

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2236,6 +2236,18 @@ def encode_string(self, s, fonttype):
22362236
return s.encode('cp1252', 'replace')
22372237
return s.encode('utf-16be', 'replace')
22382238

2239+
@staticmethod
2240+
def _font_supports_char(fonttype, char):
2241+
"""
2242+
Returns True if the font is able to provided the char in a PDF
2243+
2244+
For a Type 3 font, this method returns True only for single-byte
2245+
chars. For Type 42 fonts this method always returns True.
2246+
"""
2247+
if fonttype == 3 and ord(char) <= 255:
2248+
return True
2249+
return True
2250+
22392251
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
22402252
# docstring inherited
22412253

@@ -2270,26 +2282,27 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
22702282
}
22712283
self.file._annotations[-1][1].append(link_annotation)
22722284

2273-
# If fonttype != 3 emit the whole string at once without manual
2274-
# kerning.
2275-
if fonttype != 3:
2285+
# If fonttype is neither 3 nor 42, emit the whole string at once
2286+
# without manual kerning.
2287+
if fonttype not in [3, 42]:
22762288
self.file.output(Op.begin_text,
22772289
self.file.fontName(prop), fontsize, Op.selectfont)
22782290
self._setup_textpos(x, y, angle)
22792291
self.file.output(self.encode_string(s, fonttype),
22802292
Op.show, Op.end_text)
22812293

2282-
# There is no way to access multibyte characters of Type 3 fonts, as
2283-
# they cannot have a CIDMap. Therefore, in this case we break the
2284-
# string into chunks, where each chunk contains either a string of
2285-
# consecutive 1-byte characters or a single multibyte character.
2286-
# A sequence of 1-byte characters is broken into multiple chunks to
2287-
# adjust the kerning between adjacent chunks. Each chunk is emitted
2288-
# with a separate command: 1-byte characters use the regular text show
2289-
# command (TJ) with appropriate kerning between chunks, whereas
2290-
# multibyte characters use the XObject command (Do). (If using Type
2291-
# 42 fonts, all of this complication is avoided, but of course,
2292-
# subsetting those fonts is complex/hard to implement.)
2294+
# A sequence of characters is broken into multiple chunks. The chunking
2295+
# serves two purposes:
2296+
# - For Type 3 fonts, there is no way to access multibyte characters,
2297+
# as they cannot have a CIDMap. Therefore, in this case we break
2298+
# the string into chunks, where each chunk contains either a string
2299+
# of consecutive 1-byte characters or a single multibyte character.
2300+
# - A sequence of 1-byte characters is split into chunks to allow for
2301+
# kerning adjustments between consecutive chunks.
2302+
#
2303+
# Each chunk is emitted with a separate command: 1-byte characters use
2304+
# the regular text show command (TJ) with appropriate kerning between
2305+
# chunks, whereas multibyte characters use the XObject command (Do).
22932306
else:
22942307
# List of (start_x, [prev_kern, char, char, ...]), w/o zero kerns.
22952308
singlebyte_chunks = []
@@ -2298,7 +2311,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
22982311
prev_was_multibyte = True
22992312
for item in _text_helpers.layout(
23002313
s, font, kern_mode=KERNING_UNFITTED):
2301-
if ord(item.char) <= 255:
2314+
if self._font_supports_char(fonttype, item.char):
23022315
if prev_was_multibyte:
23032316
singlebyte_chunks.append((item.x, []))
23042317
if item.prev_kern:

0 commit comments

Comments
 (0)