geojs/scripts/make_thumbnails.py
2022-01-14 15:01:55 -05:00

170 lines
6.3 KiB
Python
Executable File

#!/usr/bin/env python
# NOTE: If this doesn't work, it may be related to a policy in
# /etc/ImageMagick-6/policy.xml
# Specifically, disable
# <policy domain="coder" rights="none" pattern="PS" />
# by removing it or commenting it out.
import json
import os
import psutil
import signal
import six
import subprocess
import sys
import time
OriginalSize = (1200, 900)
ExtraSpace = 1 # 1, otherwise we get a black border on the bottom and right
NavbarHeight = 60
FinalSize = (800, 600)
InitialDelay = 15 # in seconds
MaxDelay = 30 # in seconds
Quality = 90
OutputFile = 'thumb.jpg'
InputList = ['examples', 'tutorials']
BrowserCommand = [
'xvfb-run', '-s', '-ac -screen 0 %dx%dx24' % (
OriginalSize[0] + ExtraSpace, OriginalSize[1] + ExtraSpace + NavbarHeight),
'google-chrome', '--kiosk', '--no-pings', '--device-scale-factor=1',
'--incognito', '--start-fullscreen', '--no-default-browser-check',
'--user-data-dir=/tmp/chrome_geojs_thumbnails', '--no-first-run',
'--disable-default-apps', '--disable-popup-blocking',
'--disable-translate', '--disable-background-timer-throttling',
'--disable-renderer-backgrounding',
'--disable-device-discovery-notifications',
'--window-position=0,0',
]
BrowserCommandSize = [
'--window-size=%d,%d' % (OriginalSize[0] + ExtraSpace, OriginalSize[1] + ExtraSpace),
]
BrowserCommandSizeIgnoreNavbar = [
'--window-size=%d,%d' % (
OriginalSize[0] + ExtraSpace, OriginalSize[1] + ExtraSpace + NavbarHeight),
]
BrowserUrl = 'http://127.0.0.1:30100/%s'
ImageCommand = (
'DISPLAY=:99.0 import -window root -crop %dx%d+0+0 +repage - | '
'convert - -resize %dx%d -quality %d ' % (
OriginalSize[0], OriginalSize[1], FinalSize[0], FinalSize[1], Quality))
ImageCommandIgnoreNavbar = (
'DISPLAY=:99.0 import -window root -crop %dx%d+0+%d +repage - | '
'convert - -resize %dx%d -quality %d ' % (
OriginalSize[0], OriginalSize[1], NavbarHeight, FinalSize[0], FinalSize[1], Quality))
def process_item(path, opts):
output = (open('/tmp/thumbnail.out', 'a')
if opts.get('verbose', 0) >= 1 else open(os.devnull, 'w'))
data = json.load(open(path))
if data.get('disabled') and not opts.get('all'):
return
dest = os.path.join(os.path.dirname(path), OutputFile)
if os.path.exists(dest) and not opts.get('force'):
return
originalSize = 0
if os.path.exists(dest):
originalSize = os.path.getsize(dest)
sys.stdout.write('\r%s %d' % (path, originalSize))
sys.stdout.flush()
if opts.get('simulate'):
dest = os.path.join('/tmp', os.path.basename(os.path.dirname(
os.path.dirname(path))) + '_' + os.path.basename(os.path.dirname(
path)) + '_' + OutputFile)
if os.path.exists(dest):
os.unlink(dest)
cmd = list(BrowserCommand)
imgcmd = ImageCommand
if 'example.json' in path and not data.get('hideNavbar'):
cmd.extend(BrowserCommandSizeIgnoreNavbar)
imgcmd = ImageCommandIgnoreNavbar
else:
cmd.extend(BrowserCommandSize)
url = BrowserUrl % os.path.dirname(path)
if data.get('thumbquery'):
url += '?' + data['thumbquery']
cmd.append(url)
output.write('--> %r\n' % (cmd, ))
output.write(' %s\n' % (' '.join([six.moves.shlex_quote(arg) for arg in cmd])))
proc = subprocess.Popen(cmd, shell=False, stdout=output, stderr=output)
delay = opts.get('delay', InitialDelay)
startTime = time.time()
time.sleep(delay)
lastSize = 0
while True:
output.write('--> %r\n' % (imgcmd + six.moves.shlex_quote(dest), ))
subprocess.Popen(
imgcmd + six.moves.shlex_quote(dest), shell=True,
stdout=output, stderr=output).wait()
newSize = os.path.getsize(dest)
if newSize and newSize == lastSize:
break
if time.time() - startTime > opts.get('maxdelay', MaxDelay):
break
lastSize = newSize
sys.stdout.write('\r%s %d %d ' % (path, originalSize, newSize))
sys.stdout.flush()
time.sleep(0.5)
for child in psutil.Process(proc.pid).children(recursive=True):
try:
child.send_signal(signal.SIGINT)
except psutil.NoSuchProcess:
pass
os.kill(proc.pid, signal.SIGINT)
proc.wait()
sys.stdout.write('\n')
if __name__ == '__main__': # noqa
opts = {'force': False, 'verbose': 0}
for arg in sys.argv[1:]:
if arg in ('-a', '--all'):
opts['all'] = True
elif arg.startswith('--delay='):
opts['delay'] = float(arg.split('=', 1)[1])
elif arg == '--force':
opts['force'] = True
elif arg.startswith('--maxdelay='):
opts['maxdelay'] = float(arg.split('=', 1)[1])
elif arg.startswith('--only='):
opts['only'] = arg.split('=', 1)[1]
elif arg in ('-s', '--simulate'):
opts['simulate'] = True
elif arg in ('-v', '--verbose'):
opts['verbose'] += 1
else:
opts['help'] = True
if opts.get('help'):
print("""
Regenerate thumbnails for examples and tutorials.
Syntax: make_thumbnails.py --force --simulate --only=(substr) --all
--delay=(seconds) --maxdelay=(seconds)
Run in the root geojs directory.
--all or -a generates thumbnails for disabled examples, too.
--delay is the duration after the web browser is started before a thumbnail
snapshot might be taken. The thumbnail is only taken after the webpage hasn't
changed for a short duration.
--force regenerates all thumbnails. Otherwise, only missing thumbnails are
created.
--maxdelay is the longest to wait before taking the snapshot. This will happen
even if the webpage is still changing.
--only will only process examples or tutorials whose name contains the
specified substring.
--simulate or -s determines the size of thumbnails that would be created but
doesn't make them.
""")
sys.exit(0)
for inputdir in InputList:
for root, dirs, files in os.walk(inputdir):
dirs.sort()
for dir in dirs:
for name in ['example.json', 'tutorial.json']:
path = os.path.join(root, dir, name)
if opts.get('only') and not opts['only'] in path:
continue
if os.path.exists(path):
process_item(path, opts)