jupyter中复制粘贴形式插入的图片(attachment)导出md时不显示

Jupyter中以复制粘贴的形式插入的图片(attachment)导出到md时不显示问题的解决办法(转换为网络图片)

问题描述

本人编写Jupyter Notebook的时候,经常参考其他网站或者书中的图片,因此常常将相应的截图粘贴到Jupyter Notebook Jupyter Lab中,但是当需要导出为markdown的时候发现导出后图片无法显示。

例如,将截图直接粘贴到jupytermarkdown单元格中时,直接粘贴的结果如下图所示

image-20230202205137712

运行后显示正确图片

image-20230202205154445

但是,当将Jupyter Notebook导出为markdown后,在markdown文件中无法正确显示

image-20230202205311442

经过查询得知,在Jupyter以粘贴截图的方式插入图片,图片实际是以附件的方式存储在jupyter中。

vscode打开此ipynb文件,并右键点击Reopen Editor With,选中Text Editor模式,可以看到实际上ipynb是以json格式存储的文本文件(用记事本打开也可以)。

其中此图片对应的cell部分为:

image-20230202205038953

而更换为网络链接后就可以正常显示了,此时对应的cell

image-20230202205657384

扫描二维码关注公众号,回复: 16248192 查看本文章

因此,只需要将所有的attachments方式粘贴的图片转换为网络链接,然后再导出到md中就可以正常显示了。

前提:配置Picgo图床服务

本人利用Typora编辑笔记,并结合Picgo设置了图片自动上传机制,选择的是腾讯云cos对象存储服务。

这不是本文的重点,可以参考下面的博客进行设置,本文的方法只要通过Picgo设置了自动上传服务即可,不一定必须是腾讯云。

手把手教你Typora图床配置(PicGo+阿里云OSS/腾讯云COS)_孙不坚1208的博客-CSDN博客

处理程序详解

代码思路如下:

  • 首先以json格式打开文件
  • 遍历cell,其中有attachments的就是我们的处理对象
  • cellsource部分存储图片附件的名称,因此一次提取各个附件名称,在attachments中找到对应base64数据
  • 将图片数据通过Picgo的默认接口36677上传,返回值为上传后的图片网络链接,替换json文件中图片为在线图片。
  • 删除原json文件中attachments部分。
  • json数据写回文件
"""
将jupyter 的 markdown单元格中以复制粘贴形式插入的图片转换成图床图片
![image.png](attachment:cc48e68c-db89-4481-9f84-9900c4759344.png)  ----> ![png](https://***.png)
""" 
import os
import re
import json
import fire
import base64
import requests

headers = {
    
    'Content-Type':'application/json'}

    
def get_json_data(filename):
    dicts = {
    
    }
    with open(filename, 'r', encoding = 'utf-8') as f:
        ipynb_content = json.load(f)
        cells = ipynb_content["cells"]
        for cell in cells:
            sources = cell['source']
            if "attachments" in cell:
                attachments = cell['attachments']
                for idx, source in enumerate(sources):
                    attachment = 0
                    while(True):
                        attachment = source.find('attachment:', attachment)
                        if attachment==-1:
                            break
                        imageidx = attachment + 11
                        rbracket = source.find(')', imageidx)
                        imagename = source[imageidx:rbracket]
                        print(imagename)
                        value = attachments[imagename]
                        for data_type, base64data in value.items(): # 其实应该就一个key,valule
                            if "image" in data_type:  # image/png  image/jpeg
                                # print (key, data_type, base64data[:10])
                                pic_data = base64.b64decode(base64data)
                                if "png" in data_type:
                                    with open('temp.png', 'wb')as f:
                                        f.write(pic_data)
                                if "jpeg" in data_type:
                                    with open('tmp.jpeg', 'wb') as f:
                                        f.write(pic_data)
                                cur_path = os.path.abspath('./temp.png')
                                datas = json.dumps({
    
    'list': [cur_path]})
                                response = requests.post('http://127.0.0.1:36677/upload', data=datas, headers=headers)
                                result = response.json()['result']
                                # print(result[0])

                                url = result[0]
                                print(url)

                                print(source[attachment:rbracket])
                                sources[idx] = source.replace(source[attachment:rbracket],url)
                                # print(sources[idx])
                        attachment = rbracket + 1
                cell.pop('attachments')
                # print(cell)
        ipynb_content['cells'] = cells
        # dicts = ipynb_content
    with open(filename, 'w', encoding = 'utf-8') as w:
        # print(dicts)
        json.dump(ipynb_content, w, indent = 1, ensure_ascii=False)
        
if __name__ == '__main__':
    fire.Fire(get_json_data)

运行示例

运行前首先要开启picgo应用,否则无法使用其上传服务。

本程序使用的是picgo的上传服务,只要picgo中配置好了图床,均可使用

image-20230202224523082

上图所示的ipynb文件中有两个png图片,一个jpeg图片,均为复制粘贴形式插入,均成功转换为在线链接,导出md后均可正常显示。

image-20230202225259255

附:其他方式插入的图片导出问题

  • 如果是利用matplotlib生成的图片导出md时,会以压缩包的形式导出,图片以压缩包内的相对路径形式在md中引用,此时利用typora的一键上传本地图片的功能也可以转换为在线链接。具体点击"格式"——“图像”——“上传所有本地图像”

  • 其他的方式比如标签,无论是绝对路径还是相对路径插入的本地图片,也都可以在导出为md后,利用配置好的typora+picgo上传服务转换为在线链接。

上传本地图片的功能也可以转换为在线链接。具体点击"格式"——“图像”——“上传所有本地图像”

  • 其他的方式比如标签,无论是绝对路径还是相对路径插入的本地图片,也都可以在导出为md后,利用配置好的typora+picgo上传服务转换为在线链接。

猜你喜欢

转载自blog.csdn.net/jinniulema/article/details/128858938