misc-fred/bin/compare_them_all.py

121 lines
4.2 KiB
Python

# -*- coding: utf-8 -*-
#
# Compare desktop/mobile shots of all themes from publik-base-theme.
#
# Usage:
# --input1-directory -- directory to find version 1 screenshots
# --input2-directory -- directory to find version 2 screenshots
# --output-directory DIRECTORY -- directory to store comparison results, defaults to results/
# --overlay OVERLAY -- limit to given overlay ("none" to exclude overlays)
# --theme THEME -- theme to shot (substring match)
#
# Example:
# hobo-manage tenant_command runscript compare_them_all.py -d hobo.fred.local.0d.be
#
import argparse
import os
import sys
from hobo.theme.utils import get_themes
from django.template import Template, Context
from PIL import Image, ImageDraw
parser = argparse.ArgumentParser()
parser.add_argument('--input1-directory', dest='input1_directory', type=str, required=True)
parser.add_argument('--input2-directory', dest='input2_directory', type=str, required=True)
parser.add_argument('--output-directory', dest='output_directory', type=str, default='results')
parser.add_argument('--overlay', dest='overlay', type=str, default='none')
parser.add_argument('--theme', dest='theme', type=str)
args = parser.parse_args()
if not os.path.exists(args.output_directory):
os.mkdir(args.output_directory)
result = []
for theme in get_themes():
theme_id = theme['id']
if args.overlay == 'all':
pass
elif args.overlay == 'none' and not theme.get('overlay'):
pass
elif args.overlay == theme.get('overlay'):
pass
else:
continue
if args.theme and args.theme not in theme['id']:
continue
sys.stderr.write("%-25s" % theme_id)
shots = [
'desktop',
'mobile',
'mobile-horizontal',
]
def process_region(image, x, y, width, height):
region_total = 0
# This can be used as the sensitivity factor, the larger it is the less sensitive the comparison
factor = 100
for coordinate_y in range(y, y + height):
for coordinate_x in range(x, x + width):
try:
pixel = image.getpixel((coordinate_x, coordinate_y))
region_total += sum(pixel) / 4
except Exception:
return
return region_total / factor
theme_data = {
'label': theme['label'],
'shots': [],
}
for shot in shots:
filepath_1 = os.path.join(args.input1_directory, '%s-%s.png' % (theme_id, shot))
filepath_2 = os.path.join(args.input2_directory, '%s-%s.png' % (theme_id, shot))
filepath_output = os.path.join(args.output_directory, '%s-%s.png' % (theme_id, shot))
try:
screenshot_1 = Image.open(filepath_1)
screenshot_2 = Image.open(filepath_2)
except FileNotFoundError:
continue
width, height = screenshot_1.size
columns = 60
rows = 80
screen_width, screen_height = screenshot_1.size
block_width = ((screen_width - 1) // columns) + 1
block_height = ((screen_height - 1) // rows) + 1
for y in range(0, screen_height, block_height + 1):
for x in range(0, screen_width, block_width + 1):
region_1 = process_region(screenshot_1, x, y, block_width, block_height)
region_2 = process_region(screenshot_2, x, y, block_width, block_height)
if region_1 is not None and region_2 is not None and region_1 != region_2:
draw = ImageDraw.Draw(screenshot_1)
draw.rectangle((x, y, x + block_width, y + block_height), outline="red")
screenshot_1.save(filepath_output)
theme_data['shots'].append({
'label': shot,
'width': width,
'height': height,
'before': '../%s' % filepath_1,
'after': '../%s' % filepath_2,
'diff': '../%s' % filepath_output,
})
result.append(theme_data)
sys.stderr.write(u'\n')
with open('index_template.html', 'r') as f:
template = Template(f.read())
context = Context({'themes': result})
html = template.render(context)
with open(os.path.join(args.output_directory, 'index.html'), 'w') as f:
f.write(html)