1
1
"""Nbconvert preprocessor for the python-markdown nbextension."""
2
2
3
3
from nbconvert .preprocessors import Preprocessor
4
- from traitlets import Bool , Float
4
+ from traitlets import Bool , Float , Unicode
5
5
import re
6
6
import os
7
7
import base64
@@ -38,17 +38,23 @@ class EmbedImagesPreprocessor(Preprocessor):
38
38
to additionally embeds all images referenced by an url (e.g. http://jupyter.org/assets/nav_logo.svg) instead
39
39
of a local file name. Also
40
40
41
- EmbedImagesPreprocessor.dpi_scaling
41
+ EmbedImagesPreprocessor.resize=small
42
42
43
- Let's you scale the size of an image. This is interesting if you want to save space by not embedding large
43
+ Let's you scale-down the size of an image. This is useful if you want to save space by not embedding large
44
44
images and instead use a smaller (scaled) version. Works only for raster images (i.e. png, jpg).
45
+ Valid resize settings are: small = 500px, mid = 1000px, large = 2000px for maximum size in length or width
46
+ No upscaling of small images will be performed.
47
+
48
+ Example::
49
+
50
+ $ jupyter nbconvert --to html --EmbedImagesPreprocessor.embed_images=True --EmbedImagesPreprocessor.scale=large mynotebook.ipynb
45
51
46
52
*Note:* To embed images after conversion to HTML you can also use the `html_embed` exporter
47
53
"""
48
54
49
55
embed_images = Bool (False , help = "Embed images as attachment" ).tag (config = True )
50
56
embed_remote_images = Bool (False , help = "Embed images referenced by an url as attachment" ).tag (config = True )
51
- dpi_scaling = Float ( 0 , help = "Resize images to a certain DPI number (reduce size)" ).tag (config = True )
57
+ resize = Unicode ( '' , help = "Resize images to save space (reduce size)" ).tag (config = True )
52
58
53
59
def preprocess (self , nb , resources ):
54
60
"""Skip preprocessor if not enabled"""
@@ -59,7 +65,7 @@ def preprocess(self, nb, resources):
59
65
def replfunc_md (self , match ):
60
66
"""Read image and store as base64 encoded attachment"""
61
67
url = match .group (2 )
62
- imgformat = url .split ('.' )[- 1 ]
68
+ imgformat = url .split ('.' )[- 1 ]. lower ()
63
69
if url .startswith ('http' ):
64
70
if self .embed_remote_images :
65
71
data = urlopen (url ).read ()
@@ -72,6 +78,30 @@ def replfunc_md(self, match):
72
78
with open (filename , 'rb' ) as f :
73
79
data = f .read ()
74
80
81
+ # resize settings: small -> 500px, mid -> 1000px, large -> 200px
82
+ imgsizes = {'small' : 500 , 'mid' : 1000 , 'large' : 2000 }
83
+ if self .resize in imgsizes .keys () and imgformat in ['png' , 'jpg' ]:
84
+ from io import BytesIO
85
+ try :
86
+ from PIL import Image
87
+ except ImportError :
88
+ self .log .info ("Pillow library not available to resize images" )
89
+ Image = None
90
+ if Image :
91
+ # Only make images smaller when rescaling
92
+ im = Image .open (BytesIO (data ))
93
+ size = im .size
94
+ factor = imgsizes [self .resize ]/ max (size )
95
+ if factor < 1.0 :
96
+ newsize = ( int (size [0 ]* factor ), int (size [1 ]* factor ))
97
+ newim = im .resize (newsize )
98
+ fp = BytesIO ()
99
+ newim .save (fp , format = imgformat .replace ('jpg' , 'jpeg' )) # PIL requires JPEG instead of JPG
100
+ data = fp .getvalue ()
101
+ fp .close ()
102
+ self .log .debug ("Resized %d x %d image %s to size %d x %d pixels" %
103
+ (size [0 ], size [1 ], url , newsize [0 ], newsize [1 ]) )
104
+
75
105
self .log .debug ("embedding url: %s, format: %s" % (url , imgformat ))
76
106
b64_data = base64 .b64encode (data ).decode ("utf-8" )
77
107
self .attachments [url ] = { 'image/' + imgformat : b64_data }
0 commit comments