|
33 | 33 | from .._freesurfer import _reorient_image, _mri_orientation |
34 | 34 | from ..utils import (logger, verbose, get_subjects_dir, warn, _ensure_int, |
35 | 35 | fill_doc, _check_option, _validate_type, _safe_input, |
36 | | - deprecated) |
| 36 | + deprecated, _check_path_like) |
37 | 37 | from ..viz import (plot_events, plot_alignment, plot_cov, plot_projs_topomap, |
38 | 38 | plot_compare_evokeds, set_3d_view, get_3d_backend) |
39 | 39 | from ..viz.misc import _plot_mri_contours, _get_bem_plotting_surfaces |
@@ -1348,6 +1348,76 @@ def add_figs_to_section(self, figs, captions, section='custom', |
1348 | 1348 | image_format=image_format, tags=tags |
1349 | 1349 | ) |
1350 | 1350 |
|
| 1351 | + def add_images(self, images, titles, *, captions=None, |
| 1352 | + tags=('custom-image',)): |
| 1353 | + """Add images (e.g., PNG or JPEG pictures) to the report. |
| 1354 | +
|
| 1355 | + Parameters |
| 1356 | + ---------- |
| 1357 | + images : path-like | collection of path-like |
| 1358 | + The images to add. |
| 1359 | + titles : str | collection of str |
| 1360 | + Title(s) corresponding to the images(s). |
| 1361 | + captions : str | collection of str | None |
| 1362 | + If not ``None``, the caption(s) to add to the image(s). |
| 1363 | + tags : collection of str |
| 1364 | + Tags to add for later interactive filtering. |
| 1365 | + """ |
| 1366 | + if _check_path_like(images): |
| 1367 | + images = (images,) |
| 1368 | + else: |
| 1369 | + images = tuple(images) |
| 1370 | + |
| 1371 | + if isinstance(titles, str): |
| 1372 | + titles = (titles,) |
| 1373 | + else: |
| 1374 | + titles = tuple(titles) |
| 1375 | + |
| 1376 | + if isinstance(captions, str): |
| 1377 | + captions = (captions,) |
| 1378 | + elif captions is None: |
| 1379 | + captions = (None,) * len(images) |
| 1380 | + else: |
| 1381 | + captions = tuple(captions) |
| 1382 | + |
| 1383 | + if len(images) != len(titles): |
| 1384 | + raise ValueError( |
| 1385 | + f'Number of images ({len(images)}) must equal number of ' |
| 1386 | + f'titles ({len(titles)})' |
| 1387 | + ) |
| 1388 | + if len(images) != len(captions): |
| 1389 | + raise ValueError( |
| 1390 | + f'Number of images ({len(images)}) must equal number of ' |
| 1391 | + f'captions ({len(captions)})' |
| 1392 | + ) |
| 1393 | + |
| 1394 | + tags = tuple(tags) |
| 1395 | + for tag in tags: |
| 1396 | + if tag not in self.tags: |
| 1397 | + self.tags.append(tag) |
| 1398 | + |
| 1399 | + for img, title, caption in zip(images, titles, captions): |
| 1400 | + img_bytes = Path(img).expanduser().read_bytes() |
| 1401 | + img_base64 = base64.b64encode(img_bytes).decode('ascii') |
| 1402 | + img_format = Path(img).suffix.lower()[1:] # omit leading period |
| 1403 | + _check_option('Image format', value=img_format, |
| 1404 | + allowed_values=('png', 'gif', 'svg')) |
| 1405 | + |
| 1406 | + dom_id = self._get_id() |
| 1407 | + img_html = _html_image_element( |
| 1408 | + img=img_base64, div_klass='custom-image', |
| 1409 | + img_klass='custom-image', title=title, caption=caption, |
| 1410 | + show=True, image_format=img_format, id=dom_id, |
| 1411 | + tags=tags |
| 1412 | + ) |
| 1413 | + self._add_or_replace( |
| 1414 | + dom_id=dom_id, |
| 1415 | + toc_entry_name=title, |
| 1416 | + tags=tags, |
| 1417 | + html=img_html |
| 1418 | + ) |
| 1419 | + |
| 1420 | + @deprecated(extra='Use `Report.add_images` instead') |
1351 | 1421 | def add_images_to_section(self, fnames, captions, scale=None, |
1352 | 1422 | section='custom', comments=None, replace=False): |
1353 | 1423 | """Append custom user-defined images. |
@@ -1375,46 +1445,14 @@ def add_images_to_section(self, fnames, captions, scale=None, |
1375 | 1445 | # Note: using scipy.misc is equivalent because scipy internally |
1376 | 1446 | # imports PIL anyway. It's not possible to redirect image output |
1377 | 1447 | # to binary string using scipy.misc. |
1378 | | - if section not in self.tags: |
1379 | | - self.tags.append(section) |
1380 | | - self._sectionvars[section] = section |
1381 | | - |
1382 | | - fnames, captions, comments = self._validate_input(fnames, captions, |
1383 | | - section, comments) |
1384 | | - _check_scale(scale) |
1385 | | - |
1386 | | - for fname, caption, comment in zip(fnames, captions, comments): |
1387 | | - caption = 'custom plot' if caption == '' else caption |
1388 | | - sectionvar = self._sectionvars[section] |
1389 | | - global_id = self._get_id() |
1390 | | - div_klass = self._sectionvars[section] |
1391 | | - img_klass = self._sectionvars[section] |
1392 | | - |
1393 | | - image_format = os.path.splitext(fname)[1][1:] |
1394 | | - image_format = image_format.lower() |
1395 | | - |
1396 | | - _check_option('image_format', image_format, ['png', 'gif', 'svg']) |
1397 | | - |
1398 | | - # Convert image to binary string. |
1399 | | - with open(fname, 'rb') as f: |
1400 | | - img = base64.b64encode(f.read()).decode('ascii') |
1401 | | - html = image_template.substitute(img=img, id=global_id, |
1402 | | - image_format=image_format, |
1403 | | - div_klass=div_klass, |
1404 | | - img_klass=img_klass, |
1405 | | - caption=caption, |
1406 | | - width=scale, |
1407 | | - comment=comment, |
1408 | | - show=True) |
1409 | | - |
1410 | | - self._add_or_replace( |
1411 | | - content_id=f'{caption}-#-{sectionvar}-#-custom', |
1412 | | - sectionvar=sectionvar, |
1413 | | - html=html, |
1414 | | - dom_id=global_id, |
1415 | | - replace=replace |
1416 | | - ) |
| 1448 | + # fnames, captions, comments = self._validate_input(fnames, captions, |
| 1449 | + # section, comments) |
| 1450 | + # _check_scale(scale) |
1417 | 1451 |
|
| 1452 | + tags = _clean_tags(section) |
| 1453 | + self.add_images(images=fnames, titles=captions, captions=comments, |
| 1454 | + tags=tags) |
| 1455 | + |
1418 | 1456 | def add_htmls_to_section(self, htmls, captions, section='custom', |
1419 | 1457 | replace=False): |
1420 | 1458 | """Append htmls to the report. |
|
0 commit comments