def test_output_translate_rotate_scale(self): path = Path(__file__).parent.joinpath('output/svg_trs.svg') path.unlink(missing_ok=True) canvas_builder = CanvasBuilder() canvas_builder.set_path(path) canvas_builder.set_size( Cu.from_cm(4), Cu.from_cm(4) ) canvas = canvas_builder.build() background = Background() background.color = (0.8, 1, 0.8, 1) background.draw(canvas) svg = Svg(Path(__file__).parent.joinpath('test_svg_grid.svg')) svg_size = svg.read_svg_size() # Should set the origin of the image to the center. svg.svg_origin = Cc(svg_size[0] / 2, svg_size[1] / 2) # Should position the image in the center of the screen. svg.position = Cc.from_cm(2, 2) # Should rotate the image clock-wise. svg.rotation = math.pi / 8 # Resizes the image to almost the size of the canvas, but not exactly. svg.width = Cu.from_cm(3) svg.height = Cu.from_cm(3) svg.draw(canvas) canvas.close() assert path.exists()
def test_fill_preserve(self): path = Path(__file__).parent.joinpath( 'output/polygon_drawer_fill_preserve.svg') path.unlink(missing_ok=True) canvas_builder = CanvasBuilder() canvas_builder.set_path(path) canvas_builder.set_size(Cu.from_pt(100), Cu.from_pt(100)) canvas = canvas_builder.build() polygon_drawer = PolygonDrawer() polygon_drawer.fill_color = (1, 0, 0) polygon_drawer.stroke_color = (0, 1, 0) polygon_drawer.stroke_width = Cu.from_pt(2) polygon_drawer.geoms = [ Polygon([ (30, 30), (70, 30), (70, 70), (30, 70), (30, 30), ]) ] polygon_drawer.draw(canvas) canvas.close() assert path.exists() with open(path, 'r') as file: data = file.read() assert data.find('M 30 30 L 70 30 L 70 70 L 30 70 Z M 30 30') != -1 assert data.find('fill:rgb(100%,0%,0%)') != -1 assert data.find('stroke-width:2') != -1 assert data.find('stroke:rgb(0%,100%,0%);') != -1
def test_invalid_setters(self): valid_path = Path(__file__).parent.joinpath('output/valid.png') invalid_path = Path(__file__).parent.joinpath('output/invalid.wat') with self.assertRaises(RuntimeError): canvas_builder = CanvasBuilder() canvas_builder.set_size(Cu.from_mm(1), Cu.from_mm(1)) canvas_builder.set_path(invalid_path) with self.assertRaises(RuntimeError): canvas_builder = CanvasBuilder() canvas_builder.set_path(valid_path) canvas_builder.set_size(Cu.from_mm(-1), Cu.from_mm(1)) with self.assertRaises(RuntimeError): canvas_builder = CanvasBuilder() canvas_builder.set_path(valid_path) canvas_builder.set_size(Cu.from_mm(1), Cu.from_mm(-1)) with self.assertRaises(RuntimeError): canvas_builder = CanvasBuilder() canvas_builder.set_path(valid_path) canvas_builder.set_size(Cu.from_mm(1), Cu.from_mm(1)) canvas_builder.set_anti_alias_mode(-1) with self.assertRaises(RuntimeError): canvas_builder = CanvasBuilder() canvas_builder.set_path(valid_path) canvas_builder.set_size(Cu.from_mm(1), Cu.from_mm(1)) canvas_builder.set_anti_alias_mode(7)
def __init__(self, path: Path, surface_type: str, width: float, height: float, scale: float = 1): self.width = width self.height = height self.scale = scale self.path_as_posix = path.as_posix() if surface_type == 'pdf': surface = cairo.PDFSurface(self.path_as_posix, width, height) elif surface_type == 'svg': surface = cairo.SVGSurface(self.path_as_posix, width, height) elif surface_type == 'png': surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height)) else: raise Exception('Unexpected Format: %s' % surface_type) context = cairo.Context(surface) self.surface = surface self.context = context if isinstance(self.surface, cairo.ImageSurface): self.context.scale( CanvasUnit.from_pt(1).px * self.scale, CanvasUnit.from_pt(1).px * self.scale)
def test_scaling_outputs(self): surface_types = [('pdf', 1), ('svg', 1), ('png', 0.5), ('png', 1), ('png', 2)] units = ['pt', 'in', 'cm', 'mm', 'px'] for (surface_type, pixel_scale_factor) in surface_types: for unit in units: canvas_builder = CanvasBuilder() # We want to test all units, but some sizes are just too big # and will take up lots of disk space. So we make an exception # for inches and centimeters. expected_size_in_unit: int expected_size: Optional[CanvasUnit] if unit in ['in', 'cm']: expected_size_in_unit = 4 expected_size = Cu.from_unit(4, unit) # Setting to a smaller size to avoid disk space issues canvas_builder.set_size(expected_size, expected_size) else: expected_size_in_unit = 100 expected_size = CanvasUnit.from_unit(100, unit) canvas_builder.set_size(expected_size, expected_size) path = Path(__file__).parent \ .joinpath( 'output/canvas_builder_%s_%d%s_x%s.%s' % ( surface_type, expected_size_in_unit, unit, pixel_scale_factor, surface_type ) ) path.unlink(missing_ok=True) canvas_builder.set_path(path) canvas_builder.set_pixel_scale_factor(pixel_scale_factor) canvas = canvas_builder.build() self.draw_rectangle_top_left(canvas, unit) canvas.close() assert path.exists() actual = self.get_file_dimensions_and_scale(path) if surface_type == 'pdf': self.assert_match(expected_size_in_unit, unit, surface_type, 1, actual, expected_size.pt) elif surface_type == 'svg': self.assert_match(expected_size_in_unit, unit, surface_type, 1, actual, expected_size.pt) elif surface_type == 'png': self.assert_match(expected_size_in_unit, unit, surface_type, pixel_scale_factor, actual, expected_size.px)
def logical_extents(self) -> CanvasBbox: extent = self._layout.get_extents()[1] x = CanvasUnit.from_pt(pangocffi.units_to_double(extent.x)) y = CanvasUnit.from_pt(pangocffi.units_to_double(extent.y)) x += self._position.x y += self._position.y width = CanvasUnit.from_pt(pangocffi.units_to_double(extent.width)) height = CanvasUnit.from_pt(pangocffi.units_to_double(extent.height)) return CanvasBbox(CanvasCoordinate(x, y), width, height)
def test_unset_paths(self): path = Path(__file__).parent.joinpath( 'invalid_output_dir/canvas_builder_invalid_path.png') canvas_builder = CanvasBuilder() canvas_builder.set_path(path) canvas_builder.set_size(Cu.from_px(100), Cu.from_px(100)) with self.assertRaises(RuntimeError): canvas_builder.build() assert not path.exists()
def test_svg(self): path = Path(__file__).parent.joinpath('output/canvas_builder.pdf') path.unlink(missing_ok=True) canvas_builder = CanvasBuilder() canvas_builder.set_path(path) canvas_builder.set_size(Cu.from_mm(100), Cu.from_mm(100)) canvas = canvas_builder.build() canvas.close() assert path.exists()
def test_validating_pixel_scale_factor(self): path = Path(__file__).parent.joinpath( 'output/canvas_builder_pixel_scale_factor.svg') canvas_builder = CanvasBuilder() canvas_builder.set_path(path) canvas_builder.set_size(Cu.from_px(100), Cu.from_px(100)) canvas_builder.set_pixel_scale_factor(2) with self.assertRaises(RuntimeError): canvas_builder.build() assert not path.exists()
def draw_symbol(self, key, point: Point, canvas: Canvas): canvas.context.set_source_rgba(point.x/100, point.y/100, 0, 1) CairoHelper.draw_point( canvas.context, point, Cu.from_pt(key).pt )
def test_single_stripe(self): path = Path(__file__).parent.joinpath( 'output/stripe_filled_polygon_drawer_single.svg') path.unlink(missing_ok=True) canvas_builder = CanvasBuilder() canvas_builder.set_path(path) canvas_builder.set_size(Cu.from_pt(100), Cu.from_pt(100)) canvas = canvas_builder.build() drawer = StripeFilledPolygonDrawer() drawer.stripe_colors = [(0, 1, 0)] drawer.geoms = [ Polygon([ (30, 30), (70, 30), (70, 70), (30, 70), (30, 30), ]) ] drawer.draw(canvas) drawer.geoms = [ Polygon([ (40, 40), (60, 40), (60, 60), (40, 60), (40, 40), ]) ] drawer.stripe_colors = [None] drawer.draw(canvas) canvas.close() assert path.exists() with open(path, 'r') as file: data = file.read() assert data.find('M 30 30 L 70 30 L 70 70 L 30 70 Z M 30 30') != -1 assert data.find('M 40 40 L 60 40 L 60 60 L 40 60 Z M 40 40') == -1 assert data.find('fill:rgb(0%,100%,0%)') != -1 assert data.find('stroke:none') != -1 assert data.find('stroke-width:') == -1
def test_unit_scale(self): surface_types = ['png', 'svg', 'pdf'] for surface_type in surface_types: path = Path(__file__).parent\ .joinpath('output/canvas_builder_unit_scale.%s' % surface_type) path.unlink(missing_ok=True) canvas_builder = CanvasBuilder() canvas_builder.set_path(path) canvas_builder.set_size(CanvasUnit.from_in(1), CanvasUnit.from_in(1)) canvas = canvas_builder.build() UnitScale().draw(canvas) canvas.close() assert path.exists()
def test_z_func(self): path = Path(__file__).parent.joinpath( 'output/symbol_drawer_z_func.svg' ) path.unlink(missing_ok=True) canvas_builder = CanvasBuilder() canvas_builder.set_path(path) canvas_builder.set_size(Cu.from_pt(100), Cu.from_pt(100)) canvas = canvas_builder.build() class MySymbolDrawer(SymbolDrawer): def draw_symbol(self, key, point: Point, canvas: Canvas): canvas.context.set_source_rgba(point.x/100, point.y/100, 0, 1) CairoHelper.draw_point( canvas.context, point, Cu.from_pt(20).pt ) my_symbol_drawer = MySymbolDrawer() my_symbol_drawer.points = [ Point(30, 70), Point(35, 60), Point(40, 50), Point(45, 40), Point(50, 30), Point(55, 40), Point(60, 50), Point(65, 60), Point(70, 70) ] my_symbol_drawer.draw(canvas) canvas.close() assert path.exists() with open(path, 'r') as file: data = file.read() # Assert that the symbols appear assert data.find('rgb(50%,30%,0%)') != -1 assert data.find('rgb(50%,30%,0%)') < data.find('rgb(45%,40%,0%)') assert data.find('rgb(45%,40%,0%)') < data.find('rgb(55%,40%,0%)')
def build_canvas(self, name: str) -> Canvas: name = re.sub(r'[^0-9A-Za-z_-]', '', name) path = Path(__file__).parent.joinpath( 'output/azimuthal_rendering_%s.svg' % name ) path.unlink(missing_ok=True) canvas_builder = CanvasBuilder() canvas_builder.set_path(path) canvas_builder.set_size( Cu.from_px( self.margin * 3 + self.azimuthal_width + self.wgs84_width ), Cu.from_px( self.margin * 2 + self.azimuthal_height ) ) return canvas_builder.build()
def test_can_iterate_dict(self): path = Path(__file__).parent.joinpath( 'output/symbol_drawer_can_iterate_dict.svg' ) path.unlink(missing_ok=True) canvas_builder = CanvasBuilder() canvas_builder.set_path(path) canvas_builder.set_size(Cu.from_pt(100), Cu.from_pt(100)) canvas = canvas_builder.build() class MySymbolDrawer(SymbolDrawer): def draw_symbol(self, key, point: Point, canvas: Canvas): canvas.context.set_source_rgba(point.x/100, point.y/100, 0, 1) CairoHelper.draw_point( canvas.context, point, Cu.from_pt(key).pt ) my_symbol_drawer = MySymbolDrawer() my_symbol_drawer.points = { 2: Point(30, 70), 4: Point(35, 60), 6: Point(40, 50), 8: Point(45, 40), 10: Point(50, 30), 12: Point(55, 40), 14: Point(60, 50), 16: Point(65, 60), 18: Point(70, 70) } my_symbol_drawer.draw(canvas) canvas.close() assert path.exists() with open(path, 'r') as file: data = file.read() # Assert that the symbols appear with correct size assert data.find('d="M 55 30 C') != -1 assert data.find('d="M 79 70 C') != -1
def draw_rectangle(self, canvas: Canvas, offset: int, unit: str): height = CanvasUnit.from_pt(10).pt width = CanvasUnit.from_unit(1, unit).pt offset_height = height * offset top_left = (0, offset_height) top_right = (width, offset_height) bottom_left = (0, offset_height + height) bottom_right = (width, offset_height + height) shape = Polygon([ top_left, top_right, bottom_right, bottom_left, top_left ]) canvas.context.set_source_rgba(*self.color) CairoHelper.draw_polygon(canvas.context, shape) canvas.context.set_source_rgba(0.5, 0.5, 0.5, 1) canvas.context.fill()
def test_validation(self): with self.assertRaisesRegex( Exception, 'length of width_arr is not the same as color_arr'): drawer = StripeFilledPolygonDrawer() drawer.stripe_colors = [(0, 1, 0), (0, 1, 0)] drawer.stripe_widths = [Cu.from_pt(10)] drawer.draw(MagicMock()) with self.assertRaisesRegex( Exception, 'width_arr must contain at least one value'): drawer = StripeFilledPolygonDrawer() drawer.stripe_colors = [] drawer.stripe_widths = [] drawer.draw(MagicMock()) with self.assertRaisesRegex( Exception, 'width_arr must be a positive non-zero length'): drawer = StripeFilledPolygonDrawer() drawer.stripe_colors = [(0, 1, 0), (0, 1, 0)] drawer.stripe_widths = [Cu.from_pt(10), Cu.from_pt(0)] drawer.draw(MagicMock())
def test_multi_line_string(self): path = Path(__file__).parent.joinpath( 'output/line_drawer_multi_line_string.svg') path.unlink(missing_ok=True) canvas_builder = CanvasBuilder() canvas_builder.set_path(path) canvas_builder.set_size(Cu.from_pt(100), Cu.from_pt(100)) canvas = canvas_builder.build() line_drawer = LineDrawer() line_drawer.stroke_color = (1, 0, 0) line_drawer.stroke_width = Cu.from_pt(1.5) line_drawer.geoms = [ MultiLineString([[ (30, 30), (70, 30), (70, 70), (30, 70), ], [ (40, 40), (40, 60), (60, 60), (60, 40), ]]) ] line_drawer.draw(canvas) canvas.close() assert path.exists() with open(path, 'r') as file: data = file.read() assert data.find('M 30 30 L 70 30 L 70 70 L 30 70') != -1 assert data.find('M 40 40 L 40 60 L 60 60 L 60 40') != -1 assert data.find('fill:none') != -1 assert data.find('stroke-width:1.5') != -1 assert data.find('stroke:rgb(100%,0%,0%);') != -1
def test_two_vertical_stripes(self): path = Path(__file__).parent.joinpath( 'output/stripe_filled_polygon_drawer_two_vertical_stripes.svg') path.unlink(missing_ok=True) canvas_builder = CanvasBuilder() canvas_builder.set_path(path) canvas_builder.set_size(Cu.from_pt(100), Cu.from_pt(100)) canvas = canvas_builder.build() drawer = StripeFilledPolygonDrawer() drawer.stripe_colors = [(0, 1, 0), (0, 0, 1)] drawer.stripe_widths = [Cu.from_pt(20), Cu.from_pt(20)] drawer.stripe_origin = CanvasCoordinate.from_pt(30, 30) drawer.stripe_angle = math.pi / 2 # Vertical stripes drawer.geoms = [ Polygon([ (30, 30), (70, 30), (70, 70), (30, 70), (30, 30), ]) ] drawer.draw(canvas) canvas.close() assert path.exists() with open(path, 'r') as file: data = file.read() assert data.find('M 30 30 L 30 70 L 50 70 L 50 30 Z M 30 30') != -1 assert data.find('M 50 30 L 50 70 L 70 70 L 70 30 Z M 50 30') != -1 assert data.find('fill:rgb(0%,100%,0%)') != -1 assert data.find('fill:rgb(0%,0%,100%)') != -1 assert data.find('stroke:none') != -1 assert data.find('stroke-width:') == -1
def draw_rectangle_top_left(canvas: Canvas, unit: str): if unit in ['in', 'cm']: # Setting to a smaller size to avoid disk space issues midpoint = CanvasUnit.from_unit(2, unit).pt else: midpoint = CanvasUnit.from_unit(50, unit).pt top_left = (0, 0) top_right = (midpoint, 0) bottom_left = (0, midpoint) bottom_right = (midpoint, midpoint) shape = Polygon( [top_left, top_right, bottom_right, bottom_left, top_left]) canvas.context.set_source_rgb(0, 0, 0) CairoHelper.draw_polygon(canvas.context, shape) canvas.context.fill() point_unit_shape = Polygon([(0, 0), (0, 1), (1, 1), (1, 0), (0, 0)]) canvas.context.set_source_rgb(1, 0, 0) CairoHelper.draw_polygon(canvas.context, point_unit_shape) canvas.context.fill()
def close(self): # Special edge case for ImageSurfaces if isinstance(self.surface, cairo.ImageSurface): self.surface.write_to_png(self.path_as_posix) self.surface.finish() # Cairo sets the dots-per-image as 72 pixels-per-inch, when it should # be 96. We also want to take into account the scale, since the number # of inches should not change. We use Pillow to adjust the DPI. if isinstance(self.surface, cairo.ImageSurface): image = Image.open(self.path_as_posix) dpi = CanvasUnit.from_in(1).px * self.scale image.save(self.path_as_posix, dpi=(dpi, dpi))
def test_multi_polygons(self): path = Path(__file__).parent.joinpath( 'output/stripe_filled_polygon_drawer_multi_polygons.svg') path.unlink(missing_ok=True) canvas_builder = CanvasBuilder() canvas_builder.set_path(path) canvas_builder.set_size(Cu.from_pt(100), Cu.from_pt(100)) canvas = canvas_builder.build() drawer = StripeFilledPolygonDrawer() drawer.stripe_colors = [(1, 1, 0), None, (0.7, 0, 0.7), (0, 0, 0)] drawer.stripe_widths = [ Cu.from_pt(5), Cu.from_pt(5), Cu.from_pt(5), Cu.from_pt(5), ] drawer.stripe_origin = CanvasCoordinate.from_pt(30, 30) drawer.stripe_angle = math.pi / 8 # Vertical stripes drawer.geoms = [ MultiPolygon([ Polygon([ (30, 30), (70, 30), (70, 70), (30, 70), (30, 30), ], [[ (35, 35), (65, 35), (65, 65), (35, 65), (35, 35), ]]), Polygon([ (40, 40), (60, 40), (60, 60), (40, 60), (40, 40), ]) ]) ] drawer.draw(canvas) canvas.close() assert path.exists() with open(path, 'r') as file: data = file.read() assert data.find('fill:rgb(100%,100%,0%)') != -1 assert data.find('fill:rgb(0%,0%,0%)') != -1 assert data.find('fill:rgb(70%,0%,70%)') != -1 assert data.find('stroke:none') != -1 assert data.find('stroke-width:') == -1
def test_conversion(self): wgs84_crs = pyproj.CRS.from_epsg(4326) british_crs = pyproj.CRS.from_epsg(27700) coordinate_to_project = GeoCoordinate(55.862777, -4.260919, wgs84_crs) expected_canvas_coordinates = CanvasCoordinate( CanvasUnit.from_cm(1 + 6), CanvasUnit.from_cm(1 + 4)).pt origin_for_geo = GeoCoordinate(258000, 666000, british_crs) origin_for_canvas = CanvasCoordinate(CanvasUnit.from_cm(1), CanvasUnit.from_cm(1)) # 100 meters for every centimeter geo_to_canvas_scale = geo_canvas_ops.GeoCanvasScale( 100, CanvasUnit.from_cm(1)) transformation_func = geo_canvas_ops.build_transformer( crs=british_crs, data_crs=wgs84_crs, scale=geo_to_canvas_scale, origin_for_geo=origin_for_geo, origin_for_canvas=origin_for_canvas) self.assert_coordinates_are_close( transformation_func(*coordinate_to_project.tuple), expected_canvas_coordinates) # Repeat the same test, but this time without data_crs: transformation_func = geo_canvas_ops.build_transformer( crs=british_crs, scale=geo_to_canvas_scale, origin_for_geo=origin_for_geo, origin_for_canvas=origin_for_canvas) coordinate_to_project = GeoCoordinate(258600, 665600, british_crs) self.assert_coordinates_are_close( transformation_func(*coordinate_to_project.tuple), expected_canvas_coordinates)
def test_line_string(self): path = Path(__file__).parent.joinpath( 'output/line_drawer_line_string.svg') path.unlink(missing_ok=True) canvas_builder = CanvasBuilder() canvas_builder.set_path(path) canvas_builder.set_size(Cu.from_pt(100), Cu.from_pt(100)) canvas = canvas_builder.build() line_drawer = LineDrawer() line_drawer.stroke_color = (0, 1, 0) line_drawer.stroke_width = Cu.from_pt(1.5) line_drawer.stroke_dashes = ([ Cu.from_pt(1), Cu.from_pt(3), Cu.from_pt(3), Cu.from_pt(3) ], Cu.from_pt(4)) line_drawer.stroke_line_cap = cairocffi.constants.LINE_CAP_ROUND line_drawer.stroke_line_join = cairocffi.constants.LINE_JOIN_MITER line_drawer.geoms = [ LineString([ (30, 30), (70, 30), (70, 70), (30, 70), ]) ] line_drawer.draw(canvas) canvas.close() assert path.exists() with open(path, 'r') as file: data = file.read() assert data.find('M 30 30 L 70 30 L 70 70 L 30 70') != -1 assert data.find('fill:none') != -1 assert data.find('stroke-width:1.5') != -1 assert data.find('stroke:rgb(0%,100%,0%);') != -1
def test_setters_and_getters(self): # Create a canvas for the sake of instantiating a layout object. We do # this because that is how Pango actually resolves the font dimensions. path = Path(__file__).parent.joinpath( 'output/layout_setters_and_getters.svg') canvas_builder = CanvasBuilder() canvas_builder.set_path(path) canvas_builder.set_size(Cu.from_pt(100), Cu.from_pt(100)) canvas = canvas_builder.build() layout = Layout(canvas) layout.set_text('Hello world') layout.set_markup('<span weight="bold">Hello world!</span>') assert layout.width is None assert layout.height is None layout.width = Cu.from_pt(100) layout.height = Cu.from_pt(50) assert layout.width.pt == 100 assert layout.height.pt == 50 layout.reset_width() layout.reset_height() assert layout.width is None assert layout.height is None assert layout.position.x.pt == 0 assert layout.position.y.pt == 0 layout.position = CanvasCoordinate(Cu.from_pt(10), Cu.from_pt(5)) assert layout.position.x.pt == 10 assert layout.position.y.pt == 5 assert layout.color == (0, 0, 0, 1) layout.color = (0, 1, 0, 0.5) assert layout.color == (0, 1, 0, 0.5) assert layout.alignment == Alignment.LEFT layout.alignment = Alignment.RIGHT assert layout.alignment == Alignment.RIGHT extents = layout.logical_extents assert extents.pos.x.pt == 10 assert extents.pos.y.pt == 5 assert extents.width.pt > 1 assert extents.height.pt > 1
def get_file_dimensions_and_scale( path: Path) -> Tuple[float, float, float]: width: float height: float scale: float if path.suffix.lower() == '.pdf': pipe = subprocess.Popen( ['grep', '-a', 'MediaBox', path.as_posix()], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) stdout, stderr = pipe.communicate() stdout_str = str(stdout.decode('utf-8')) match = re.search(r'([0-9.]+) ([0-9.]+) ]', stdout_str) width = float(match.group(1)) height = float(match.group(2)) scale = 1.0 elif path.suffix.lower() == '.svg': pipe = subprocess.Popen( ['grep', '-a', '<svg', path.as_posix()], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) stdout, stderr = pipe.communicate() stdout_str = str(stdout.decode('utf-8')) width_match = re.search(r'width="([0-9.]+)pt"', stdout_str) height_match = re.search(r'height="([0-9.]+)pt"', stdout_str) width = float(width_match.group(1)) height = float(height_match.group(1)) scale = 1.0 else: from PIL import Image image = Image.open(path.as_posix()) width, height = image.size scale = CanvasUnit.from_px(float(image.info['dpi'][0])).inches image.close() return width, height, scale
def test_scale(self): path = Path(__file__).parent.joinpath('output/svg_scale.svg') path.unlink(missing_ok=True) canvas_builder = CanvasBuilder() canvas_builder.set_path(path) canvas_builder.set_size( Cu.from_cm(9), Cu.from_cm(6) ) canvas = canvas_builder.build() background = Background() background.color = (1, 0.8, 0.8, 1) background.draw(canvas) # No scaling svg = Svg(Path(__file__).parent.joinpath('test_svg.svg')) svg.position = Cc.from_cm(1, 1) svg.draw(canvas) # Scale 2x by height svg = Svg(Path(__file__).parent.joinpath('test_svg.svg')) svg.position = Cc.from_cm(5, 1) svg.width = Cu.from_cm(3) svg.draw(canvas) # Scale 2x by height svg = Svg(Path(__file__).parent.joinpath('test_svg.svg')) svg.position = Cc.from_cm(1, 4) svg.height = Cu.from_cm(1) svg.draw(canvas) # Scale without ratio preservation svg = Svg(Path(__file__).parent.joinpath('test_svg.svg')) svg.position = Cc.from_cm(5, 4) svg.width = Cu.from_cm(3) svg.height = Cu.from_cm(1) svg.draw(canvas) canvas.close() assert path.exists()
def read_svg_size(self) -> Tuple[CanvasUnit, CanvasUnit]: svg_surface = SvgSurface(self.path) return ( CanvasUnit.from_pt(svg_surface.svg_width), CanvasUnit.from_pt(svg_surface.svg_height) )
def __init__(self): self.stroke_color = (0, 0, 0, 1) self.stroke_width = CanvasUnit.from_pt(1) self.stroke_dashes = None self.stroke_line_cap = None self.stroke_line_join = None
def height(self) -> Optional[CanvasUnit]: pango_height = self._layout.get_height() if pango_height == -1: return None return CanvasUnit.from_pt(pangocffi.units_to_double(pango_height))