diff --git a/README.md b/README.md index e1784b0205887398bedaeae89fcc8724fb26b46d..9fe098196d54f5309a5e7d34036cd7da76752c8d 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,8 @@ The argument "plot_engine" defines which plot engine was used to create the figu tagplot returns a PlotIDTransfer object that contains the tagged figures and the corresponding IDs as strings. Optional parameters can be used to customize the tag process. +- *figure_ids*: list of str, optional + IDs that will be printed on the plot. If empty, IDs will be generated for each plot. If this option is used, an ID for each plot has to be specified. Default: []. - *prefix* : str, optional Will be added as prefix to the ID. - *id_method* : str, optional diff --git a/plotid/plotoptions.py b/plotid/plotoptions.py index 521e4845cfbf8fa0de8fbd83bdcd380ca6a08954..3a60c6db3b0bda2beadb52a4bc066fd4f01b0189 100644 --- a/plotid/plotoptions.py +++ b/plotid/plotoptions.py @@ -50,10 +50,9 @@ class PlotOptions: id_method : str, optional id_method for creating the ID. Create an ID by Unix time is referenced as "time", create a random ID with id_method="random". - The default is 'time'. + The default is "time". qrcode : bool, optional - Experimental support to encode the ID in a QR code on the exported plot. - Default: False. + Encode the ID in a QR code on the exported plot. Default: False. qr_position : tuple, optional Position of the bottom right corner of the QR Code on the plot in relative (x, y) coordinates. Default: (1, 0). @@ -63,7 +62,9 @@ class PlotOptions: Print ID on the plot. Default: True. font: str, optional Font that will be used to print the ID. A path to an .otf or a .ttf - file has to be given. + file has to be given. To use already installed fonts, you can search for the + standard path of fonts on your operating system and give then the path of the + desired font file to this parameter. fontsize: int, optional Fontsize for the displayed ID. Default: 12. fontcolor: tuple, optional diff --git a/plotid/resources/OpenSans/OFL.txt b/plotid/resources/OpenSans/OFL.txt new file mode 100644 index 0000000000000000000000000000000000000000..9b448d4017f9233c21ae6db92c90bc2d229f56b2 --- /dev/null +++ b/plotid/resources/OpenSans/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2020 The Open Sans Project Authors (https://github.com/googlefonts/opensans) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/plotid/resources/OpenSans/OpenSans-Bold.ttf b/plotid/resources/OpenSans/OpenSans-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a1398b338084cbaf0e99d89cb6089715baa78a6d Binary files /dev/null and b/plotid/resources/OpenSans/OpenSans-Bold.ttf differ diff --git a/plotid/resources/OpenSans/OpenSans-Regular.ttf b/plotid/resources/OpenSans/OpenSans-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1dc226ddc00a11a9813844b00fb5edaf87921c38 Binary files /dev/null and b/plotid/resources/OpenSans/OpenSans-Regular.ttf differ diff --git a/plotid/resources/__init__.py b/plotid/resources/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/plotid/tagplot.py b/plotid/tagplot.py index 3c01d06ce570b54453d84a40b4dcb3bcca546820..b43b3a36bef27e7327e5d3146d015b30546d6287 100644 --- a/plotid/tagplot.py +++ b/plotid/tagplot.py @@ -41,7 +41,8 @@ def tagplot( ---------------- figure_ids: list of str, optional IDs that will be printed on the plot. If empty, IDs will be generated for each - plot. Default: []. + plot. If this option is used, an ID for each plot has to be specified. + Default: []. location : str, optional Location for ID to be displayed on the plot. Default is "east". rotation: float or int, optional @@ -55,10 +56,9 @@ def tagplot( id_method : str, optional id_method for creating the ID. Create an ID by Unix time is referenced as "time", create a random ID with id_method="random". - The default is 'time'. + The default is "time". qrcode : bool, optional - Experimental support to encode the ID in a QR code on the exported plot. - Default: False. + Encode the ID in a QR code on the exported plot. Default: False. qr_position : tuple, optional Position of the bottom right corner of the QR Code on the plot in relative (x, y) coordinates. Default: (1, 0). @@ -67,8 +67,10 @@ def tagplot( id_on_plot: bool, optional Print ID on the plot. Default: True. font: str, optional - Font that will be used to print the ID. A path to an .otf or a .ttf - file has to be given. + Font that will be used to print the ID. An absolute path to an .otf or a .ttf + file has to be given. To use already installed fonts, you can search for the + standard path of fonts on your operating system and give then the path of the + desired font file to this parameter. fontsize: int, optional Fontsize for the displayed ID. Default: 12. fontcolor: tuple, optional diff --git a/plotid/tagplot_image.py b/plotid/tagplot_image.py index 888fec1944f2811d32e08cb8250c2f5f6a97d5ff..a1f60eb7c86c2af040dbd3563cd882ecd01360fb 100644 --- a/plotid/tagplot_image.py +++ b/plotid/tagplot_image.py @@ -7,6 +7,7 @@ Functions: """ import os import warnings +from importlib.resources import files from PIL import Image, ImageDraw, ImageFont, ImageOps from plotid.create_id import create_id, create_qrcode from plotid.plotoptions import PlotOptions, PlotIDTransfer @@ -38,11 +39,22 @@ def tagplot_image(plotid_object: PlotOptions) -> PlotIDTransfer: if not isinstance(img, str): raise TypeError("Name of the image is not a string.") if not os.path.isfile(img): - raise TypeError("File does not exist.") + raise TypeError(f"Image '{img}' does not exist.") # Check if figs is a valid file is done by pillow internally color = tuple(rgb_value * 255 for rgb_value in plotid_object.fontcolor) - font = ImageFont.load_default() + # font = ImageFont.load_default() + font_path = ( + files("plotid.resources").joinpath("OpenSans").joinpath("OpenSans-Regular.ttf") + ) + font = ImageFont.truetype(str(font_path), plotid_object.fontsize) + + if plotid_object.font: + try: + # Absolute path to font file (.ttf or .otf) has to be given + font = ImageFont.truetype(plotid_object.font, plotid_object.fontsize) + except OSError: + warnings.warn("Font was not found.\nplotID continues with fallback font.") if plotid_object.font: try: diff --git a/plotid/tagplot_matplotlib.py b/plotid/tagplot_matplotlib.py index f0eaac2910a7eb68f6b5fdafbe21238ec99eebd8..2a0b44145537be999324662fac3b0b8d7232c710 100644 --- a/plotid/tagplot_matplotlib.py +++ b/plotid/tagplot_matplotlib.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- """Tag your matplotlib plot with an ID.""" +from importlib.resources import files import matplotlib import matplotlib.pyplot as plt from PIL import Image @@ -35,6 +36,19 @@ def tagplot_matplotlib(plotid_object: PlotOptions) -> PlotIDTransfer: if not isinstance(figure, matplotlib.figure.Figure): raise TypeError("Figure is not a valid matplotlib-figure.") + if plotid_object.font: + # Load custom font into matplotlib + matplotlib.font_manager.fontManager.addfont(plotid_object.font) + font = matplotlib.font_manager.FontProperties(fname=plotid_object.font) + else: + font = ( + files("plotid.resources") + .joinpath("OpenSans") + .joinpath("OpenSans-Regular.ttf") + ) + matplotlib.font_manager.fontManager.addfont(str(font)) + font = matplotlib.font_manager.FontProperties(fname=font) + # Loop to create and position the IDs for j, fig in enumerate(plotid_object.figs): if plotid_object.id_method == "custom": @@ -48,11 +62,6 @@ def tagplot_matplotlib(plotid_object: PlotOptions) -> PlotIDTransfer: plt.figure(fig) if plotid_object.id_on_plot: - font = "DejaVu Sans" - if plotid_object.font: - # Load custom font into matplotlib - matplotlib.font_manager.fontManager.addfont(plotid_object.font) - font = matplotlib.font_manager.FontProperties(fname=plotid_object.font) plt.figtext( x=plotid_object.position[0], diff --git a/tests/test_tagplot_image.py b/tests/test_tagplot_image.py index 6ffbca0e0cf36e87f087bb02a32295d2c008a5a6..2dd88fc35cee0f5d3907dabfd0947771ff90b617 100644 --- a/tests/test_tagplot_image.py +++ b/tests/test_tagplot_image.py @@ -47,7 +47,7 @@ class TestTagplotImage(unittest.TestCase): id_method=METHOD, qrcode=True, fontsize=10, - font="tests/fonts/xolonium-fonts-4.1/ttf/Xolonium-Bold.ttf", + font="plotid/resources/OpenSans/OpenSans-Bold.ttf", fontcolor=(0, 1, 0), ) options.validate_input() @@ -88,20 +88,9 @@ class TestTagplotImage(unittest.TestCase): with self.assertRaises(TypeError): tagplot_image("wrong_object") - def test_wrong_font(self) -> None: - """Test if Warning is raised if a given font file can not be found.""" - options = PlotOptions( - [IMG1, IMG2], - ROTATION, - POSITION, - figure_ids=["test123456", "654321tset"], - prefix=PROJECT_ID, - id_method=METHOD, - qrcode=True, - fontsize=10, - font="not_existing_font.ttf", - fontcolor=(0, 1, 0), - ) + def test_font_file_not_defined(self) -> None: + """Test if a Warning is raised if an invalid font file was specified.""" + options = PlotOptions(IMG1, ROTATION, POSITION, font="font") options.validate_input() with self.assertWarns(Warning): tagplot_image(options) diff --git a/tests/test_tagplot_matplotlib.py b/tests/test_tagplot_matplotlib.py index 6ce909f969a4719a3d708e1d6089d6548d76caae..d93e768610983d0dcabe6deaa913973e8516a8dd 100644 --- a/tests/test_tagplot_matplotlib.py +++ b/tests/test_tagplot_matplotlib.py @@ -38,7 +38,7 @@ class TestTagplotMatplotlib(unittest.TestCase): id_method=METHOD, qrcode=True, fontsize=10, - font="tests/fonts/xolonium-fonts-4.1/otf/Xolonium-Regular.otf", + font="plotid/resources/OpenSans/OpenSans-Bold.ttf", fontcolor=(0, 0, 1), ) options.validate_input()