ThreadCount Community edition
Uniform stock management for healthcare linen rooms. Licensed under the GNU AGPL v3.
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate the ThreadCount Staff launcher icon.
|
||||
|
||||
python3 scripts/make-staff-icon.py
|
||||
|
||||
The two apps have to be the same family and still be telling apart on a home screen, where the
|
||||
only other clue is a truncated label. So this is the counter app's mark exactly — four stepped
|
||||
bars in the 60/48/34/22 proportions from tc-icon.svg — inverted onto ink: the leading bar keeps
|
||||
the accent, the rest go from ink to paper, and the ground goes from paper to ink.
|
||||
|
||||
Light tile versus dark tile is the strongest difference available at 48px, it costs no new
|
||||
artwork, and it stays on-brand: the app's own splash is already ink.
|
||||
|
||||
The geometry is measured from the counter app's own PNGs rather than guessed, and expressed as
|
||||
fractions of the canvas so every density comes out identical rather than merely similar. Bars are
|
||||
drawn at 4x and downsampled, which is what keeps a 43-pixel-wide bar from landing half a pixel
|
||||
off at mdpi.
|
||||
"""
|
||||
import os
|
||||
from PIL import Image
|
||||
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
RES = os.path.join(ROOT, "android-staff/app/src/main/res")
|
||||
|
||||
INK = (32, 30, 29, 255)
|
||||
PAPER = (243, 242, 242, 255)
|
||||
ACCENT = (236, 48, 19, 255)
|
||||
|
||||
# Measured from android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png (432px):
|
||||
# bars start at x=129, widths 174/139/98/64, first at y=147, pitch 40, height 23.
|
||||
FG = {
|
||||
"x0": 129 / 432,
|
||||
"widths": [174 / 432, 139 / 432, 98 / 432, 64 / 432],
|
||||
"y0": 147 / 432,
|
||||
"pitch": 40 / 432,
|
||||
"height": 23 / 432,
|
||||
}
|
||||
# Measured from .../mipmap-xxxhdpi/ic_launcher.png (192px): the legacy tile crops tighter, so the
|
||||
# mark sits larger in frame than it does inside the adaptive icon's safe zone.
|
||||
LEGACY = {
|
||||
"x0": 38 / 192,
|
||||
"widths": [116 / 192, 93 / 192, 66 / 192, 43 / 192],
|
||||
"y0": 47 / 192,
|
||||
"pitch": 27 / 192,
|
||||
"height": 21 / 192,
|
||||
}
|
||||
|
||||
SS = 4 # supersample factor
|
||||
|
||||
|
||||
def draw(size, geom, background):
|
||||
"""The mark at `size` px. `background` None gives a transparent adaptive foreground."""
|
||||
n = size * SS
|
||||
im = Image.new("RGBA", (n, n), background or (0, 0, 0, 0))
|
||||
px = Image.new("RGBA", (1, 1)) # placeholder so the linter sees px used below
|
||||
del px
|
||||
for i, wfrac in enumerate(geom["widths"]):
|
||||
x0 = round(geom["x0"] * n)
|
||||
y0 = round((geom["y0"] + i * geom["pitch"]) * n)
|
||||
w = round(wfrac * n)
|
||||
h = round(geom["height"] * n)
|
||||
# The leading bar carries the accent; the rest are paper, because the ground is now ink.
|
||||
colour = ACCENT if i == 0 else PAPER
|
||||
im.paste(colour, (x0, y0, x0 + w, y0 + h))
|
||||
return im.resize((size, size), Image.LANCZOS)
|
||||
|
||||
|
||||
DENSITIES = {"mdpi": (48, 108), "hdpi": (72, 162), "xhdpi": (96, 216), "xxhdpi": (144, 324), "xxxhdpi": (192, 432)}
|
||||
|
||||
|
||||
def main():
|
||||
if not os.path.isdir(RES):
|
||||
raise SystemExit(f"no android-staff res dir at {RES}")
|
||||
for density, (legacy_px, fg_px) in DENSITIES.items():
|
||||
d = os.path.join(RES, f"mipmap-{density}")
|
||||
os.makedirs(d, exist_ok=True)
|
||||
|
||||
draw(fg_px, FG, None).save(os.path.join(d, "ic_launcher_foreground.png"))
|
||||
tile = draw(legacy_px, LEGACY, INK)
|
||||
tile.save(os.path.join(d, "ic_launcher.png"))
|
||||
# The launcher applies its own mask, so the round variant is the same tile — which is what
|
||||
# the counter app ships too.
|
||||
tile.save(os.path.join(d, "ic_launcher_round.png"))
|
||||
print(f" {density}: foreground {fg_px}px, launcher {legacy_px}px")
|
||||
|
||||
bg = os.path.join(RES, "values/ic_launcher_background.xml")
|
||||
with open(bg, "w", encoding="utf-8") as f:
|
||||
f.write('<?xml version="1.0" encoding="utf-8"?>\n<resources>\n'
|
||||
' <!-- Ink, where the counter app is paper. This is what tells the two apps\n'
|
||||
' apart on a home screen. -->\n'
|
||||
' <color name="ic_launcher_background">#201E1D</color>\n</resources>\n')
|
||||
print(f" background -> #201E1D")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user