#!/usr/bin/env python3 """ Готовит модуль с данными значков из файлов в icons_online. Зачем модулем, а не файлами рядом с программой: программа не должна зависеть от того, лежит ли что-то в её каталоге. Значки маленькие, все вместе занимают единицы килобайт. Размер выбран под кнопку: у неё двадцать восемь точек стороны, значку достаётся клетка двадцать четыре на двадцать четыре. Уменьшение делает convert с обычным сглаживанием, пропорции при этом сохраняются — все исходники квадратные, растягивать нечего. Запуск: python3 tools/make_icons.py """ import subprocess import sys from pathlib import Path ROOT = Path(__file__).resolve().parent.parent SRC = ROOT / 'icons_online' OUT = ROOT / 'src' / 'uIconData.pas' # Имя в программе -> файл исходника и сторона в точках. # Для «схлопывания» берётся вариант на шестьдесят четыре точки: чем крупнее # исходник, тем чище получается уменьшение. ICONS = [ ('Snap', 'icons8-магнит-30.png', 24), ('Ripple', 'icons8-merge-vertical-64.png', 24), ('Log', 'icons8-property-30.png', 24), ('Glue', 'icons8-клей-30.png', 24), ('Target', 'icons8-цель-30.png', 24), ('SelectClips', 'icons8-select-all-90.png', 24), ('SelectRange', 'icons8-width-90.png', 24), ] # Значок самой программы: отдельно, потому что окну нужен формат ico — # только его умеет читать TIcon в LCL. APP_ICON = ('icons8-показ-видеокадров-30.png', 32) def make_ico(path: Path, side: int) -> bytes: out = subprocess.run( ['convert', str(path), '-background', 'none', '-alpha', 'on', '-resize', '%dx%d' % (side, side), 'ico:-'], check=True, capture_output=True) return out.stdout def scale(path: Path, side: int) -> bytes: out = subprocess.run( ['convert', str(path), '-background', 'none', '-alpha', 'on', '-resize', '%dx%d' % (side, side), 'png:-'], check=True, capture_output=True) return out.stdout def pascal_bytes(data: bytes, indent: str = ' ') -> str: parts = [] for i in range(0, len(data), 16): chunk = ', '.join('$%02X' % b for b in data[i:i + 16]) parts.append(indent + chunk) return ',\n'.join(parts) def main() -> int: if not SRC.is_dir(): print('нет каталога с исходниками:', SRC, file=sys.stderr) return 1 blocks = [] names = [] for name, filename, side in ICONS: path = SRC / filename if not path.is_file(): print('нет файла:', path, file=sys.stderr) return 1 data = scale(path, side) names.append((name, len(data))) blocks.append( ' { %s, %d на %d точек }\n' ' Icon%sData: array[0..%d] of Byte = (\n%s\n );' % (filename, side, side, name, len(data) - 1, pascal_bytes(data))) app_src, app_side = APP_ICON app_path = SRC / app_src if not app_path.is_file(): print('нет файла:', app_path, file=sys.stderr) return 1 app_data = make_ico(app_path, app_side) names.append(('App (ico)', len(app_data))) blocks.append( ' { %s, значок окна, %d на %d точек, формат ico }\n' ' IconAppData: array[0..%d] of Byte = (\n%s\n );' % (app_src, app_side, app_side, len(app_data) - 1, pascal_bytes(app_data))) text = '''{ uIconData — значки, вшитые в программу. Собран из файлов в icons_online командой: python3 tools/make_icons.py Правится не он, а исходные картинки: этот файл переписывается целиком. Значки взяты у Icons8 и требуют указания авторства — оно есть в окне «О программе», вкладка «Библиотеки и авторство». Ссылки на каждый значок лежат в icons_online/attribution.txt. Картинки чёрные на прозрачном фоне. Цвет им задаётся при отрисовке: берётся прозрачность точки, а цвет — тот, каким сейчас рисуется кнопка. Поэтому один и тот же значок годится и для тёмной кнопки, и для оранжевой. } unit uIconData; {$mode objfpc}{$H+} interface const %s implementation end. ''' % ('\n\n'.join(blocks)) OUT.write_text(text, encoding='utf-8') print('записан', OUT) for name, size in names: print(' %-8s %d байт' % (name, size)) return 0 if __name__ == '__main__': sys.exit(main())