From 76b3b6e20b2f7b66a5b7de16cee9a90423a225c0 Mon Sep 17 00:00:00 2001 From: Frank Sauerburger Date: Fri, 9 Jul 2021 15:56:25 +0200 Subject: [PATCH 1/2] Test for kerning in PDF output with type 42 font This commit adds an image comparison test to ensure that the text in a type 42 font has proper kerning in the PDF output. --- .../test_text/text_pdf_font42_kerning.pdf | Bin 0 -> 5364 bytes lib/matplotlib/tests/test_text.py | 7 +++++++ 2 files changed, 7 insertions(+) create mode 100644 lib/matplotlib/tests/baseline_images/test_text/text_pdf_font42_kerning.pdf 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 0000000000000000000000000000000000000000..a8ce9fca346c69d372dbbc0f2a0f4b60fdafa6da GIT binary patch literal 5364 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 Vgv?|wv>l^@QHDuNYn$l6{s+5*s~Z3S literal 0 HcmV?d00001 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) From 67aea087db15623c888e40b34d6b53b04872f51c Mon Sep 17 00:00:00 2001 From: Frank Sauerburger Date: Fri, 9 Jul 2021 16:27:36 +0200 Subject: [PATCH 2/2] 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. --- lib/matplotlib/backends/backend_pdf.py | 45 +++++++++++++++++--------- 1 file changed, 30 insertions(+), 15 deletions(-) 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: pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

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:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy