Skip to content

Commit 32f4db5

Browse files
committed
Write plot images as WebP instead of PNG
Plots are exported at ~1500x1500, and the page now ships 100+ of them. Re-encoding the notebook's PNG output as quality-85 WebP cuts the image payload from 8.5 MB to 2.6 MB with no visible loss. Filenames keep the MD5-of-base64 scheme so unchanged plots keep their URLs. image_from_cell now also returns the pixel dimensions, which the template uses to reserve layout space.
1 parent b5168a8 commit 32f4db5

1 file changed

Lines changed: 20 additions & 5 deletions

File tree

‎render.py‎

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import subprocess
1212
import base64
1313
import hashlib
14+
import io
15+
from PIL import Image
1416

1517

1618
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
@@ -49,18 +51,29 @@
4951
intro = f.read()
5052

5153

54+
WEBP_QUALITY = 85
55+
56+
5257
def image_from_cell(cell):
58+
"""Save the cell's PNG output as WebP and return its path and pixel size.
59+
60+
The filename stays the MD5 of the base64 PNG, so a plot that hasn't changed
61+
keeps its URL. The pixel size lets the template declare width/height, which
62+
reserves layout space for the lazily loaded images.
63+
"""
5364
try:
5465
for c in cell['outputs']:
5566
if 'data' in c and 'image/png' in c['data']:
5667
base64_img = c['data']['image/png'].replace("\n", "").strip()
5768
filename = hashlib.md5()
5869
filename.update(base64_img.encode('ascii'))
59-
web_path = "/img/plots/{}.png".format(filename.hexdigest())
70+
web_path = "/img/plots/{}.webp".format(filename.hexdigest())
6071
full_path = "web" + web_path
61-
with open(full_path, "wb") as fh:
62-
fh.write(base64.b64decode(base64_img))
63-
return web_path
72+
image = Image.open(io.BytesIO(base64.b64decode(base64_img)))
73+
if image.mode not in ("RGB", "RGBA"):
74+
image = image.convert("RGBA")
75+
image.save(full_path, "WEBP", quality=WEBP_QUALITY, method=6)
76+
return {"path": web_path, "width": image.width, "height": image.height}
6477
except KeyError as e:
6578
logging.error("Can't find image in cell: %s", cell['source'])
6679
raise e
@@ -145,7 +158,9 @@ def extract_cells(path):
145158
"cell_num": cell_num,
146159
"package": packages.get(tags["package"], tags["package"]),
147160
"package-slug": tags['package'],
148-
"image": image,
161+
"image": image["path"],
162+
"image-width": image["width"],
163+
"image-height": image["height"],
149164
"content": source,
150165
"comment": md.convert(comment) or None,
151166
})

0 commit comments

Comments
 (0)