class Plot(object): red = (1., 0., 0.) green = (0., 1., 0.) blue = (0., 0., 1.) yellow = (1., 1., 0.) cyan = (0., 1., 1.) magenta = (1., 0., 1.) def __init__(self, width, height): from cairocffi import SVGSurface, Context self.plot_id = next(_debug_generator) self._surface = SVGSurface("debug_plot-%05d.svg" % self.plot_id, width, height) self._ctx = Context(self._surface) self._ctx.set_source_rgb(0., 0., 0.) self._ctx.paint() def line(self, line, color): ctx = self._ctx ctx.move_to(line.p1.x, line.p1.y) ctx.line_to(line.p2.x, line.p2.y) ctx.set_source_rgb(*color) ctx.stroke() def circle(self, center, radius, stroke_color, fill_color=None): ctx = self._ctx ctx.new_sub_path() ctx.arc(center.x, center.y, radius, 0, math.pi * 2) ctx.set_source_rgb(*stroke_color) if fill_color: ctx.stroke_preserve() ctx.set_source_rgb(*fill_color) ctx.fill() else: ctx.stroke()
def _draw_stroke(self, ctx: Context, geom: Union[Polygon, MultiPolygon]): if isinstance(geom, MultiPolygon): for sub_geom in geom.geoms: self._draw_stroke(ctx, sub_geom) return CairoHelper.draw_polygon(ctx, geom) ctx.stroke()
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 _draw_railway(self, ctx: Context, line_string: LineString): CairoHelper.draw_line_string(ctx, line_string) # Todo: Buffer the linestring outwards # ShapelyHelper.buffer_linestring() ctx.stroke()
def _draw_stroke(self, ctx: Context, geom: Union[LineString, MultiLineString]): if isinstance(geom, MultiLineString): for sub_geom in geom.geoms: self._draw_stroke(ctx, sub_geom) return CairoHelper.draw_line_string(ctx, geom) ctx.stroke()
def __init__(self, width, height): from cairocffi import SVGSurface, Context self.plot_id = next(_debug_generator) self._surface = SVGSurface("debug_plot-%05d.svg" % self.plot_id, width, height) self._ctx = Context(self._surface) self._ctx.set_source_rgb(0., 0., 0.) self._ctx.paint()
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 set(self, ctx: Context): """ Set this font to get used on the given context. :param ctx: """ ctx.select_font_face(self.name, cairo.FONT_SLANT_ITALIC if self.italic else cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD if self.bold else cairo.FONT_WEIGHT_NORMAL) ctx.set_font_size(self.size)
def draw_line_string(ctx: Context, line_string: LineString): start = True for x, y in line_string.coords: if start: ctx.move_to(x, y) else: ctx.line_to(x, y) start = False
def paint_scale_background(self, ctx: Context): cpu_count = Global.system_data.cpu_count for i in range(cpu_count): if i % 2: ctx.set_source_rgba(*Color.GRAY33) else: ctx.set_source_rgba(*Color.GRAY50) ctx.move_to(0, self.height - self.height / cpu_count * i) ctx.line_to(self.width, self.height - self.height / cpu_count * i) ctx.stroke()
def create_graphics(self, surface: Surface): if surface is None: raise ValueError("Argument 'surface' is required.") g = Graphics(surface) g.set_antialias(ANTIALIAS_BEST) g.set_font_options(self.font_options) return g
def _rectangle_path( context: cairocffi.Context, rectangle: pangocffi.Rectangle ): x, y, width, height = _convert_rectangle_to_pixels(rectangle) context.move_to(x, y) context.line_to(x + width, y) context.line_to(x + width, y + height) context.line_to(x, y + height) context.line_to(x, y)
def paint(self, ctx: Context): """ Renders this widget. :param ctx: Cairo context. """ if self.background: ctx.set_source_rgba(*self.background) self.paint_background(ctx) ctx.set_source_rgba(*self.foreground) self.paint_foreground(ctx) self.dirty = False
def draw_background(self, g: Graphics, component: T, color: RGBA) -> None: area = component.bounds if area.width == 0 or area.height == 0: return g.set_source_rgba(color.r, color.g, color.b, color.a) self.draw_rect(g, area, 8) g.fill()
def _show_label( context: cairocffi.Context, position: Tuple[float, float], width: float, text: str ): context.translate(position[0], position[1]) label = pangocairocffi.create_layout(context) label.set_width(pangocffi.units_from_double(width)) label.set_alignment(pangocffi.Alignment.LEFT) label.set_markup('<span font-family="sans-serif">%s</span>' % text) pangocairocffi.show_layout(context, label) context.translate(-position[0], -position[1])
def draw(self, ctx: Context, outline: Union[Polygon, MultiPolygon]): if isinstance(outline, MultiPolygon): shadow_line_strings = [] for sub_outline in outline.geoms: shadow_line_string = self.draw(ctx, sub_outline) shadow_line_strings.append(shadow_line_string) return shadow_line_strings buffered_outline = outline.buffer(-self.outline_line_width / 2, cap_style=3, join_style=2) shadow_line_strings = self._get_shadow_lines(buffered_outline) for shadow_line_string in shadow_line_strings: CairoHelper.draw_line_string(ctx, shadow_line_string) ctx.stroke() pass
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 _coordinate_path( context: cairocffi.Context, point: Tuple[int, int], radius: float = 1 ): for i in range(0, 8): p_x = pangocffi.units_to_double(point[0]) + \ math.sin(i/4 * math.pi) * radius p_y = pangocffi.units_to_double(point[1]) + \ math.cos(i/4 * math.pi) * radius if i == 0: context.move_to(p_x, p_y) else: context.line_to(p_x, p_y)
def set_source_rgb(self, colour: Union[ColorType, List[ColorType]], ctx: cairocffi.Context = None): # If an alternate context is not provided then we draw to the # drawer's default context if ctx is None: ctx = self.ctx if isinstance(colour, list): if len(colour) == 0: # defaults to black ctx.set_source_rgba(*utils.rgb("#000000")) elif len(colour) == 1: ctx.set_source_rgba(*utils.rgb(colour[0])) else: linear = cairocffi.LinearGradient(0.0, 0.0, 0.0, self.height) step_size = 1.0 / (len(colour) - 1) step = 0.0 for c in colour: rgb_col = utils.rgb(c) if len(rgb_col) < 4: rgb_col[3] = 1 linear.add_color_stop_rgba(step, *rgb_col) step += step_size ctx.set_source(linear) else: ctx.set_source_rgba(*utils.rgb(colour))
def draw(self, ctx: Context): if not self.canvas_set: raise Exception("Canvas size not set!") top_left = (0, 0) top_right = (self.canvas_width, 0) bottom_left = (0, self.canvas_height) bottom_right = (self.canvas_width, self.canvas_height) canvas = Polygon( [top_left, top_right, bottom_right, bottom_left, top_left]) ctx.set_source_rgba(*self.color) CairoHelper.draw_polygon(ctx, canvas) ctx.fill()
def test_layout_clusters_get_max_logical_extent(): surface = SVGSurface(None, 100, 100) cairo_context = Context(surface) layout_1 = pangocairocffi.create_layout(cairo_context) layout_1.set_markup('Text with one line') layout_1_clusters = LayoutClusters(layout_1) extent_1 = layout_1_clusters.get_max_logical_extent() layout_2 = pangocairocffi.create_layout(cairo_context) layout_2.set_markup('text with\ntwo lines') layout_2_clusters = LayoutClusters(layout_2) extent_2 = layout_2_clusters.get_max_logical_extent() assert extent_1.x == 0 assert extent_1.y == 0 assert extent_1.width > 0 assert extent_1.height > 0 assert extent_2.x == extent_1.x assert extent_2.y == extent_1.y assert extent_1.width != extent_2.width assert extent_1.height * 2 == extent_2.height surface.finish()
def _create_real_surface(self, filename: str, width: int = 100, height: int = 100) -> Tuple[Surface, Context]: surface = SVGSurface('tests/output/text_path_%s' % filename, width, height) cairo_context = Context(surface) return surface, cairo_context
def _show_layout_line_logical_extents( context: cairocffi.Context, layout: pangocffi.Layout ): layout_iter = layout.get_iter() context.set_line_width(0.5) context.set_dash([1, 1]) alternate = True while True: alternate = not alternate extents = layout_iter.get_line_extents() context.set_source_rgba(0, 0, 1 if alternate else 0.5, 0.9) _rectangle_path(context, extents[1]) context.stroke() _coordinate_path(context, (extents[1].x, extents[1].y)) context.fill() if not layout_iter.next_run(): break
def paint_foreground(self, ctx: Context): layout = self.font.get_layout(self.text, ctx, self.foreground, self.escape) if self.h_alignment == TextWidget.HAlignment.LEFT: layout.set_alignment(Alignment.LEFT) else: layout.set_width(round(self.width * 1000)) if self.h_alignment == TextWidget.HAlignment.CENTER: layout.set_alignment(Alignment.CENTER) elif self.h_alignment == TextWidget.HAlignment.RIGHT: layout.set_alignment(Alignment.RIGHT) y = -layout.get_extents()[0].y / 1000 if self.v_alignment == TextWidget.VAlignment.BOTTOM: y += self.height - layout.get_extents()[0].height / 1000 elif self.v_alignment == TextWidget.VAlignment.CENTER: y += (self.height - layout.get_extents()[0].height / 1000) / 2 ctx.move_to(0, y) pangocairo.show_layout(ctx, layout)
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(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 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 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 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 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 __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 __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 ()