diff --git a/CHANGELOG.md b/CHANGELOG.md index b1e19d0f5..117adf5b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and [PEP 440](https://www.python.org/dev/peps/pep-0440/). ### Changed - `image()` method now insert `.svg` images as PDF paths +- the [defusedxml](https://pypi.org/project/defusedxml/) package was added as dependency in order to make SVG parsing safer - log level of `_substitute_page_number()` has been lowered from `INFO` to `DEBUG` ### Fixed @@ -22,6 +23,13 @@ and [PEP 440](https://www.python.org/dev/peps/pep-0440/). resulting in calls to `cell()` / `multi_cell()` with `align="R"` to display nothing - thanks @mcerveny for the fix! - a bug with incorrect width calculation of markdown text +### Deprecated +- the font caching mechanism, that used the `pickle` module, has been removed, for security reasons, + and because it provided little performance, and only for specific use cases - _cf._ [issue #345](https://github.com/PyFPDF/fpdf2/issues/345). + That means that the `font_cache_dir` optional paramater of `fpdf.FPDF` + and the `uni` optional paramater of `FPDF.add_font` are deprecated. + The `fpdf.fpdf.load_cache` function has also been removed. + ## [2.5.0] - 2022-01-22 ### Added Thanks to @torque for contributing this massive new feature: diff --git a/README.md b/README.md index 7f9e4c16d..f632bfffd 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Pypi latest version](https://img.shields.io/pypi/v/fpdf2.svg)](https://pypi.python.org/pypi/fpdf2) [![License: LGPL v3](https://img.shields.io/badge/License-LGPL%20v3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0) [![codecov](https://codecov.io/gh/PyFPDF/fpdf2/branch/master/graph/badge.svg)](https://codecov.io/gh/PyFPDF/fpdf2) +[![security: bandit](https://img.shields.io/badge/security-bandit-yellow.svg)](https://github.com/PyCQA/bandit) [![Downloads per month](https://pepy.tech/badge/fpdf2/month)](https://pepy.tech/project/fpdf2) [![Discussions](https://img.shields.io/github/discussions/PyFPDF/fpdf2)](https://github.com/PyFPDF/fpdf2/discussions) diff --git a/docs/EmojisSymbolsDingbats.md b/docs/EmojisSymbolsDingbats.md index ef1cb36cc..c013b106d 100644 --- a/docs/EmojisSymbolsDingbats.md +++ b/docs/EmojisSymbolsDingbats.md @@ -11,7 +11,7 @@ Here is an example using the [DejaVu](https://dejavu-fonts.github.io) font: import fpdf pdf = fpdf.FPDF() -pdf.add_font("DejaVuSans", fname="DejaVuSans.ttf", uni=True) +pdf.add_font("DejaVuSans", fname="DejaVuSans.ttf") pdf.set_font("DejaVuSans", size=64) pdf.add_page() pdf.multi_cell(0, txt="".join([chr(0x1F600 + x) for x in range(68)])) diff --git a/docs/Unicode.md b/docs/Unicode.md index 129cd17ad..762d22528 100644 --- a/docs/Unicode.md +++ b/docs/Unicode.md @@ -59,7 +59,7 @@ pdf.add_page() # Add a DejaVu Unicode font (uses UTF-8) # Supports more than 200 languages. For a coverage status see: # http://dejavu.svn.sourceforge.net/viewvc/dejavu/trunk/dejavu-fonts/langcover.txt -pdf.add_font('DejaVu', fname='DejaVuSansCondensed.ttf', uni=True) +pdf.add_font('DejaVu', fname='DejaVuSansCondensed.ttf') pdf.set_font('DejaVu', size=14) text = u""" @@ -81,14 +81,14 @@ for txt in text.split('\n'): # Supports: Bengali, Devanagari, Gujarati, # Gurmukhi (including the variants for Punjabi) # Kannada, Malayalam, Oriya, Tamil, Telugu, Tibetan -pdf.add_font('gargi', fname='gargi.ttf', uni=True) +pdf.add_font('gargi', fname='gargi.ttf') pdf.set_font('gargi', size=14) pdf.write(8, u'Hindi: नमस्ते दुनिया') pdf.ln(20) # Add a AR PL New Sung Unicode font (uses UTF-8) # The Open Source Chinese Font (also supports other east Asian languages) -pdf.add_font('fireflysung', fname='fireflysung.ttf', uni=True) +pdf.add_font('fireflysung', fname='fireflysung.ttf') pdf.set_font('fireflysung', size=14) pdf.write(8, u'Chinese: 你好世界\n') pdf.write(8, u'Japanese: こんにちは世界\n') @@ -97,13 +97,13 @@ pdf.ln(10) # Add a Alee Unicode font (uses UTF-8) # General purpose Hangul truetype fonts that contain Korean syllable # and Latin9 (iso8859-15) characters. -pdf.add_font('eunjin', fname='Eunjin.ttf', uni=True) +pdf.add_font('eunjin', fname='Eunjin.ttf') pdf.set_font('eunjin', size=14) pdf.write(8, u'Korean: 안녕하세요') pdf.ln(20) # Add a Fonts-TLWG (formerly ThaiFonts-Scalable) (uses UTF-8) -pdf.add_font('waree', fname='Waree.ttf', uni=True) +pdf.add_font('waree', fname='Waree.ttf') pdf.set_font('waree', size=14) pdf.write(8, u'Thai: สวัสดีชาวโลก') pdf.ln(20) diff --git a/fpdf/fpdf.py b/fpdf/fpdf.py index 45b3a1620..ef405b925 100644 --- a/fpdf/fpdf.py +++ b/fpdf/fpdf.py @@ -14,7 +14,6 @@ The version number is updated here (above and below in variable). """ -import errno import hashlib import io import logging @@ -202,17 +201,6 @@ def get_page_format(format, k=None): raise FPDFPageFormatException(f"Arguments must be numbers: {args}") from e -def load_cache(filename: Path): - """Return unpickled object, or None if cache unavailable""" - if not filename: - return None - try: - return pickle.loads(filename.read_bytes()) - # File missing, unsupported pickle, etc - except (OSError, ValueError): - return None - - def check_page(fn): """Decorator to protect drawing methods""" @@ -232,7 +220,11 @@ class FPDF(GraphicsStateMixin): MARKDOWN_UNDERLINE_MARKER = "--" def __init__( - self, orientation="portrait", unit="mm", format="A4", font_cache_dir=True + self, + orientation="portrait", + unit="mm", + format="A4", + font_cache_dir="DEPRECATED", ): """ Args: @@ -245,11 +237,13 @@ def __init__( Default to "mm". format (str): possible values are "a3", "a4", "a5", "letter", "legal" or a tuple (width, height) expressed in the given unit. Default to "a4". - font_cache_dir (Path or str): directory where pickle files - for TTF font files are kept. - `None` disables font chaching. - The default is `True`, meaning the current folder. + font_cache_dir (Path or str): [**DEPRECATED**] unused """ + if font_cache_dir != "DEPRECATED": + warnings.warn( + '"font_cache_dir" parameter is deprecated, unused and will soon be removed', + PendingDeprecationWarning, + ) super().__init__() # Initialization of instance attributes self.offsets = {} # array of object offsets @@ -272,7 +266,6 @@ def __init__( self.ws = 0 # word spacing self.angle = 0 # used by deprecated method: rotate() - self.font_cache_dir = font_cache_dir self.xmp_metadata = None self.image_filter = "AUTO" self.page_duration = 0 # optional pages display duration, cf. add_page() @@ -1428,13 +1421,13 @@ def solid_arc( style, ) - def add_font(self, family, style="", fname=None, uni=False): + def add_font(self, family, style="", fname=None, uni="DEPRECATED"): """ - Imports a TrueType, OpenType or Type1 font and makes it available + Imports a TrueType or OpenType font and makes it available for later calls to the `set_font()` method. - **Warning:** for Type1 and legacy fonts it is necessary to generate a font definition file first with the `MakeFont` utility. - This feature is currently deprecated in favour of TrueType Unicode font support + **Warning:** there is partial support for Type1 and legacy fonts in .pkl font definition files, + generated by the `MakeFont` utility, but this feature is getting deprecated in favour of TrueType Unicode font support (whose fonts are automatically processed with the included `ttfonts.py` module). You will find more information on the "Unicode" documentation page. @@ -1444,17 +1437,13 @@ def add_font(self, family, style="", fname=None, uni=False): style (str): font style. "B" for bold, "I" for italic. fname (str): font file name. You can specify a relative or full path. If the file is not found, it will be searched in `FPDF_FONT_DIR`. - uni (bool): if set to `True`, enable TrueType font subset embedding. - Text will then be treated as `utf8` by default. - Calling this method with uni=False is discouraged as legacy font support is complex and deprecated. - - Notes - ----- - - Due to the fact that font processing can occupy large amount of time, some data is cached. - Cache files are created in the current folder by default. - This can be controlled with the `font_cache_dir` paramater of the `FPDF` constructor. + uni (bool): [**DEPRECATED**] unused """ + if uni != "DEPRECATED": + warnings.warn( + '"uni" parameter is deprecated, unused and will soon be removed', + PendingDeprecationWarning, + ) if not fname: fname = family.replace(" ", "") + f"{style.lower()}.pkl" style = "".join(sorted(style.upper())) @@ -1468,7 +1457,7 @@ def add_font(self, family, style="", fname=None, uni=False): if fontkey in self.fonts or fontkey in self.core_fonts: warnings.warn(f"Core font or font already added '{fontkey}': doing nothing") return - if uni: + if str(fname).endswith(".ttf"): for parent in (".", FPDF_FONT_DIR): if not parent: continue @@ -1478,14 +1467,6 @@ def add_font(self, family, style="", fname=None, uni=False): else: raise FileNotFoundError(f"TTF Font file not found: {fname}") - if self.font_cache_dir is None: - cache_dir = unifilename = None - else: - cache_dir = ( - Path() if self.font_cache_dir is True else Path(self.font_cache_dir) - ) - unifilename = cache_dir / f"{ttffilename.stem}.pkl" - # include numbers in the subset! (if alias present) # ensure that alias is mapped 1-by-1 additionally (must be replaceable) sbarr = "\x00 " @@ -1493,44 +1474,34 @@ def add_font(self, family, style="", fname=None, uni=False): sbarr += "0123456789" sbarr += self.str_alias_nb_pages - font_dict = load_cache(unifilename) - if font_dict is None: - ttf = TTFontFile() - ttf.getMetrics(ttffilename) - desc = { - "Ascent": round(ttf.ascent), - "Descent": round(ttf.descent), - "CapHeight": round(ttf.capHeight), - "Flags": ttf.flags, - "FontBBox": ( - f"[{ttf.bbox[0]:.0f} {ttf.bbox[1]:.0f}" - f" {ttf.bbox[2]:.0f} {ttf.bbox[3]:.0f}]" - ), - "ItalicAngle": int(ttf.italicAngle), - "StemV": round(ttf.stemV), - "MissingWidth": round(ttf.defaultWidth), - } - - # Generate metrics .pkl file - font_dict = { - "type": "TTF", - "name": re.sub("[ ()]", "", ttf.fullName), - "desc": desc, - "up": round(ttf.underlinePosition), - "ut": round(ttf.underlineThickness), - "ttffile": ttffilename, - "fontkey": fontkey, - "unifilename": unifilename, - "originalsize": os.stat(ttffilename).st_size, - "cw": ttf.charWidths, - } - - if unifilename: - try: - unifilename.write_bytes(pickle.dumps(font_dict)) - except OSError as e: - if e.errno != errno.EACCES: - raise # Not a permission error. + ttf = TTFontFile() + ttf.getMetrics(ttffilename) + desc = { + "Ascent": round(ttf.ascent), + "Descent": round(ttf.descent), + "CapHeight": round(ttf.capHeight), + "Flags": ttf.flags, + "FontBBox": ( + f"[{ttf.bbox[0]:.0f} {ttf.bbox[1]:.0f}" + f" {ttf.bbox[2]:.0f} {ttf.bbox[3]:.0f}]" + ), + "ItalicAngle": int(ttf.italicAngle), + "StemV": round(ttf.stemV), + "MissingWidth": round(ttf.defaultWidth), + } + + # Generate metrics .pkl file + font_dict = { + "type": "TTF", + "name": re.sub("[ ()]", "", ttf.fullName), + "desc": desc, + "up": round(ttf.underlinePosition), + "ut": round(ttf.underlineThickness), + "ttffile": ttffilename, + "fontkey": fontkey, + "originalsize": os.stat(ttffilename).st_size, + "cw": ttf.charWidths, + } self.fonts[fontkey] = { "i": len(self.fonts) + 1, @@ -1543,29 +1514,21 @@ def add_font(self, family, style="", fname=None, uni=False): "ttffile": font_dict["ttffile"], "fontkey": fontkey, "subset": SubsetMap(map(ord, sbarr)), - "unifilename": unifilename, } self.font_files[fontkey] = { "length1": font_dict["originalsize"], "type": "TTF", "ttffile": ttffilename, } - self.font_files[fname] = {"type": "TTF"} else: - if fname.endswith(".ttf"): - warnings.warn( - "When providing a TTF font file you must pass uni=True to FPDF.add_font" - ) + warnings.warn( + "Support for .pkl font files definition is deprecated, and will be removed from fpdf2 soon." + " If you require this feature, please report your need on fpdf2 GitHub project.", + PendingDeprecationWarning, + ) font_dict = pickle.loads(Path(fname).read_bytes()) - if font_dict["type"] == "TTF": - warnings.warn( - "Pickle was generated from TTF font file, setting uni=True" - ) - self.add_font(family, style=style, fname=fname, uni=True) - return - - self.fonts[fontkey] = {"i": len(self.fonts) + 1} - self.fonts[fontkey].update(font_dict) + font_dict["i"] = len(self.fonts) + 1 + self.fonts[fontkey] = font_dict diff = font_dict.get("diff") if diff: # Search existing encodings @@ -2722,7 +2685,7 @@ def image( """ if type: warnings.warn( - '"type" is unused and will soon be deprecated', + '"type" parameter is deprecated, unused and will soon be removed', PendingDeprecationWarning, ) if str(name).endswith(".svg"): @@ -3010,7 +2973,7 @@ def output(self, name="", dest=""): """ if dest: warnings.warn( - '"dest" is unused and will soon be deprecated', + '"dest" parameter is deprecated, unused and will soon be removed', PendingDeprecationWarning, ) # Finish document if necessary: @@ -3438,40 +3401,18 @@ def _putfonts(self): self.mtd(font) def _putTTfontwidths(self, font, maxUni): - if font["unifilename"] is None: - cw127fname = None - else: - cw127fname = Path(font["unifilename"]).with_suffix(".cw127.pkl") - font_dict = load_cache(cw127fname) - if font_dict: - rangeid = font_dict["rangeid"] - range_ = font_dict["range"] - prevcid = font_dict["prevcid"] - prevwidth = font_dict["prevwidth"] - interval = font_dict["interval"] - range_interval = font_dict["range_interval"] - startcid = 128 - else: - rangeid = 0 - range_ = {} - range_interval = {} - prevcid = -2 - prevwidth = -1 - interval = False - startcid = 1 + rangeid = 0 + range_ = {} + range_interval = {} + prevcid = -2 + prevwidth = -1 + interval = False + startcid = 1 cwlen = maxUni + 1 # for each character subset = font["subset"].dict() for cid in range(startcid, cwlen): - if cid == 128 and font_dict: - try: - with cw127fname.open("wb") as fh: - pickle.dump(font_dict, fh) - except OSError as e: - if e.errno != errno.EACCES: - raise # Not a permission error. - width = _char_width(font, cid) if "dw" not in font or (font["dw"] and width != font["dw"]): cid_mapped = subset.get(cid) @@ -4194,4 +4135,4 @@ def _is_xml(img: io.BytesIO): sys.modules[__name__].__class__ = WarnOnDeprecatedModuleAttributes -__all__ = ["FPDF", "load_cache", "get_page_format", "TitleStyle", "PAGE_FORMATS"] +__all__ = ["FPDF", "get_page_format", "TitleStyle", "PAGE_FORMATS"] diff --git a/test/cells/test_cell.py b/test/cells/test_cell.py index caec5426b..58e7a0b98 100644 --- a/test/cells/test_cell.py +++ b/test/cells/test_cell.py @@ -177,9 +177,9 @@ def test_cell_markdown(tmp_path): def test_cell_markdown_with_ttf_fonts(tmp_path): pdf = fpdf.FPDF() pdf.add_page() - pdf.add_font("Roboto", "", HERE / "../fonts/Roboto-Regular.ttf", uni=True) - pdf.add_font("Roboto", "B", HERE / "../fonts/Roboto-Bold.ttf", uni=True) - pdf.add_font("Roboto", "I", HERE / "../fonts/Roboto-Italic.ttf", uni=True) + pdf.add_font("Roboto", "", HERE / "../fonts/Roboto-Regular.ttf") + pdf.add_font("Roboto", "B", HERE / "../fonts/Roboto-Bold.ttf") + pdf.add_font("Roboto", "I", HERE / "../fonts/Roboto-Italic.ttf") pdf.set_font("Roboto", size=60) pdf.cell(txt="**Lorem** __Ipsum__ --dolor--", markdown=True) assert_pdf_equal(pdf, HERE / "cell_markdown_with_ttf_fonts.pdf", tmp_path) @@ -188,7 +188,7 @@ def test_cell_markdown_with_ttf_fonts(tmp_path): def test_cell_markdown_missing_ttf_font(tmp_path): pdf = fpdf.FPDF() pdf.add_page() - pdf.add_font("Roboto", fname=HERE / "../fonts/Roboto-Regular.ttf", uni=True) + pdf.add_font("Roboto", fname=HERE / "../fonts/Roboto-Regular.ttf") pdf.set_font("Roboto", size=60) with pytest.raises(fpdf.FPDFException) as error: pdf.cell(txt="**Lorem Ipsum**", markdown=True) @@ -214,8 +214,8 @@ def test_cell_markdown_bleeding(tmp_path): # issue 241 def test_cell_markdown_right_aligned(tmp_path): # issue 333 pdf = fpdf.FPDF() pdf.add_page() - pdf.add_font("Roboto", "", HERE / "../fonts/Roboto-Regular.ttf", uni=True) - pdf.add_font("Roboto", "B", HERE / "../fonts/Roboto-Bold.ttf", uni=True) + pdf.add_font("Roboto", "", HERE / "../fonts/Roboto-Regular.ttf") + pdf.add_font("Roboto", "B", HERE / "../fonts/Roboto-Bold.ttf") pdf.set_font("Roboto", size=60) pdf.cell( 0, diff --git a/test/cells/test_multi_cell.py b/test/cells/test_multi_cell.py index 8eb5fb4a3..7c0e7687b 100644 --- a/test/cells/test_multi_cell.py +++ b/test/cells/test_multi_cell.py @@ -163,7 +163,7 @@ def test_multi_cell_table_unbreakable(tmp_path): # issue 111 def test_multi_cell_justified_with_unicode_font(tmp_path): # issue 118 pdf = fpdf.FPDF() pdf.add_page() - pdf.add_font("DejaVu", "", HERE / "../fonts/DejaVuSans.ttf", uni=True) + pdf.add_font("DejaVu", "", HERE / "../fonts/DejaVuSans.ttf") pdf.set_font("DejaVu", "", 14) text = 'Justified line containing "()" that is long enough to trigger wrapping and a line jump' pdf.multi_cell(w=0, h=8, txt=text, ln=1) diff --git a/test/cells/test_multi_cell_markdown.py b/test/cells/test_multi_cell_markdown.py index cb0245659..cd7a8d70f 100644 --- a/test/cells/test_multi_cell_markdown.py +++ b/test/cells/test_multi_cell_markdown.py @@ -27,9 +27,9 @@ def test_multi_cell_markdown(tmp_path): def test_multi_cell_markdown_with_ttf_fonts(tmp_path): pdf = fpdf.FPDF() pdf.add_page() - pdf.add_font("Roboto", "", HERE / "../fonts/Roboto-Regular.ttf", uni=True) - pdf.add_font("Roboto", "B", HERE / "../fonts/Roboto-Bold.ttf", uni=True) - pdf.add_font("Roboto", "I", HERE / "../fonts/Roboto-Italic.ttf", uni=True) + pdf.add_font("Roboto", "", HERE / "../fonts/Roboto-Regular.ttf") + pdf.add_font("Roboto", "B", HERE / "../fonts/Roboto-Bold.ttf") + pdf.add_font("Roboto", "I", HERE / "../fonts/Roboto-Italic.ttf") pdf.set_font("Roboto", size=32) text = ( # Some text where styling occur over line breaks: "Lorem ipsum dolor, **consectetur adipiscing** elit," @@ -46,7 +46,7 @@ def test_multi_cell_markdown_with_ttf_fonts(tmp_path): def test_multi_cell_markdown_missing_ttf_font(): pdf = fpdf.FPDF() pdf.add_page() - pdf.add_font("Roboto", fname=HERE / "../fonts/Roboto-Regular.ttf", uni=True) + pdf.add_font("Roboto", fname=HERE / "../fonts/Roboto-Regular.ttf") pdf.set_font("Roboto", size=60) with pytest.raises(fpdf.FPDFException) as error: pdf.multi_cell(w=pdf.epw, txt="**Lorem Ipsum**", markdown=True) diff --git a/test/end_to_end_legacy/charmap/test_charmap.py b/test/end_to_end_legacy/charmap/test_charmap.py index 4ddfcd252..329676107 100644 --- a/test/end_to_end_legacy/charmap/test_charmap.py +++ b/test/end_to_end_legacy/charmap/test_charmap.py @@ -48,7 +48,7 @@ def test_first_999_chars(font_filename, tmp_path): pdf = fpdf.FPDF() pdf.add_page() - pdf.add_font(font_name, fname=font_path, uni=True) + pdf.add_font(font_name, fname=font_path) pdf.set_font(font_name, size=10) ttf = MyTTFontFile() diff --git a/test/fonts/add_font_from_pkl.pdf b/test/fonts/add_font_from_pkl.pdf deleted file mode 100644 index 2f136aafe..000000000 Binary files a/test/fonts/add_font_from_pkl.pdf and /dev/null differ diff --git a/test/fonts/add_font_subset_complete.pdf b/test/fonts/add_font_subset_complete.pdf deleted file mode 100644 index 86ef1c4bd..000000000 Binary files a/test/fonts/add_font_subset_complete.pdf and /dev/null differ diff --git a/test/fonts/test_add_font.py b/test/fonts/test_add_font.py index 5257a2709..146e88d27 100644 --- a/test/fonts/test_add_font.py +++ b/test/fonts/test_add_font.py @@ -10,20 +10,13 @@ HERE = Path(__file__).resolve().parent -def test_add_font_non_existing_file(): +def test_add_font_non_existing(): pdf = FPDF() - with pytest.raises(FileNotFoundError) as error: - pdf.add_font("non-existing") - expected_msg = "[Errno 2] No such file or directory: 'non-existing.pkl'" - assert str(error.value) == expected_msg - - -def test_add_font_non_existing_file_unicode(): - pdf = FPDF() - with pytest.raises(FileNotFoundError) as error: - pdf.add_font("non-existing", uni=True) - expected_msg = "TTF Font file not found: non-existing.pkl" - assert str(error.value) == expected_msg + for uni in (True, False): + with pytest.raises(FileNotFoundError) as error: + pdf.add_font("non-existing", uni=uni) + expected_msg = "[Errno 2] No such file or directory: 'non-existing.pkl'" + assert str(error.value) == expected_msg def test_deprecation_warning_for_FPDF_CACHE_DIR(): @@ -61,7 +54,7 @@ def test_add_font_unicode_with_path_fname_ok(tmp_path): for font_cache_dir in (True, tmp_path, None): pdf = FPDF(font_cache_dir=font_cache_dir) font_file_path = HERE / "Roboto-Regular.ttf" - pdf.add_font("Roboto-Regular", fname=str(font_file_path), uni=True) + pdf.add_font("Roboto-Regular", fname=str(font_file_path)) pdf.set_font("Roboto-Regular", size=64) pdf.add_page() pdf.cell(txt="Hello World!") @@ -72,42 +65,13 @@ def test_add_font_unicode_with_str_fname_ok(tmp_path): for font_cache_dir in (True, str(tmp_path), None): pdf = FPDF(font_cache_dir=font_cache_dir) font_file_path = HERE / "Roboto-Regular.ttf" - pdf.add_font("Roboto-Regular", fname=str(font_file_path), uni=True) + pdf.add_font("Roboto-Regular", fname=str(font_file_path)) pdf.set_font("Roboto-Regular", size=64) pdf.add_page() pdf.cell(txt="Hello World!") assert_pdf_equal(pdf, HERE / "add_font_unicode.pdf", tmp_path) -def test_add_font_from_pkl(tmp_path): - pdf = FPDF() - font_file_path = HERE / "Roboto-Regular.ttf" - pdf.add_font("Roboto-Regular", fname=str(font_file_path), uni=True) - del pdf.fonts["roboto-regular"] # required to be allow to re-add it - # re-using .pkl file generated by previous method call: - pdf.add_font("Roboto-Regular") - pdf.set_font("Roboto-Regular", size=64) - pdf.add_page() - pdf.cell(txt="Hello World!") - assert_pdf_equal(pdf, HERE / "add_font_from_pkl.pdf", tmp_path) - - -def test_add_font_subset_complete(tmp_path): - pdf = FPDF() - pdf.alias_nb_pages(None) - - font_file_path = HERE / "Roboto-Regular.ttf" - pdf.add_font("Roboto-Regular", fname=str(font_file_path), uni=True) - - pdf = FPDF() - # re-using .pkl file generated by previous instance - pdf.add_font("Roboto-Regular") - pdf.set_font("Roboto-Regular", size=64) - pdf.add_page() - pdf.cell(txt="This is page {nb}") - assert_pdf_equal(pdf, HERE / "add_font_subset_complete.pdf", tmp_path) - - def teardown(): # Clean-up for test_add_font_from_pkl with suppress(FileNotFoundError): @@ -130,7 +94,7 @@ def test_add_core_fonts(): def test_render_en_dash(tmp_path): # issue-166 pdf = FPDF() font_file_path = HERE / "Roboto-Regular.ttf" - pdf.add_font("Roboto-Regular", fname=str(font_file_path), uni=True) + pdf.add_font("Roboto-Regular", fname=str(font_file_path)) pdf.set_font("Roboto-Regular", size=120) pdf.add_page() pdf.cell(w=pdf.epw, txt="–") # U+2013 diff --git a/test/fonts/test_font_remap.py b/test/fonts/test_font_remap.py index 2712f69ee..f7e9d1822 100644 --- a/test/fonts/test_font_remap.py +++ b/test/fonts/test_font_remap.py @@ -37,7 +37,7 @@ def test_emoji_glyph(tmp_path): pdf = FPDF(font_cache_dir=tmp_path) font_file_path = HERE / "DejaVuSans.ttf" - pdf.add_font("DejaVuSans", fname=str(font_file_path), uni=True) + pdf.add_font("DejaVuSans", fname=str(font_file_path)) pdf.set_font("DejaVuSans", size=64) pdf.add_page() @@ -53,7 +53,7 @@ def test_nb_replace(tmp_path): pdf = FPDF(font_cache_dir=tmp_path) font_file_path = HERE / "DejaVuSans.ttf" - pdf.add_font("DejaVuSans", fname=str(font_file_path), uni=True) + pdf.add_font("DejaVuSans", fname=str(font_file_path)) pdf.add_page() pdf.set_font("DejaVuSans", size=64) @@ -70,8 +70,8 @@ def test_two_mappings(tmp_path): font_file_path_1 = HERE / "DejaVuSans.ttf" font_file_path_2 = HERE / "DroidSansFallback.ttf" - pdf.add_font("DejaVuSans", fname=str(font_file_path_1), uni=True) - pdf.add_font("DroidSansFallback", fname=str(font_file_path_2), uni=True) + pdf.add_font("DejaVuSans", fname=str(font_file_path_1)) + pdf.add_font("DroidSansFallback", fname=str(font_file_path_2)) pdf.add_page() pdf.set_font("DejaVuSans", size=64) @@ -85,7 +85,7 @@ def test_two_mappings(tmp_path): def test_thai_text(tmp_path): pdf = FPDF(font_cache_dir=tmp_path) - pdf.add_font("Waree", fname=HERE / "Waree.ttf", uni=True) + pdf.add_font("Waree", fname=HERE / "Waree.ttf") pdf.set_font("Waree") pdf.add_page() pdf.write(txt="สวัสดีชาวโลก ทดสอบฟอนต์, Hello world font test.") diff --git a/test/html/test_html.py b/test/html/test_html.py index 735e1cb43..4bc42ba10 100644 --- a/test/html/test_html.py +++ b/test/html/test_html.py @@ -402,7 +402,7 @@ def test_html_justify_paragraph(tmp_path): def test_issue_156(tmp_path): pdf = MyFPDF() - pdf.add_font("Roboto", style="B", fname="test/fonts/Roboto-Bold.ttf", uni=True) + pdf.add_font("Roboto", style="B", fname="test/fonts/Roboto-Bold.ttf") pdf.set_font("Roboto", style="B") pdf.add_page() with pytest.raises(FPDFException) as error: @@ -411,7 +411,7 @@ def test_issue_156(tmp_path): str(error.value) == "Undefined font: roboto - Use built-in fonts or FPDF.add_font() beforehand" ) - pdf.add_font("Roboto", fname="test/fonts/Roboto-Regular.ttf", uni=True) + pdf.add_font("Roboto", fname="test/fonts/Roboto-Regular.ttf") pdf.write_html("Regular text
Bold text") assert_pdf_equal(pdf, HERE / "issue_156.pdf", tmp_path) @@ -432,7 +432,7 @@ def test_html_font_color_name(tmp_path): def test_html_heading_hebrew(tmp_path): pdf = MyFPDF() - pdf.add_font("DejaVuSans", fname=HERE / "../fonts/DejaVuSans.ttf", uni=True) + pdf.add_font("DejaVuSans", fname=HERE / "../fonts/DejaVuSans.ttf") pdf.set_font("DejaVuSans") pdf.add_page() pdf.write_html("

Hebrew: שלום עולם

") diff --git a/test/outline/test_outline.py b/test/outline/test_outline.py index 31a8057d4..316887759 100644 --- a/test/outline/test_outline.py +++ b/test/outline/test_outline.py @@ -161,7 +161,7 @@ def test_2_pages_outline(tmp_path): def test_russian_heading(tmp_path): # issue-320 pdf = FPDF() - pdf.add_font("Roboto", style="B", fname="test/fonts/Roboto-Regular.ttf", uni=True) + pdf.add_font("Roboto", style="B", fname="test/fonts/Roboto-Regular.ttf") pdf.set_font("Roboto", style="B") pdf.add_page() pdf.start_section("Русский, English, 1 2 3...") diff --git a/test/utils/test_load_cache.py b/test/utils/test_load_cache.py deleted file mode 100644 index c2e5923bf..000000000 --- a/test/utils/test_load_cache.py +++ /dev/null @@ -1,18 +0,0 @@ -import pickle - -import fpdf - - -def test_load_cache_none(): - result = fpdf.fpdf.load_cache(None) - assert result is None - - -def test_load_cache_pickle(tmp_path): - path = tmp_path / "filename.pickle" - a = {"hello": "world"} - with path.open("wb") as handle: - pickle.dump(a, handle, protocol=pickle.HIGHEST_PROTOCOL) - - assert fpdf.fpdf.load_cache(path) == a - assert fpdf.fpdf.load_cache(path.with_name("filename1.pickle")) is None diff --git a/tutorial/unicode.py b/tutorial/unicode.py index ad6ca06fd..99d0bf6d1 100644 --- a/tutorial/unicode.py +++ b/tutorial/unicode.py @@ -8,7 +8,7 @@ # Add a DejaVu Unicode font (uses UTF-8) # Supports more than 200 languages. For a coverage status see: # http://dejavu.svn.sourceforge.net/viewvc/dejavu/trunk/dejavu-fonts/langcover.txt -pdf.add_font("DejaVu", fname="DejaVuSansCondensed.ttf", uni=True) +pdf.add_font("DejaVu", fname="DejaVuSansCondensed.ttf") pdf.set_font("DejaVu", size=14) text = """ @@ -30,14 +30,14 @@ # Supports: Bengali, Devanagari, Gujarati, # Gurmukhi (including the variants for Punjabi) # Kannada, Malayalam, Oriya, Tamil, Telugu, Tibetan -pdf.add_font("gargi", fname="gargi.ttf", uni=True) +pdf.add_font("gargi", fname="gargi.ttf") pdf.set_font("gargi", size=14) pdf.write(8, "Hindi: नमस्ते दुनिया") pdf.ln(20) # Add a AR PL New Sung Unicode font (uses UTF-8) # The Open Source Chinese Font (also supports other east Asian languages) -pdf.add_font("fireflysung", fname="fireflysung.ttf", uni=True) +pdf.add_font("fireflysung", fname="fireflysung.ttf") pdf.set_font("fireflysung", size=14) pdf.write(8, "Chinese: 你好世界\n") pdf.write(8, "Japanese: こんにちは世界\n") @@ -46,13 +46,13 @@ # Add a Alee Unicode font (uses UTF-8) # General purpose Hangul truetype fonts that contain Korean syllable # and Latin9 (iso8859-15) characters. -pdf.add_font("eunjin", fname="Eunjin.ttf", uni=True) +pdf.add_font("eunjin", fname="Eunjin.ttf") pdf.set_font("eunjin", size=14) pdf.write(8, "Korean: 안녕하세요") pdf.ln(20) # Add a Fonts-TLWG (formerly ThaiFonts-Scalable) (uses UTF-8) -pdf.add_font("waree", fname="Waree.ttf", uni=True) +pdf.add_font("waree", fname="Waree.ttf") pdf.set_font("waree", size=14) pdf.write(8, "Thai: สวัสดีชาวโลก") pdf.ln(20)