66
77from __future__ import annotations
88
9+ from binascii import a2b_base64
910from functools import lru_cache
11+ import hashlib
1012import json
13+ from mimetypes import guess_extension
1114from pathlib import Path
1215from typing import Any , Sequence
16+ import os
1317
1418from docutils import nodes
19+ from sphinx .builders import Builder
20+ from sphinx .environment import BuildEnvironment
1521from sphinx .transforms .post_transforms import SphinxPostTransform
1622from sphinx .util import logging as sphinx_logging
1723
@@ -69,7 +75,13 @@ def apply(self, **kwargs):
6975 if node .gtype == "text" :
7076 _nodes = generate_text_nodes (node , output )
7177 else :
72- _nodes = generate_any_nodes (node , output , priority_list )
78+ _nodes = generate_any_nodes (
79+ node ,
80+ output ,
81+ priority_list ,
82+ self .app .builder ,
83+ self .env ,
84+ )
7385
7486 if _nodes :
7587 node .replace_self (_nodes )
@@ -88,7 +100,11 @@ def ref_warning(msg: str, node) -> None:
88100
89101
90102def generate_any_nodes (
91- node : PendingGlueReference , output : dict [str , Any ], priority_list : Sequence [str ]
103+ node : PendingGlueReference ,
104+ output : dict [str , Any ],
105+ priority_list : Sequence [str ],
106+ builder : Builder ,
107+ env : BuildEnvironment ,
92108) -> list [nodes .Element ]:
93109 """Generate nodes for a cell, according to the highest priority mime type."""
94110 data = output ["data" ]
@@ -106,6 +122,37 @@ def generate_any_nodes(
106122 text = data [mime_type ], format = "html" , classes = ["output" , "text_html" ]
107123 )
108124 ]
125+ if mime_type in {
126+ "image/png" ,
127+ "image/jpeg" ,
128+ "image/gif" ,
129+ "application/pdf" ,
130+ }:
131+ # this is mostly a copy of mystnb/core/render.py::render_image
132+
133+ # data is b64-encoded as text
134+ data_bytes = a2b_base64 (data [mime_type ])
135+
136+ # create filename
137+ extension = guess_extension (mime_type ) or "." + mime_type .rsplit ("/" )[- 1 ]
138+ # latex does not recognize the '.jpe' extension
139+ extension = ".jpeg" if extension == ".jpe" else extension
140+
141+ data_hash = hashlib .sha256 (data_bytes ).hexdigest ()
142+ filename = f"{ data_hash } { extension } "
143+
144+ # now we resolve the relative path to the image
145+ imgdir = Path (builder .imagedir )
146+ outdir = Path (builder .outdir )
147+ page_dir = (outdir / env .docname ).parent
148+ filepath = outdir / imgdir / filename
149+
150+ uri = os .path .relpath (filepath , page_dir )
151+ image_node = nodes .image (uri = uri )
152+ image_node ["candidates" ] = {"*" : uri }
153+
154+ return [image_node ]
155+
109156 ref_warning (
110157 f"No allowed mime type found in { node .key !r} : { list (output ['data' ])} " , node
111158 )
0 commit comments