nbconvert: attached image in ipynb not shown in html

image_test.ipynb.zip I tried converting this simple notebook with python -m nbconvert docs/notebooks/image_test.ipynb running nbconvert 5.3.1 . The notebook contains one markdown cell with a single line ![image.png](attachment:image.png) But the image does not show up in the resulting html, only a cell with text ‘image.png’ in it. (attachment:image.png). The image works in the notebook so it seems correctly embedded. Is this not supported? It’s an important feature for me so any help would be really useful. Thanks in advance

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 29
  • Comments: 19 (5 by maintainers)

Most upvoted comments

Have wrapped it together so anybody can immediately use it:

Usage: ipy2html.py filename.ipynb [--slides]

ipy2html.py.gz

For what it’s worth, fixing up the HTML post-conversion manually is also pretty straightforward: Assuming that all attachment filenames are unique, you could do something like

import nbconvert
import nbformat

with open('my_notebook.ipynb') as nb_file:
    nb_contents = nb_file.read()

# Convert using the ordinary exporter
notebook = nbformat.reads(nb_contents, as_version=4)
exporter = nbconvert.HTMLExporter()
body, res = exporter.from_notebook_node(notebook)

# Create a dict mapping all image attachments to their base64 representations
images = {}
for cell in notebook['cells']:
    if 'attachments' in cell:
        attachments = cell['attachments']
        for filename, attachment in attachments.items():
            for mime, base64 in attachment.items():
                images[f'attachment:{filename}'] = f'data:{mime};base64,{base64}'

# Fix up the HTML and write it to disk
for src, base64 in images.items():
    body = body.replace(f'src="{src}"', f'src="{base64}"')
with open('my_notebook.html', 'w') as output_file:
    output_file.write(body)

Of course, this does nothing to actually fix the bug. Without being able to claim much of an overview of how rendering occurs, it seems like you would want to somehow take this into account in the filter nbconvert.html.HTMLExporter.markdown2html (which does not see the NotebookNode itself, but if you don’t mind adding this as state, you could do so in from_notebook_node).

Hello guys. Thanks for your workaround code snippets.

I slightly changed @platise’s code which can handle multiple non-unique attachments.

import nbformat
import nbconvert
import sys

if len(sys.argv) < 2:
    print("Usage:", sys.argv[0], 'filename.ipynb', '[--slides]')
    exit(-1)

with open(sys.argv[1]) as nb_file:
    nb_contents = nb_file.read()

# Convert using the ordinary exporter
notebook = nbformat.reads(nb_contents, as_version=4)
if len(sys.argv) == 3 and sys.argv[2] == '--slides':
    outname = sys.argv[1].split('.ipynb')[0] + '.slides.html'
    print("Converting to slides:", outname)    
    exporter = nbconvert.SlidesExporter()    
else:
    outname = sys.argv[1].split('.ipynb')[0] + '.html'
    print("Converting to HTML:", outname)
    exporter = nbconvert.HTMLExporter()
    
body, res = exporter.from_notebook_node(notebook)

# Create a list saving all image attachments to their base64 representations
images = []
for cell in notebook['cells']:
    if 'attachments' in cell:
        attachments = cell['attachments']
        for filename, attachment in attachments.items():
            for mime, base64 in attachment.items():
                images.append( [f'attachment:{filename}', f'data:{mime};base64,{base64}'] )

# Fix up the HTML and write it to disk
for itmes in images:
    src = itmes[0]
    base64 = itmes[1]
    body = body.replace(f'src="{src}"', f'src="{base64}"', 1)
    
with open(outname, 'w') as output_file:
    output_file.write(body)

The usage is same.

ipy2html.py

I needed this, so I wrote a pre-processor to extract attached images and put them in the outputs, which is used for images in the output part of a code cell.

It has been working well for me.

https://gist.github.com/sglyon/5687b8455a0107afc6f4c60b5f313670

Thanks @imcomking for upgrade, works well! and also handles exports where Embedded HTML doesn’t work, with ref to @tonycpsu

No problem.

My usage was as follows

from traitlets.config import Config
import nbformat
import nbconvert


def to_pdf(ipynb_path)
    c = Config()
    my_preprocesors = [ExtractAttachmentsPreprocessor]
    c.PDFExporter.preprocessors = my_preprocesors
    c.LatexExporter.preprocessors = my_preprocesors

    exporter = nbconvert.PDFExporter(config=c, extra_loaders=[dl])
    writer = nbconvert.writers.FilesWriter()

    nb = nbformat.read(ipynb_path, as_version=4)

    (body, resources) = exporter.from_notebook_node(nb, resources=resources)
    writer.write(body, resources, "output.pdf")