Обложка канала

Geeks

11247 @g33ks

Канал от гиков для гиков. Новости технологий и ссылки на новые каналы ИТ и научной тематики.

Geeks

4 года назад
Открыть в
Часть 2 Генерация векторного изображения Самый простой способ вывести изображение, состоящее из примитивов, это ручками слепить данные для SVG, и сохранить их в файл. SVG представляет из себя обычный XML. Я быстро сделал Jinja2-шаблон и циклом в нем нарисовал необходимые прямоугольники. Потом почесал затылок и решил, что Jinja2 всё таки пакет сторонний, а хочется свести количество зависимостей к нулю (спойлер: у меня так не выйдет). Заглянем в будущее и рассмотрим фрагмент XML-файла, который у нас должен получиться: <?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns="<http://www.w3.org/2000/svg>" viewBox="0, 0, 64, 64"> <rect x="0" y="0" width="64" height="64" style="fill:#933" /> <rect x="32" y="0" width="32" height="64" style="fill:#393" /> </svg> Кажется, что комментировать тут особо и нечего - сначала рисуем один прямоугольник во всю величину аватарки. А затем на ней начинаем рисовать прямоугольники второго цвета. Итак, даже тщательно не вглядываясь в XML можно приметить, что условно данные можно разделить на две части: - Основной блок в котором мы задаем размер области видимости. То есть главный прямоугольник в который и будет вписана аватарка. И в этот блок мы вписываем сгенерированные прямоугольники. Зададим значение вот такой чудесной строкой: SVG_WRAPPER = """<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns="<http://www.w3.org/2000/svg>" viewBox="0, 0, {width}, {height}"> {rects} </svg> """ - И множество блоков прямоугольников, которые будут генерироваться из вот такой строки: SVG_RECT_TAG = '<rect x="{x}" y="{y}" width="{width}" height="{height}" style="fill:{color}" /> Для получения готовых к использованию фрагментов XML будем использовать format для подмены значений в строках. И теперь мы можем написать функцию для создания svg-тега прямоугольника: def make_svg_cell( x: int, y: int, offset: int, size: int, color: Optional[str], ) -> str: return SVG_RECT_TAG.format( x=x*size+offset, y=y*size+offset, size=size, color=color, ) И пробежав по списку со списками сырых значений мы можем сгенерировать все прямоугольники и подставить их в строку SVG_WRAPPER. Готовая функция примет следующий вид: def make_svg_data( data: List[List[bool]], cell_size: int, offset: int, first_color: Optional[str], second_color: Optional[str], ) -> str: box_size = len(data) * cell_size + 2 * offset box = make_svg_cell( x=0, y=0, offset=0, size=box_size, color=first_color, ) rects: List[str] = [box] for y, row in enumerate(data): for x, cell in enumerate(row): if not cell: continue rect = make_svg_cell( x=x, y=y, offset=offset, size=cell_size, color=second_color, ) rects.append(rect) svg_xml = SVG_WRAPPER.format( rects="\\n".join(rects), size=box_size, color=first_color, ) return svg_xml И завершающий шаг, на котором можно проверить результат работы скрипта: data = generate_data() svg = make_svg_data(data, cell_size=16, offset=8, first_color="#fff", second_color="#f6f") with open("test.svg", "w") as file: file.write(data) Теперь можно открыть файл и полюбоваться на сгенеренное. Если хочется растровое изображение, то самый простой способ его получить - конвертнув его из SVG (на pypi можно найти пакет CairoSVG, но в системе должна стоять либа cairo).