Skip to main content

webapp/server.py

1#!/usr/bin/env python
3import base64
4import os
5import secrets
6import subprocess
7import sys
8import tempfile
10from flask import Flask, flash, redirect, render_template, request
11import wcag_contrast_ratio as contrast
14app = Flask(__name__)
15app.secret_key = secrets.token_hex()
18VERSION = subprocess.check_output(["dominant_colours", "--version"]).decode("utf8")
21@app.route("/")
22def index():
23 return render_template("index.html", version=VERSION)
26@app.template_filter("usable_colours")
27def usable_colours(colours):
28 result = []
30 for hex_string in colours:
31 r = red(hex_string)
32 g = green(hex_string)
33 b = blue(hex_string)
35 ratio = contrast.rgb((r / 255, g / 255, b / 255), (1, 1, 1))
37 if contrast.passes_AA(ratio):
38 result.append(hex_string)
40 return result
43@app.template_filter("red")
44def red(hex_string):
45 return int(hex_string[1:3], 16)
48@app.template_filter("green")
49def green(hex_string):
50 return int(hex_string[3:5], 16)
53@app.template_filter("blue")
54def blue(hex_string):
55 return int(hex_string[5:7], 16)
58@app.route("/palette", methods=["GET", "POST"])
59def get_palette():
60 if request.method == "GET":
61 return redirect("/")
63 if request.method == "POST":
64 uploaded_file = request.files["file"]
65 _, extension = os.path.splitext(uploaded_file.filename)
67 with tempfile.NamedTemporaryFile(suffix=extension) as tmp_file:
68 uploaded_file.save(tmp_file)
70 # If we don't flush here, the file may be incomplete. This can
71 # lead to errors like:
72 #
73 # failed to fill whole buffer
74 #
75 # when running dominant_colours.
76 tmp_file.flush()
78 proc = subprocess.Popen(
79 ["dominant_colours", tmp_file.name, "--no-palette", "--max-colours=5"],
80 stdout=subprocess.PIPE,
81 stderr=subprocess.PIPE,
82 )
83 stdout, stderr = proc.communicate()
84 return_code = proc.poll()
86 if return_code != 0:
87 stderr = stderr.decode(sys.stdin.encoding)
88 flash(f"Something went wrong:<br/>{stderr}")
89 return redirect("/")
91 stdout = stdout.decode(sys.stdin.encoding)
92 colours = stdout.strip().split("\n")
94 with tempfile.NamedTemporaryFile(suffix="jpg") as thumbnail_file:
95 subprocess.check_call(
96 [
97 "convert",
98 tmp_file.name,
99 "-resize",
100 "600x600",
101 thumbnail_file.name,
102 ]
103 )
104 thumbnail_file.seek(0)
105 thumbnail = thumbnail_file.read()
107 thumbnail_data_uri = (
108 b"data:image/jpg;base64," + base64.b64encode(thumbnail)
109 ).decode("ascii")
111 return render_template(
112 "palette.html",
113 colours=colours,
114 thumbnail_data_uri=thumbnail_data_uri,
115 version=VERSION,
116 )
119if __name__ == "__main__":
120 app.run(debug=True, host="0.0.0.0", port=4711)