Skip to content
This repository was archived by the owner on Jan 13, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
341 changes: 341 additions & 0 deletions _doc/notebooks/example_nbimage.ipynb

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions _doc/sphinxdoc/source/api/image.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

imghelper: helpers for images
=============================

.. contents::
:local:

Export
++++++

.. autosignature:: pyquickhelper.imghelper.img_export.images2pdf

.. autosignature:: pyquickhelper.imghelper.svg_helper.svg2img

Image manipulations
+++++++++++++++++++

.. autosignature:: pyquickhelper.imghelper.img_helper.concat_images

.. image:: https://github.com/sdpython/pyquickhelper/raw/master/_unittests/ut_imghelper/data/merged_image6.png

.. autosignature:: pyquickhelper.imghelper.img_helper.white_to_transparency

.. autosignature:: pyquickhelper.imghelper.img_helper.zoom_img
1 change: 1 addition & 0 deletions _doc/sphinxdoc/source/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ API Summary
clihelper
filehelper
helpgen
image
sphinxext
jenkins
jupyter
Expand Down
31 changes: 21 additions & 10 deletions _unittests/ut_helpgen/test_helper_helpgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,38 @@
@brief test log(time=8s)
@author Xavier Dupre
"""

import sys
import os
import unittest

from pyquickhelper.loghelper.flog import fLOG
from pyquickhelper.helpgen.utils_sphinx_config import locate_image_documentation, NbImage

from IPython.core.display import Image
from pyquickhelper.pycode import ExtTestCase
from pyquickhelper.helpgen.utils_sphinx_config import NbImage


class TestHelperHelpGen(unittest.TestCase):
class TestHelperHelpGen(ExtTestCase):

def test_NbImage(self):
fLOG(
__file__,
self._testMethodName,
OutputPrint=__name__ == "__main__")
r = NbImage("completion.png")
assert isinstance(r, Image)

def test_NbImage_url(self):
r = NbImage(
'https://github.com/sdpython/pyquickhelper/raw/master/'
'_doc/sphinxdoc/source/phdoc_static/project_ico.png')
self.assertIsInstance(r, Image)

def test_NbImage_multi(self):
r = NbImage("completion.png", "completion.png")
self.assertIsInstance(r, Image)

def test_NbImage_url_multi(self):
r = NbImage(
'https://github.com/sdpython/pyquickhelper/raw/master/'
'_doc/sphinxdoc/source/phdoc_static/project_ico.png',
'https://github.com/sdpython/pyquickhelper/raw/master/'
'_doc/sphinxdoc/source/phdoc_static/project_ico.png')
self.assertIsInstance(r, Image)


if __name__ == "__main__":
unittest.main()
2 changes: 1 addition & 1 deletion _unittests/ut_helpgen/test_stat_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def test_enumerate_notebooks_link(self):
counts["title"] += 1
nbfound.add(rl[1])
self.assertTrue(counts.get("ref", 0) > 0)
self.assertIn(counts.get(None, 0), (0, 12))
self.assertIn(counts.get(None, 0), (0, 13))
self.assertTrue(counts["title"] > 0)
self.assertTrue(len(nbfound) > 8)
# self.assertTrue(counts.get("refn", 0) > 0)
Expand Down
Binary file added _unittests/ut_imghelper/data/img1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _unittests/ut_imghelper/data/img2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _unittests/ut_imghelper/data/img3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _unittests/ut_imghelper/data/img4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _unittests/ut_imghelper/data/img5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _unittests/ut_imghelper/data/img6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added _unittests/ut_imghelper/data/merged_image6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 1 addition & 4 deletions _unittests/ut_imghelper/test_imgexport.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
"""
@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_export import images2pdf
Expand All @@ -17,7 +14,7 @@ class TestImgExport(ExtTestCase):

def test_exports(self):
temp = get_temp_folder(__file__, "temp_img2pdf")
data = os.path.join(temp, "..", "data", "IMG_20160103_0024.jpg")
data = os.path.join(temp, "..", "data", "image2.jpg")
datap = os.path.join(temp, "..", "data", "*.jpg")
dest = os.path.join(temp, "images.pdf")
res = images2pdf([data, datap], dest)
Expand Down
25 changes: 23 additions & 2 deletions _unittests/ut_imghelper/test_imghelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

from pyquickhelper.loghelper import fLOG
from pyquickhelper.pycode import get_temp_folder, ExtTestCase
from pyquickhelper.imghelper.img_helper import zoom_img, white_to_transparency
from pyquickhelper.imghelper.img_helper import (
zoom_img, white_to_transparency, concat_images)


class TestImgHelper(ExtTestCase):
Expand All @@ -31,7 +32,7 @@ def test_img_zoom(self):

def test_img_zoom_folder(self):
temp = get_temp_folder(__file__, "temp_img_zoom_folder")
data = os.path.join(temp, "..", "data", "*.png")
data = os.path.join(temp, "..", "data", "image*.png")
dest = os.path.join(temp, "{}")
obj = zoom_img(data, factor=0.5, out_file=dest)
dest = os.path.join(temp, "image.png")
Expand All @@ -46,6 +47,26 @@ def test_transparency(self):
self.assertExists(dest)
self.assertNotEmpty(obj)

def test_concat_images(self):
temp = get_temp_folder(__file__, "temp_concat_images")
data = os.path.join(temp, "..", "data")
images = [os.path.join(data, 'img%d.png' % (i + 1))
for i in range(0, 6)]
dest = os.path.join(temp, "image2.png")
res = concat_images(images, out_file=dest, width=600)
self.assertExists(dest)
self.assertEqual(res.size[0], 600)

def test_concat_images4(self):
temp = get_temp_folder(__file__, "temp_concat_images4")
data = os.path.join(temp, "..", "data")
images = [os.path.join(data, 'img%d.png' % (i + 1))
for i in range(0, 4)]
dest = os.path.join(temp, "image2.png")
res = concat_images(images, out_file=dest, width=600)
self.assertExists(dest)
self.assertEqual(res.size[0], 600)


if __name__ == "__main__":
unittest.main()
2 changes: 1 addition & 1 deletion _unittests/ut_ipythonhelper/test_notebook_runner_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def test_notebook_runner_report(self):
if len(cov) <= 9:
raise Exception("too few found notebooks")

if cov.shape[0] != 15:
if cov.shape[0] != 16:
raise AssertionError("NB={0}\n----\n{1}".format(cov.shape, cov))
self.assertIn("last_name", cov.columns)
cols = ['notebooks', 'last_name', 'date', 'etime',
Expand Down
155 changes: 111 additions & 44 deletions src/pyquickhelper/helpgen/utils_sphinx_config.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"""
@file
@brief Check various settings.

"""

import sys
import os
import site
from io import BytesIO
import urllib.request as urllib_request


def getsitepackages():
Expand Down Expand Up @@ -35,16 +35,22 @@ def locate_image_documentation(image_name):
it was taken. The function was entering an infinite loop.
The function can deal with subfolder and not only the folder which contains the notebook.
"""
image_name = os.path.abspath(image_name)
if os.path.exists(image_name):
return image_name
folder, filename = os.path.split(image_name)
while len(folder) > 0 and (not os.path.exists(folder) or "_doc" not in os.listdir(folder)):
while (len(folder) > 0 and
(not os.path.exists(folder) or "_doc" not in os.listdir(folder))):
fold = os.path.split(folder)[0]
if fold == folder:
break
folder = fold
doc = os.path.join(folder, "_doc")
if not os.path.exists(doc):
raise FileNotFoundError(
"unable to find a folder called _doc, the function cannot locate an image\n{0}".format(image_name))
"Unable to find a folder called _doc, "
"the function cannot locate an image %r, doc=%r, folder=%r."
"" % (image_name, doc, folder))
for root, _, files in os.walk(doc):
for name in files:
t = os.path.join(root, name)
Expand All @@ -54,52 +60,37 @@ def locate_image_documentation(image_name):
raise FileNotFoundError(image_name)


def NbImage(name, repository=None, force_github=False, width=None, branch='master'):
"""
Retrieves a name or a url of the image if it is not found in the local folder
or a subfolder.

@param name image name (name.png)
@param force_github force the system to retrieve the image from GitHub
@param repository repository, see below
@param width to modify the width
@param branch branch
@return an `Image object <http://ipython.org/ipython-doc/2/api/generated/IPython.core.display.html
#IPython.core.display.Image>`_

We assume the image is retrieved from a notebook.
This function will display an image even though the notebook is not run
from the sources. IPython must be installed.

if *repository* is None, then the function will use the variable ``module.__github__`` to
guess the location of the image.
The function is able to retrieve an image in a subfolder.
Displays a better message if ``__github__`` was not found.
"""
from IPython.core.display import Image
local = os.path.abspath(name)
if not force_github and os.path.exists(local):
return Image(local, width=width)

local_split = local.replace("\\", "/").split("/")
if "notebooks" not in local_split:
local = locate_image_documentation(local)
return Image(local, width=width)
def _NbImage_path(name, repository=None, force_github=False, branch='master'):
if not isinstance(name, str):
return name
if os.path.exists(name):
return os.path.abspath(name).replace("\\", "/")
if not name.startswith('http://') and not name.startswith('https://'):
# local file
local = name
local_split = name.split("/")
if "notebooks" not in local_split:
local = locate_image_documentation(local)
return local
else:
return name

# otherwise --> github
paths = local.replace("\\", "/").split("/")
try:
pos = paths.index("notebooks") - 1
except IndexError as e:
# we are looking for the right path
mes = "The image is not retrieved from a notebook from a folder `_docs/notebooks`" + \
" or you changed the current folder:\n{0}"
raise IndexError(mes.format(local)) from e
raise IndexError(
"The image is not retrieved from a notebook from a folder "
"`_docs/notebooks` or you changed the current folder:"
"\n{0}".format(local)) from e
except ValueError as ee:
# we are looking for the right path
mes = "the image is not retrieve from a notebook from a folder ``_docs/notebooks`` " + \
"or you changed the current folder:\n{0}"
raise IndexError(mes.format(local)) from ee
raise IndexError(
"The image is not retrieve from a notebook from a folder "
"``_docs/notebooks`` or you changed the current folder:"
"\n{0}".format(local)) from ee

if repository is None:
module = paths[pos - 1]
Expand All @@ -109,16 +100,92 @@ def NbImage(name, repository=None, force_github=False, width=None, branch='maste
repository = "https://github.com/sdpython/ensae_teaching_cs/"
else:
raise ImportError(
"The module {0} was not imported, cannot guess the location of the repository".format(module))
"The module {0} was not imported, cannot guess "
"the location of the repository".format(module))
else:
modobj = sys.modules[module]
if not hasattr(modobj, "__github__"):
raise AttributeError(
"The module has no attribute '__github__'. The repository cannot be guessed.")
"The module has no attribute '__github__'. "
"The repository cannot be guessed.")
repository = modobj.__github__
repository = repository.rstrip("/")

loc = "/".join([branch, "_doc", "notebooks"] + paths[pos + 2:])
url = repository + "/" + loc
url = url.replace("github.com", "raw.githubusercontent.com")
return Image(url, width=width)
return url


def _NbImage(url, width=None):
if isinstance(url, str):
if url.startswith('http://') or url.startswith('https://'):
with urllib_request.urlopen(url) as u:
text = u.read()
content = BytesIO(text)
return NbImage(content)
return NbImage(url, width=width)


def NbImage(*name, repository=None, force_github=False, width=None,
branch='master', row_height=200):
"""
Retrieves a name or a url of the image if it is not found in the local folder
or a subfolder.

:param name: image name (name.png) (or multiple names)
:param force_github: force the system to retrieve the image from GitHub
:param repository: repository, see below
:param width: to modify the width
:param branch: branch
:param row_height: row height if there are multiple images
:return: an `Image object
<http://ipython.org/ipython-doc/2/api/generated/IPython.core.display.html
#IPython.core.display.Image>`_

We assume the image is retrieved from a notebook.
This function will display an image even though the notebook is not run
from the sources. IPython must be installed.

if *repository* is None, then the function will use the variable
``module.__github__`` to guess the location of the image.
The function is able to retrieve an image in a subfolder.
Displays a better message if ``__github__`` was not found.

See notebook :ref:`examplenbimagerst`.
"""
from IPython.core.display import Image
if len(name) == 1:
url = _NbImage_path(
name[0], repository=repository,
force_github=force_github, branch=branch)
return Image(url, width=width)

if len(name) == 0:
raise ValueError( # pragma: no cover
"No image to display.")

from ..imghelper.img_helper import concat_images
from PIL import Image as pil_image
images = []
for img in name:
url = _NbImage_path(
img, repository=repository,
force_github=force_github, branch=branch)
if url.startswith('http://') or url.startswith('https://'):
with urllib_request.urlopen(url) as u:
text = u.read()
content = BytesIO(text)
images.append(pil_image.open(content))
else:
images.append(pil_image.open(url))

if width is None:
width = max(img.size[0] for img in images) * 2
width = max(200, width)

new_image = concat_images(images, width=width, height=row_height)
b = BytesIO()
new_image.save(b, format='png')
data = b.getvalue()
return Image(data, width=width)
Loading