textmachine/frontend/scripts/measure.py

81 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Замер кадра: доли поверхностей, границы панелей, высоты полос, базовые линии текста.
# Инструмент существует ради нормы «работать замером, а не на глаз» (FRONTEND_PLAN.md §5):
# каждая сессия, трогающая масштаб и зазоры, обязана привести числа, а не впечатление.
#
# python3 scripts/measure.py references/fleet.png .shots/showcase.png
#
# Оба кадра приводятся к CSS-пикселям по своему масштабу (аргумент --scale, по умолчанию 2 —
# и референс, и наш снимок сняты при deviceScaleFactor 2).
import sys
from collections import Counter
from PIL import Image
def surfaces(image, top=8):
counts = Counter(image.getdata())
total = sum(counts.values())
return [
('#%02x%02x%02x' % color, round(100 * n / total, 2)) for color, n in counts.most_common(top)
]
def runs(values, minimum=2):
"""Отрезки одинакового значения подряд: (значение, начало, длина)."""
out = []
start = 0
for index in range(1, len(values) + 1):
if index == len(values) or values[index] != values[start]:
if index - start >= minimum:
out.append((values[start], start, index - start))
start = index
return out
def column_profile(image, y):
"""Цвета вдоль горизонтального среза — так видны границы панелей и промежутки."""
return [image.getpixel((x, y)) for x in range(image.width)]
def row_profile(image, x):
return [image.getpixel((x, y)) for y in range(image.height)]
def report(path, scale):
image = Image.open(path).convert('RGB')
print(f'\n=== {path}{image.width}x{image.height} физ, {image.width // scale}x{image.height // scale} CSS ===')
print('поверхности (доля кадра):')
for color, share in surfaces(image):
print(f' {color} {share:5.2f}%')
middle = image.height // 2
# Проба берётся по центру верхней полосы, а не в углу: у референса углы окна macOS скруглены,
# и в углу лежит чёрный фон рабочего стола, а не фон оболочки.
shell = image.getpixel((image.width // 2, 2 * scale))
print('\nфон оболочки (верхняя полоса): #%02x%02x%02x' % shell)
# Горизонтальный срез по середине: отрезки фона оболочки = промежутки между панелями.
strip = column_profile(image, middle)
gaps = [(start, length) for color, start, length in runs(strip) if color == shell]
print('промежутки фона по горизонтали (CSS: начало, ширина):')
for start, length in gaps:
print(f' x={start / scale:7.1f} w={length / scale:5.1f}')
# Вертикальный срез по левому краю панели: верхняя полоса и статус-полоса.
x = gaps[0][0] + gaps[0][1] + 4 if gaps else 20
column = row_profile(image, x)
bands = [(start, length) for color, start, length in runs(column) if color == shell]
print(f'полосы фона по вертикали при x={x / scale:.1f} (CSS: начало, высота):')
for start, length in bands:
print(f' y={start / scale:7.1f} h={length / scale:5.1f}')
if __name__ == '__main__':
args = [a for a in sys.argv[1:] if not a.startswith('--')]
scale = 2
for a in sys.argv[1:]:
if a.startswith('--scale='):
scale = int(a.split('=')[1])
for path in args:
report(path, scale)