mknotebooks icon indicating copy to clipboard operation
mknotebooks copied to clipboard

Notebook with multiple inline images only renders one for all

Open dacort opened this issue 4 years ago • 1 comments

I have a notebook in which I've pasted multiple images.

Unfortunately, each image has the same name. And due to this code that extracts the attachments, each image is overwritten with the same name until the last one.

Looks like there's not a way to correct this in Jupyter itself...this issue is still open. So I guess the only options are to pre-process the notebook manually or somehow fix it up in here.

I should note that nbconvert seems to support this fine as it uses inline, base64 images.

multi_image.ipynb.zip

dacort avatar Jul 12 '21 18:07 dacort

I managed to workaround this by just writing a quick script to replace all image.png attachments with an incremented version.

import argparse
import json
import sys
from io import TextIOWrapper


def init_argparse() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        description="Uniquify images in a Jupyter Notebook.",
    )
    parser.add_argument(
        "-v", "--version", action="version", version=f"{parser.prog} version 1.0.0"
    )
    parser.add_argument("infile", type=argparse.FileType("r"))
    parser.add_argument(
        "outfile", nargs="?", type=argparse.FileType("w"), default=sys.stdout
    )
    return parser


def uniquify_images(input_file: TextIOWrapper, output_file: TextIOWrapper):
    data = json.loads(input_file.read())
    counter = 0
    for cell in data["cells"]:
        if cell.get("cell_type") != "markdown":
            continue
        if cell.get("attachments") and cell.get("attachments").get("image.png"):
            filename = f"image_{counter:03}.png"
            cell["attachments"][filename] = cell["attachments"].pop("image.png")
            cell["source"] = [
                t.replace("(attachment:image.png)", f"(attachment:{filename})")
                for t in cell["source"]
            ]
            counter += 1

    output_file.write(json.dumps(data, indent=1))


def main() -> None:
    parser = init_argparse()
    args = parser.parse_args()
    uniquify_images(args.infile, args.outfile)


main()

Run with:

python convert.py docs/image_book.ipynb docs/image_book_new.ipynb

Works for my specific use-case. :)

dacort avatar Jul 12 '21 23:07 dacort