Skip to content

Instantly share code, notes, and snippets.

@mmmunk mmmunk/picdir-to-html.py

Last active May 15, 2020
Embed
What would you like to do?
Reads a directory of picture files and creates a single-file HTML-document including all the pictures as Base64 data inside the document
# Reads a directory of picture files and creates a single-file HTML-document including all the pictures as Base64 data inside the document
import sys
import os
import io
import math
import base64
from PIL import Image, UnidentifiedImageError
# ---------- TagBuilder ----------
def escape_tag_str(s):
s = str(s)
for c in s:
if c in '&<>':
return s.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
return s
class Tag:
def __init__(self, tagname, tagcontent=None, **kwargs):
self.name = tagname
self.content = []
self.add(tagcontent)
self.attributes = []
for k, v in kwargs.items():
if k.endswith('_'):
k = k[:-1]
if v in (False, None):
continue
elif v == True and type(v) == bool:
self.attributes.append(k)
else:
self.attributes.append('%s="%s"' % (k, str(v).replace('"', '&quot;')))
def add(self, tagcontent):
if isinstance(tagcontent, (list, tuple)):
for item in tagcontent:
self.add(item)
else:
if tagcontent != None:
self.content.append(tagcontent)
def render(self, output, preamble=None):
if preamble:
output(preamble)
output('<')
output(self.name)
for item in self.attributes:
output(' ')
output(item)
if len(self.content) > 0:
output('>')
for item in self.content:
if isinstance(item, Tag):
item.render(output)
else:
if isinstance(self, TagE):
output(escape_tag_str(item))
else:
output(str(item))
output('</')
output(self.name)
output('>')
else:
output('/>')
class TagE(Tag):
pass
# ---------- MAIN ----------
input_dir = sys.argv[1]
output_file = sys.argv[2]
fixed_pixel_count = 76800
body = Tag('body', TagE('h1', input_dir))
for fn in os.listdir(input_dir):
pfn = os.path.join(input_dir, fn)
if os.path.isfile(pfn):
try:
im = Image.open(pfn)
except UnidentifiedImageError:
continue
w = im.width
h = im.height
if w * h > fixed_pixel_count:
ar = w / h
h = round(math.sqrt((h / w) * fixed_pixel_count))
w = round(h * ar)
im = im.resize((w, h), Image.LANCZOS)
if im.mode != 'RGB':
im = im.convert('RGB')
with io.BytesIO() as b:
im.save(b, format='JPEG', quality=85, optimize=True, subsampling=2)
body.add(Tag('img', style='width: %dpx; height: %dpx;' % (im.width, im.height), src='data:image/jpeg;base64,' + base64.b64encode(b.getvalue()).decode('ascii'), alt=escape_tag_str(fn)))
head = Tag('head', (Tag('meta', charset='UTF-8'), Tag('title', 'Pictures')))
head.add(Tag('style', ('body {font-family: sans-serif; font-size: 100%;}\n', 'img {margin: 10px; vertical-align: middle;}\n')))
with open(output_file, 'w') as f:
Tag('html', (head, body)).render(f.write, '<!DOCTYPE html>\n')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.