diff --git a/_unittests/ut_cli/data/image.png b/_unittests/ut_cli/data/image.png new file mode 100644 index 000000000..5bd15e991 Binary files /dev/null and b/_unittests/ut_cli/data/image.png differ diff --git a/_unittests/ut_cli/test_cli_img.py b/_unittests/ut_cli/test_cli_img.py new file mode 100644 index 000000000..74787f5a3 --- /dev/null +++ b/_unittests/ut_cli/test_cli_img.py @@ -0,0 +1,37 @@ +""" +@brief test tree node (time=7s) +""" + +import sys +import os +import unittest +import warnings +from io import StringIO + +from pyquickhelper.loghelper import fLOG, BufferedPrint +from pyquickhelper.pycode import ExtTestCase, get_temp_folder +from pyquickhelper.__main__ import main + + +class TestCliImgHelper(ExtTestCase): + + def test_zoom_img_help(self): + st = BufferedPrint() + main(args=['zoom_img', '--help'], fLOG=st.fprint) + res = str(st) + self.assertIn("zoom_img [-h]", res) + + def test_zoom_img_do(self): + temp = get_temp_folder(__file__, 'temp_img_zoom') + dest = os.path.join(temp, '{}') + data = os.path.join(temp, '..', 'data', '*.png') + st = BufferedPrint() + win = main(args=['zoom_img', '-f', '0.5', '--img', + data, '-o', dest], fLOG=st.fprint) + res = str(st) + self.assertNotIn("zoom_img [-h]", res) + self.assertIn("Writing '", res) + + +if __name__ == "__main__": + unittest.main() diff --git a/_unittests/ut_imghelper/data/image.png b/_unittests/ut_imghelper/data/image.png new file mode 100644 index 000000000..5bd15e991 Binary files /dev/null and b/_unittests/ut_imghelper/data/image.png differ diff --git a/_unittests/ut_imghelper/test_imghelper.py b/_unittests/ut_imghelper/test_imghelper.py new file mode 100644 index 000000000..cbcd4ee72 --- /dev/null +++ b/_unittests/ut_imghelper/test_imghelper.py @@ -0,0 +1,41 @@ +""" +@brief test log(time=7s) + +skip this test for regular run +""" + +import sys +import os +import unittest + +from pyquickhelper.loghelper import fLOG +from pyquickhelper.pycode import get_temp_folder, ExtTestCase +from pyquickhelper.imghelper.img_helper import zoom_img + + +class TestImgHelper(ExtTestCase): + + def test_img_zoom(self): + temp = get_temp_folder(__file__, "temp_img_zoom") + data = os.path.join(temp, "..", "data", "image.png") + dest = os.path.join(temp, "image2.png") + obj = zoom_img(data, factor=0.5, out_file=dest) + self.assertExists(dest) + self.assertNotEmpty(obj) + dest = os.path.join(temp, "image3.png") + obj = zoom_img(data, max_dim=10, out_file=dest) + self.assertExists(dest) + self.assertNotEmpty(obj) + + def test_img_zoom_folder(self): + temp = get_temp_folder(__file__, "temp_img_zoom_folder") + data = os.path.join(temp, "..", "data", "*.png") + dest = os.path.join(temp, "{}") + obj = zoom_img(data, factor=0.5, out_file=dest) + dest = os.path.join(temp, "image.png") + self.assertExists(dest) + self.assertNotEmpty(obj) + + +if __name__ == "__main__": + unittest.main() diff --git a/src/pyquickhelper/__main__.py b/src/pyquickhelper/__main__.py index 316efcf7b..c7f82f57d 100644 --- a/src/pyquickhelper/__main__.py +++ b/src/pyquickhelper/__main__.py @@ -27,6 +27,7 @@ def main(args, fLOG=print): from .filehelper import explore_folder from .cli.simplified_fct import sphinx_rst from .ipythonhelper import run_notebook + from .imghelper.img_helper import zoom_img except ImportError: # pragma: no cover from pyquickhelper.cli.pyq_sync_cli import pyq_sync from pyquickhelper.cli.encryption_file_cli import encrypt_file, decrypt_file @@ -39,6 +40,7 @@ def main(args, fLOG=print): from pyquickhelper.filehelper import explore_folder from pyquickhelper.cli.simplified_fct import sphinx_rst from pyquickhelper.ipythonhelper import run_notebook + from pyquickhelper.imghelper.img_helper import zoom_img fcts = dict(synchronize_folder=pyq_sync, encrypt_file=encrypt_file, decrypt_file=decrypt_file, encrypt=encrypt, @@ -46,7 +48,8 @@ def main(args, fLOG=print): process_notebooks=process_notebooks, visual_diff=create_visual_diff_through_html_files, ls=explore_folder, run_test_function=run_test_function, - sphinx_rst=sphinx_rst, run_notebook=run_notebook) + sphinx_rst=sphinx_rst, run_notebook=run_notebook, + zoom_img=zoom_img) return cli_main_helper(fcts, args=args, fLOG=fLOG) diff --git a/src/pyquickhelper/imghelper/img_helper.py b/src/pyquickhelper/imghelper/img_helper.py new file mode 100644 index 000000000..29436384a --- /dev/null +++ b/src/pyquickhelper/imghelper/img_helper.py @@ -0,0 +1,60 @@ +""" +@file +@brief Helpers around images. + +.. versionadded:: 1.9 +""" +import os +import glob + + +def zoom_img(img, factor=1., max_dim=None, out_file=None, fLOG=None): + """ + Zooms an image. + + @param img image or filename or pattern + @param factor multiplies the image by this factor if not None + @param max_dim modifies the image, the highest dimension + should below this number + @param out_file stores the image into this file if not None + @param fLOG logging function + @return image + """ + if isinstance(img, str): + if '*' in img: + found = glob.glob(img) + res = [] + for im in found: + if out_file is None: + i = zoom_img(im, factor=factor, max_dim=max_dim, fLOG=fLOG) + else: + of = out_file.format(os.path.split(im)[-1]) + i = zoom_img(im, factor=factor, max_dim=max_dim, + out_file=of, fLOG=fLOG) + res.append(i) + return res + from PIL import Image + obj = Image.open(img) + elif hasattr(obj, 'size'): + obj = img + else: + raise TypeError( + "Image should be a string or an image not {}.".format(type(img))) + dx, dy = obj.size + if max_dim is not None: + if not isinstance(max_dim, int): + max_dim = int(max_dim) + facx = dx * 1. / max_dim + facy = dy * 1. / max_dim + factor = min(facx, facy) + if factor is not None: + if not isinstance(factor, float): + factor = int(factor) + dx = int(dx * factor + 0.5) + dy = int(dy * factor + 0.5) + obj = obj.resize((dx, dy)) + if out_file is not None: + if fLOG is not None: + fLOG("Writing '{}' dim=({},{}).".format(out_file, dx, dy)) + obj.save(out_file) + return obj diff --git a/src/pyquickhelper/sphinxext/sphinx_githublink_extension.py b/src/pyquickhelper/sphinxext/sphinx_githublink_extension.py index 7beb96a77..99a6e5c6b 100644 --- a/src/pyquickhelper/sphinxext/sphinx_githublink_extension.py +++ b/src/pyquickhelper/sphinxext/sphinx_githublink_extension.py @@ -181,14 +181,15 @@ def githublink_role(role, rawtext, text, lineno, inliner, elif doc == "src": path = docname source_doc = inliner.document.settings._source - source_doc = source_doc.replace("\\", "/") - spl = source_doc.split('/') - if '_doc' in source_doc: - sub_doc = source_doc[:source_doc.index('_doc')] - root_doc = "/".join(sub_doc) - root_doc_src = os.path.join(root_doc, 'src') - if os.path.exists(root_doc_src): - path = os.path.join('src', docname) + if source_doc is not None: + source_doc = source_doc.replace("\\", "/") + spl = source_doc.split('/') + if '_doc' in source_doc: + sub_doc = source_doc[:source_doc.index('_doc')] + root_doc = "/".join(sub_doc) + root_doc_src = os.path.join(root_doc, 'src') + if os.path.exists(root_doc_src): + path = os.path.join('src', docname) elif doc == "doc": path = os.path.join('_doc', 'sphinxdoc', 'source', docname) else: