from __future__ import annotations import aggdraw from fontTools.pens.basePen import BasePen from PIL import Image, ImageDraw from generator.engraving.fonts import Fonts from generator.engraving.types import Page class OutlinePen(BasePen): def __init__(self, glyphs, scale: float, x: float, y: float): super().__init__(glyphs) self.path = aggdraw.Path() self.scale, self.x, self.y = scale, x, y def point(self, point): return self.x + point[0] * self.scale, self.y - point[1] * self.scale def _moveTo(self, point): self.path.moveto(*self.point(point)) def _lineTo(self, point): self.path.lineto(*self.point(point)) def _curveToOne(self, first, second, last): self.path.curveto(*self.point(first), *self.point(second), *self.point(last)) def _closePath(self): self.path.close() def _endPath(self): pass def rasterize_page(page: Page, fonts: Fonts) -> Image.Image: scale = page.supersampling image = Image.new('RGB', (page.width * scale, page.height * scale), 'white') context = aggdraw.Draw(image) for item in page.primitives: points = [(x * scale, y * scale) for x, y in item.points] if item.kind == 'text': continue if item.kind == 'glyph': pen = OutlinePen(fonts.glyphs, item.size * scale / fonts.units, *points[0]) fonts.outline(item.value).replay(pen) path = pen.path else: path = aggdraw.Path() path.moveto(*points[0]) if item.kind == 'curve': path.curveto(*points[1], *points[2], *points[3]) else: for point in points[1:]: path.lineto(*point) if item.kind == 'polygon': path.close() if item.kind in ('glyph', 'polygon'): context.path(path, None, aggdraw.Brush('black')) else: context.path(path, aggdraw.Pen('black', item.thickness * scale)) context.flush() drawing = ImageDraw.Draw(image) for item in page.primitives: if item.kind == 'text': drawing.text(tuple(v * scale for v in item.points[0]), item.value, font=fonts.text_font(item.size * scale), anchor='ls', fill='black') return image.resize((page.width, page.height), Image.Resampling.LANCZOS)