def _(d: Line, ctx: cairo.Context, scale: float): ctx.save() ctx.move_to(d.x0 * scale, d.y0 * scale) ctx.line_to(d.x1 * scale, d.y1 * scale) ctx.stroke() # ctx.fill() ctx.restore()
def export_svg(fn, paths, size, line_with=0.1, scale_factor=None): from cairocffi import SVGSurface, Context from .ddd import spatial_sort_2d as sort if not scale_factor: scale_factor = size s = SVGSurface(fn, size, size) c = Context(s) c.set_line_width(0.1) paths = sort(paths) for path in paths: path *= scale_factor c.new_path() c.move_to(*path[0,:]) for p in path[1:]: c.line_to(*p) c.stroke() c.save()
def draw_elements(elements: Sequence[Element], ctx: cairo.Context, scale: float): ctx.save() for element in elements: if element.drawing is not None: draw(element.drawing, ctx, scale) ctx.translate(element.thickness * scale, 0) ctx.restore()
def paint_children(self, ctx: Context): for child in self.children: ctx.save() ctx.translate(*child.position(Anchor.TOP_LEFT)) ctx.rectangle(0, 0, *child.size) ctx.clip() child.paint(ctx) ctx.restore()
def draw_ray_trace(r0: Sequence[float], elements: Sequence[Element], ctx: cairo.Context, scale: float): ctx.save() r = r0 for element in elements: ctx.move_to(0, r[0] * scale) ctx.translate(element.thickness * scale, 0) rp = element.matrix.dot(r) ctx.line_to(0, rp[0] * scale) ctx.stroke() r = rp ctx.restore()
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, context: Context): text_path_glyph_items = self._compute_text_path_glyph_items() for text_path_glyph_item in text_path_glyph_items: glyph_position = text_path_glyph_item.position glyph_rotation = text_path_glyph_item.rotation context.save() context.translate(glyph_position.x, glyph_position.y) context.rotate(glyph_rotation) show_glyph_item(context, self._layout_text, text_path_glyph_item.glyph_item) context.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 render_cluster_glyph_items( ctx: cairocffi.Context, layout: pangocffi.Layout ): """ Renders each cluster within a layout with a unique rotation and color. Warning: Does not support bidirectional text. :param ctx: a Cairo context :param layout: a Pango layout """ layout_run_iter = layout.get_iter() layout_cluster_iter = layout.get_iter() layout_text = layout.get_text() alternate = False while True: layout_run = layout_run_iter.get_run() layout_line_baseline = layout_run_iter.get_baseline() if layout_run is None: if not layout_run_iter.next_run(): break continue clusters = get_clusters_from_glyph_item(layout_run, layout_text) for cluster in clusters: cluster_extents = layout_cluster_iter.get_cluster_extents()[1] layout_cluster_iter.next_cluster() alternate = not alternate ctx.set_source_rgba(0.5, 0, 1 if alternate else 0.5, 0.9) ctx.save() ctx.translate( pangocffi.units_to_double(cluster_extents.x), pangocffi.units_to_double(layout_line_baseline) ) ctx.rotate(-0.05 if alternate else 0.05) pangocairocffi.show_glyph_item( ctx, layout_text, cluster ) ctx.restore() if not layout_run_iter.next_run(): break
def label_train_interfaces(ctx: cairo.Context, train: trains.Train, radius_factors=1, broken_spaces: Sequence = None): spaces, brokens = break_spaces(train.spaces, broken_spaces) radius_factors = np.broadcast_to(radius_factors, (len(train.interfaces), )) ctx.save() ctx.translate(0, spaces[0]) for interface, space, radius_factor in zip(train.interfaces, spaces[1:], radius_factors): label_interface(ctx, interface, radius_factor) ctx.translate(0, space) ctx.restore()
def make_train_spaces(ctx: cairo.Context, train: trains.Train, broken_spaces: Sequence = None, frac: float = 1 / 4): spaces, brokens = break_spaces(train.spaces, broken_spaces) ctx.save() radius = train.interfaces[ 0].radius # if len(self.interfaces) > 0 else self.spaces[0] y_next = 0 xys_last = np.asarray([[-radius, 0], [radius, 0]]) n = train.interfaces[0].n1 for space, next_interface, broken in zip(spaces, train.interfaces + (None, ), brokens): ctx.set_source_rgba(*index_colors.get(n.name, (0, 0, 1, 1))) y_next += space # Generate next interface points. if next_interface is None: xys_next = np.asarray([[-radius, 0], [radius, 0]]) else: xys_next = next_interface.get_points() xys_next += [0, y_next] if broken: num = 8 n = np.arange(num + 1) jagged = np.c_[2 * (n / num - 0.5) * radius, (n % 2) * space * frac + y_next - space / 2] xys = np.r_[xys_last, jagged[::-1, :] - (0, space * frac)] draw_polyline(ctx, xys) ctx.fill() xys = np.r_[jagged, xys_next[::-1, :]] draw_polyline(ctx, xys) ctx.fill() else: xys = np.r_[xys_last, xys_next[::-1, :]] draw_polyline(ctx, xys) ctx.fill() xys_last = xys_next if next_interface is not None: n = next_interface.n2 ctx.restore()
def make_train_interfaces(ctx: cairo.Context, train: trains.Train, broken_spaces: Sequence = None): """ Propagation is along positive y axis, starting from origin. Args: size (scalar): Full transverse dimension of interfaces. """ spaces, brokens = break_spaces(train.spaces, broken_spaces) ctx.save() ctx.translate(0, spaces[0]) for interface, space in zip(train.interfaces, spaces[1:]): make_interface(ctx, interface) ctx.translate(0, space) ctx.restore()
def label_train_spaces(ctx: cairo.Context, train: trains.Train, radius_factors=1, broken_spaces: Sequence = None): """Draw material name and thickness of the spaces. Args: radius_factors (scalar or sequence): Factor by which the average interface radii is multiplied to place the text. If a scalar is given it is broadcast. """ spaces, brokens = break_spaces(train.spaces, broken_spaces) radius_factors = np.broadcast_to(radius_factors, (len(spaces), )) radius_last = train.interfaces[0].radius y_last = 0 h_last = 0 n = train.interfaces[0].n1 for space, next_interface, radius_factor in zip( spaces, train.interfaces + (None, ), radius_factors): if next_interface is None: radius_next = radius_last h_next = 0 else: radius_next = next_interface.radius h_next = functions.calc_sphere_sag(next_interface.roc, radius_next) y_next = y_last + space if space != 0: string = '%.3f mm %s' % (space * 1e3, n.name) radius = (radius_last + radius_next) / 2 x = radius_factor * radius y = (y_next + h_next + y_last + h_last) / 2 ctx.save() ctx.translate(x, y) ctx.show_text(string) ctx.new_path() ctx.restore() if radius_factor > 1: draw_polyline(ctx, ((radius, y), (x, y))) ctx.stroke() y_last = y_next h_last = h_next if next_interface is not None: n = next_interface.n2 radius_last = next_interface.radius
def draw_children(self, g: Graphics) -> None: ui = cast(ContainerUI, self.ui) (cx, cy, cw, ch) = ui.content_bounds(self).tuple g.save() g.rectangle(cx, cy, cw, ch) g.clip() try: # noinspection PyTypeChecker for child in self.children: child.draw(g) except BaseException as e: self.error_handler(e) g.restore()
def draw(self, g: Graphics) -> None: if self.visible: g.save() (dx, dy) = self.parent.map(lambda p: p.location).value_or(Point(0, 0)) (cx, cy, cw, ch) = self.ui.clip_bounds(self).tuple g.translate(dx, dy) g.rectangle(cx, cy, cw, ch) g.clip() try: self.draw_component(g) except BaseException as e: self.error_handler(e) g.restore()
def __draw_sector (self: 'HueSatWheelWidget', cr: cairocffi.Context, center_x: float, center_y: float) -> None: cr.save () cr.set_line_width (1) offset = self.rotation for idx, sector in enumerate (self.sector[0]): half_angle = 2 * numpy.pi * sector / 2 offset += self.sector[1][idx] * 2 * numpy.pi cr.set_source_rgba (0, 0, 0, 1) cr.move_to (center_x, center_y) cr.arc (center_x, center_y, (self.size - 2) / 2., offset - half_angle, half_angle + offset) cr.line_to (center_x, center_y) cr.stroke_preserve () cr.set_source_rgba (0, 0, 0, 0.25) cr.fill () cr.restore ()
def label_interface(ctx: cairo.Context, face: trains.Interface, radius_factor=1): """Draw text saying ROC, and a line from the edge of the interface to the text. Args: radius_factor (scalar): Factor by which interface radius is multiplied to get text x position. """ x = radius_factor * face.radius y = functions.calc_sphere_sag(face.roc, face.radius) string = 'ROC %.3f mm' % (face.roc * 1e3) ctx.set_source_rgb(0, 0, 0) ctx.save() ctx.translate(x, y) ctx.show_text(string) ctx.new_path() ctx.restore() if radius_factor > 1: draw_polyline(ctx, ((face.radius, y), (x, y))) ctx.stroke()
def render_run_glyph_items( ctx: cairocffi.Context, layout: pangocffi.Layout ) -> None: """ Renders each layout run within a layout with a unique rotation and color. :param ctx: a Cairo context :param layout: a Pango layout """ layout_iter = layout.get_iter() layout_text = layout.get_text() alternate = False while True: layout_run = layout_iter.get_run() layout_run_extents = layout_iter.get_run_extents()[1] layout_line_baseline = layout_iter.get_baseline() if layout_run is None: if not layout_iter.next_run(): break continue alternate = not alternate ctx.set_source_rgba(0, 0.5, 1 if alternate else 0.5, 0.9) ctx.save() ctx.translate( pangocffi.units_to_double(layout_run_extents.x), pangocffi.units_to_double(layout_line_baseline) ) ctx.rotate(0.05 if alternate else -0.05) pangocairocffi.show_glyph_item(ctx, layout_text, layout_run) ctx.restore() if not layout_iter.next_run(): break
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: Arc, ctx: cairo.Context, scale: float): ctx.save() ctx.arc(d.xc * scale, d.yc * scale, d.radius * scale, d.theta0, d.theta1) ctx.stroke() ctx.restore()
def _(d: Scaling, ctx: cairo.Context, scale: float): ctx.save() ctx.scale(d.x, d.y) draw(d.child, ctx, scale) ctx.restore()
def _(d: Translation, ctx: cairo.Context, scale: float): ctx.save() ctx.translate(d.x * scale, d.y * scale) draw(d.child, ctx, scale) ctx.restore()
def ctx_scope(ctx: cairo.Context): try: ctx.save() yield ctx finally: ctx.restore()
def __draw_ring (self: 'HueSatWheelWidget', cr: cairocffi.Context, width: int, height: int, center_x: float, center_y: float, outer: float, inner: float) -> None: self.__redraw = False stride = cairocffi.ImageSurface.format_stride_for_width (cairocffi.FORMAT_ARGB32, width) buf = numpy.empty (int (height * stride), dtype = numpy.uint8) for y in range (height): idx = y * width * 4 dy = -(y - center_y) for x in range (width): dx = x - center_x dist = dx * dx + dy * dy angle = math.atan2 (dy, dx) if angle < 0: angle += 2 * numpy.pi hue = angle / (2 * numpy.pi) hue_idx = int ((angle + 2 * numpy.pi / 3) / (2 * numpy.pi) * 255) hue_idx = hue_idx % 256 if dist < ((inner - 1) ** 2) * (1 - self.__hist[255 - hue_idx]) or \ dist > ((outer + 1) ** 2): buf[idx + 0] = 0 buf[idx + 1] = 0 buf[idx + 2] = 0 buf[idx + 3] = 0 idx += 4 continue r, g, b = colorsys.hsv_to_rgb (hue, 1.0, 1.0) a = 255 buf[idx + 0] = int (math.floor (r * 255 + 0.5)) buf[idx + 1] = int (math.floor (g * 255 + 0.5)) buf[idx + 2] = int (math.floor (b * 255 + 0.5)) buf[idx + 3] = a idx += 4 source = cairocffi.ImageSurface.create_for_data ( memoryview (buf), cairocffi.FORMAT_ARGB32, width, height, stride ) fg_color = self.get_style_context ().get_color (Gtk.StateFlags.NORMAL) cr.save () cr.set_source_rgba (0, 0, 0, 0) cr.paint () cr.set_source_surface (source, 0, 0) cr.paint () cr.set_line_width (1) cr.new_path () cr.set_source_rgba (*list (fg_color)) cr.arc (center_x, center_y, (self.size - 4) / 2. - self.ring_width, 0, 2 * numpy.pi) cr.stroke () cr.arc (center_x, center_y, (self.size - 2) / 2, 0, 2 * numpy.pi) cr.stroke () cr.arc (center_x, center_y, 5, 0, 2 * numpy.pi) cr.fill () cr.restore ()
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()