def draw_component(self, g: Graphics, component: Canvas) -> None: super().draw_component(g, component) if component.image == Nothing: return image = component.image.unwrap() padding = component.resolve_insets(StyleKeys.Padding).value_or( Insets(0, 0, 0, 0)) + component.padding (x, y, w, h) = component.bounds.tuple bounds = Bounds(x + padding.left, y + padding.top, max(w - padding.left - padding.right, 0), max(h - padding.top - padding.bottom, 0)) (iw, ih) = image.size.tuple (w, h) = bounds.size.tuple if iw == 0 or ih == 0 or w == 0 or h == 0: return (x, y) = bounds.location.tuple sw = w / iw sh = h / ih sx = x / sw sy = y / sh g.scale(sw, sh) g.set_source_surface(image.surface, sx, sy) g.paint()
def apply_viewbox(ctx: cairo.Context, width: float, height: float, viewbox) -> float: viewbox_width = viewbox[2] viewbox_height = viewbox[3] scale = min(width / viewbox_width, height / viewbox_height) ctx.translate(-viewbox[0] * scale, -viewbox[1] * scale) ctx.scale(scale, scale) translate_x = (width / scale - viewbox_width) / 2 translate_y = (height / scale - viewbox_height) / 2 ctx.translate(translate_x, translate_y) return scale
def draw(self, ctx: Context, surface: Surface): ctx.save() ctx.translate(self.translate_x, self.translate_y) ctx.rotate(self.rotation) ctx.scale(self.width / self.svg_width, self.height / self.svg_height) ctx.translate(-self.origin_x, -self.origin_y) CairoSVGSurface(self.tree, None, 96, output_cairo=surface, output_cairo_context=ctx) ctx.restore()
def draw(self, ctx: Context): text_baseline = self.get_text_baseline(ctx) default_font_max_height = ctx.get_scaled_font().extents()[0] text_max_length = float('inf') line_string_bottom_length = text_baseline.length trimmed = False while text_max_length > line_string_bottom_length: text_max_length = ctx.text_extents(self.text)[4] / default_font_max_height * self.text_height + \ (len(self.text)-1) * self.text_spacing if text_max_length > line_string_bottom_length: self.text = self.text[:-1].strip() trimmed = True text_start_interp_pos_min = 0 text_start_interp_pos_max = line_string_bottom_length - text_max_length if self.text_alignment == 'left': text_start_interp_pos = self.text_alignment_offset elif self.text_alignment == 'center': text_start_interp_pos = line_string_bottom_length / 2 - text_max_length / 2 - self.text_alignment_offset else: text_start_interp_pos = line_string_bottom_length - text_max_length - self.text_alignment_offset text_start_interp_pos = min( text_start_interp_pos_max, max(text_start_interp_pos_min, text_start_interp_pos)) text_interp_pos = text_start_interp_pos for char in self.text: char_pos_origin = text_baseline.interpolate(text_interp_pos) char_advance_x = ctx.text_extents( char)[4] / default_font_max_height * self.text_height char_pos_end = text_baseline.interpolate(text_interp_pos + char_advance_x) ctx.save() ctx.translate(char_pos_origin.x, char_pos_origin.y) text_angle = math.atan2(char_pos_end.y - char_pos_origin.y, char_pos_end.x - char_pos_origin.x) ctx.rotate(text_angle) ctx.scale(1 / default_font_max_height * self.text_height) if not trimmed: ctx.set_source_rgba(0, 0, 0, 1) else: ctx.set_source_rgba(0, 0, 0.2, 1) ctx.show_text(char) ctx.fill() ctx.restore() text_interp_pos += char_advance_x + self.text_spacing
def transform( ctx: cairo.Context, point: Tuple[float, float], rotation: float = None, scale_x=1.0, scale_y=1.0, ): ctx.translate(point[0], point[1]) if rotation is not None: ctx.rotate(math.radians(rotation)) if scale_x != 1.0 or scale_y != 1.0: ctx.scale(sx=scale_x, sy=scale_y) ctx.translate(-point[0], -point[1])
def paint_foreground(self, ctx: Context): if self._image: sx = self.width / self._image.get_width() sy = self.height / self._image.get_height() s = min(sx, sy) sw = self._image.get_width() * s sh = self._image.get_height() * s ctx.scale(s, s) x = 0 y = 0 if self.alignment == Anchor.TOP_LEFT: x = 0 y = 0 elif self.alignment == Anchor.TOP_CENTER: x = (self.width - sw) / 2 y = 0 elif self.alignment == Anchor.TOP_RIGHT: x = self.width - sw y = 0 elif self.alignment == Anchor.CENTER_LEFT: x = 0 y = (self.height - sh) / 2 elif self.alignment == Anchor.CENTER_CENTER: x = (self.width - sw) / 2 y = (self.height - sh) / 2 elif self.alignment == Anchor.CENTER_RIGHT: x = (self.width - sw) y = (self.height - sh) / 2 elif self.alignment == Anchor.BOTTOM_LEFT: x = 0 y = self.height - sh elif self.alignment == Anchor.BOTTOM_CENTER: x = (self.width - sw) / 2 y = self.height - sh elif self.alignment == Anchor.BOTTOM_RIGHT: x = self.width - sw y = self.height - sh x /= s y /= s ctx.set_source_surface(self._image, x, y) ctx.paint() else: ctx.move_to(0, 0) ctx.line_to(self.size.width, self.size.height) ctx.stroke() ctx.move_to(0, self.size.height) ctx.line_to(self.size.width, 0) ctx.stroke()
def _generate_layer(self, transcription, page, layer): surface = PDFSurface(layer, *page.page_size) context = Context(surface) # context.select_font_face('Georgia') context.set_source_rgba(1, 1, 1, 1 / 256) # almost invisible context.set_font_size(2) for line_ink, line_transcription in zip(page.lines, transcription): ink, transformation = writing.normalized(line_ink) context.save() context.transform( Matrix(*(Transformation.translation( 0, page.page_size[1]).parameter))) context.transform(Matrix(*(Transformation.mirror(0).parameter))) context.transform(Matrix(*((~transformation).parameter))) context.transform(Matrix(*(Transformation.mirror(0).parameter))) HANDWRITING_WIDTH = ink.boundary_box[1] TYPEWRITING_WIDTH = context.text_extents(line_transcription)[2] context.scale(HANDWRITING_WIDTH / TYPEWRITING_WIDTH, 1) context.move_to(0, 0) context.show_text(line_transcription) context.restore() context.stroke() context.show_page() surface.flush()
def _(d: Scaling, ctx: cairo.Context, scale: float): ctx.save() ctx.scale(d.x, d.y) draw(d.child, ctx, scale) ctx.restore()
def draw_text(ctx: Context, text: str, x: float, y: float, scale: float): original = ctx.get_matrix() ctx.translate(x, y) ctx.scale(scale / 10) # Default font size is 10 mm (1cm) ctx.show_text(text) ctx.set_matrix(original)
def draw(self, ctx: Context, surface: Surface): ctx.save() ctx.translate(self.position_x, self.position_y) ctx.scale(self.width / self.svg_width, self.height / self.svg_height) CairoSVGSurface(self.tree, surface, ctx, 96) ctx.restore()