diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index 10063bd9a7b3..d4cde3155af4 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -2236,6 +2236,20 @@ def encode_string(self, s, fonttype): return s.encode('cp1252', 'replace') return s.encode('utf-16be', 'replace') + @staticmethod + def _font_supports_char(fonttype, char): + """ + Returns True if the font is able to provided the char in a PDF + + For a Type 3 font, this method returns True only for single-byte + chars. For Type 42 fonts this method always returns True. + """ + if fonttype == 3: + return ord(char) <= 255 + if fonttype == 42: + return True + raise NotImplementedError() + def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): # docstring inherited @@ -2270,26 +2284,27 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): } self.file._annotations[-1][1].append(link_annotation) - # If fonttype != 3 emit the whole string at once without manual - # kerning. - if fonttype != 3: + # If fonttype is neither 3 nor 42, emit the whole string at once + # without manual kerning. + if fonttype not in [3, 42]: self.file.output(Op.begin_text, self.file.fontName(prop), fontsize, Op.selectfont) self._setup_textpos(x, y, angle) self.file.output(self.encode_string(s, fonttype), Op.show, Op.end_text) - # There is no way to access multibyte characters of Type 3 fonts, as - # they cannot have a CIDMap. Therefore, in this case we break the - # string into chunks, where each chunk contains either a string of - # consecutive 1-byte characters or a single multibyte character. - # A sequence of 1-byte characters is broken into multiple chunks to - # adjust the kerning between adjacent chunks. Each chunk is emitted - # with a separate command: 1-byte characters use the regular text show - # command (TJ) with appropriate kerning between chunks, whereas - # multibyte characters use the XObject command (Do). (If using Type - # 42 fonts, all of this complication is avoided, but of course, - # subsetting those fonts is complex/hard to implement.) + # A sequence of characters is broken into multiple chunks. The chunking + # serves two purposes: + # - For Type 3 fonts, there is no way to access multibyte characters, + # as they cannot have a CIDMap. Therefore, in this case we break + # the string into chunks, where each chunk contains either a string + # of consecutive 1-byte characters or a single multibyte character. + # - A sequence of 1-byte characters is split into chunks to allow for + # kerning adjustments between consecutive chunks. + # + # Each chunk is emitted with a separate command: 1-byte characters use + # the regular text show command (TJ) with appropriate kerning between + # chunks, whereas multibyte characters use the XObject command (Do). else: # List of (start_x, [prev_kern, char, char, ...]), w/o zero kerns. singlebyte_chunks = [] @@ -2298,7 +2313,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): prev_was_multibyte = True for item in _text_helpers.layout( s, font, kern_mode=KERNING_UNFITTED): - if ord(item.char) <= 255: + if self._font_supports_char(fonttype, item.char): if prev_was_multibyte: singlebyte_chunks.append((item.x, [])) if item.prev_kern: diff --git a/lib/matplotlib/tests/baseline_images/test_text/text_pdf_font42_kerning.pdf b/lib/matplotlib/tests/baseline_images/test_text/text_pdf_font42_kerning.pdf new file mode 100644 index 000000000000..a8ce9fca346c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/text_pdf_font42_kerning.pdf differ diff --git a/lib/matplotlib/tests/test_text.py b/lib/matplotlib/tests/test_text.py index abefe3c3ab04..8c575a7be1a6 100644 --- a/lib/matplotlib/tests/test_text.py +++ b/lib/matplotlib/tests/test_text.py @@ -741,3 +741,10 @@ def test_parse_math(): ax.text(0, 0, r"$ \wrong{math} $", parse_math=True) with pytest.raises(ValueError, match='Unknown symbol'): fig.canvas.draw() + + +@image_comparison(['text_pdf_font42_kerning.pdf'], style='mpl20') +def test_pdf_font42_kerning(): + plt.rcParams['pdf.fonttype'] = 42 + plt.figure() + plt.figtext(0.1, 0.5, "ATAVATAVATAVATAVATA", size=30)
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: