Coverage for qubalab/objects/draw.py: 100%
35 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-31 11:24 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-31 11:24 +0000
1from typing import Union
2from PIL import Image, ImageDraw
3import shapely
6def draw_geometry(image_size: tuple[int, int], drawing_context: ImageDraw.Draw, geometry: shapely.Geometry, value: int):
7 """
8 Draw the provided Shapely geometry with the provided drawing context using the provided value.
10 :param image_size: the size of the image to draw on
11 :param drawing_context: the drawing context to use
12 :param geometry: the geometry to draw
13 :param value: the value to use when drawing
14 """
15 if (isinstance(geometry, shapely.Point)):
16 _draw_point(drawing_context, geometry, value)
17 elif (isinstance(geometry, Union[shapely.LineString, shapely.LinearRing])):
18 _draw_line(drawing_context, geometry, value)
19 elif (isinstance(geometry, shapely.Polygon)):
20 _draw_polygon(image_size, drawing_context, geometry, value)
21 elif (isinstance(geometry, shapely.MultiPoint)):
22 for point in geometry.geoms:
23 _draw_point(drawing_context, point, value)
24 elif (isinstance(geometry, shapely.MultiLineString)):
25 for line in geometry.geoms:
26 _draw_line(drawing_context, line, value)
27 elif (isinstance(geometry, shapely.MultiPolygon)):
28 for polygon in geometry.geoms:
29 _draw_polygon(image_size, drawing_context, polygon, value)
30 elif (isinstance(geometry, shapely.GeometryCollection)):
31 for g in geometry.geoms:
32 draw_geometry(image_size, drawing_context, g, value)
34def _draw_point(drawing_context: ImageDraw, point: shapely.Point, value: int):
35 drawing_context.point([point.x, point.y], value)
37def _draw_line(drawing_context: ImageDraw, line: Union[shapely.LineString, shapely.LinearRing], value: int):
38 drawing_context.line(line.coords, value)
40def _draw_polygon(image_size: tuple[int, int], drawing_context: ImageDraw, polygon: shapely.Polygon, value: int):
41 # If we have holes, we risk overpainting existing pixels with the background color
42 # For that reason we need to create a separate binary image and then copy the values
43 if len(polygon.interiors) > 0:
44 bitmap = Image.new('1', image_size)
45 bitmap_draw = ImageDraw.Draw(bitmap)
47 bitmap_draw.polygon(polygon.exterior.coords, 1)
48 for interior in polygon.interiors:
49 bitmap_draw.polygon(interior.coords, 0)
51 drawing_context.bitmap((0, 0), bitmap, value)
52 else:
53 drawing_context.polygon(polygon.exterior.coords, value)