def _tonumpy(surface: cairo.ImageSurface): np_image = np.ndarray( shape=(surface.get_height(), surface.get_width(), 4), dtype=np.uint8, buffer=surface.get_data(), strides=(surface.get_width() * 4, 4, 1) ) np_image = np_image[:, :, :-1] np_image = np_image[:, :, ::-1] np_image = np_image.copy() return np_image
def _cairo_surface_write_to_bmp(img: cairo.ImageSurface) -> bytes: data = bytes(img.get_data()) return ( b"BM" + struct.pack( "<ihhiiiihhiiiiii", 54 + len(data), # size of BMP file 0, # unused 0, # unused 54, # pixel array offset 40, # DIB header img.get_width(), # width img.get_height(), # height 1, # planes 32, # BPP 0, # no compression len(data), # size of the raw bitmap data 2835, # 72DPI H 2835, # 72DPI V 0, # palette 0, # all colors are important ) + data )
def getMatrix(x: int, y: int, surf: cairo.ImageSurface): sx = surf.get_width() / 8.5 / 25.4 sy = surf.get_height() / 11 / 25.4 x0 = (origin[0] + deltaX * x) * sx y0 = (origin[1] + deltaY * y) * sy return cairo.Matrix(x0=x0, y0=y0, xx=sx, yy=sy)
def _surface_to_array(surface: cairo.ImageSurface) -> np.ndarray: """convert surface to array""" # NOTE! The format of the array is PREMULTIPLIED ALPHA, not RGBA! res = np.ndarray( (surface.get_height(), surface.get_width(), 4), # do height and width work here??? dtype=np.uint8, buffer=surface.get_data()) res = res[:, :, [2, 1, 0, 3]] # swap RGB order like OpenCV return res
def draw_frame(self, target: cairo.ImageSurface): ctx = cairo.Context(target) ctx.set_source_rgba(0.92, 0.72, 1, 0.3) w, h = target.get_width(), target.get_height() projection = np.dot(numgl.perspective(90, w / h, 0.1, 5), self.camera()) clip = pygl.transform(projection, self.positions) screen = pygl.get_screen(clip, (w, h)) for x, y, _ in screen: ctx.move_to(x, y) ctx.arc(x, y, 1, 0, TAU) ctx.fill()
def motionblur(target: cairo.ImageSurface, t: float, draw: Callable, look_ahead: float, n: int): w = target.get_width() h = target.get_width() frames = [] for tt in np.linspace(0, look_ahead, n): frame = np.zeros((w * h * 4,), dtype=np.uint8) surface = cairo.ImageSurface.create_for_data(memoryview(frame), cairo.Format.RGB24, w, h) draw(surface, t + tt) #frames.append(degamma(frame)) frames.append(frame) avg = np.average(np.stack(frames), axis=0).astype(np.uint8) #avg = gamma(np.average(np.stack(frames), axis=0)).astype(np.uint8) data = target.get_data() for i in range(len(data)): data[i] = avg[i]
def draw(self, target: cairo.ImageSurface): saved = self.positions, self.t n = 4 lookahead = 0.2 dt = lookahead / n targets = [] for _ in range(n): image = cairo.ImageSurface(cairo.Format.RGB24, target.get_width(), target.get_height()) self.draw_frame(image) targets.append(image) self.step(dt) data = target.get_data() for i in range(len(data)): data[i] = int(sum(img.get_data()[i] for img in targets) / n) self.positions, self.t = saved
def clear(target: cairo.ImageSurface, color=(1, 1, 1)) -> None: r, g, b = color ctx = cairo.Context(target) ctx.rectangle(0, 0, target.get_width(), target.get_height()) ctx.set_source_rgb(r, g, b) ctx.fill()
def clear(target: cairo.ImageSurface, color: Color=Color.WHITE) -> None: ctx = cairo.Context(target) ctx.rectangle(0, 0, target.get_width(), target.get_height()) ctx.set_source_rgb(color.r, color.g, color.b) ctx.fill()
def resolution(surface: cairo.ImageSurface) -> Resolution: return surface.get_width(), surface.get_height()
def downloadOSMMap(west, south, east, north, zoom, mapType=None): """ Download OSM map of selected area. Original was found on https://smyt.ru/blog/statc-osm-map-with-python/ Map may be download from few different OSM tile servers with different zoom. Download speed depends on size of selected area. Parameters ---------- weast,south,east,north : float coordinates of borders of map zoom : int map zoom, changes map detail mapType : {'white', 'dark', 'toner', None}, optional type of OSM tile server, default is None None - regular OSM map white, dark - white or dark cartodb OSM map toner - stamen toner OSM map Returns ------- numpy.array background map of selected area """ tiles = list(mercantile.tiles(west, south, east, north, zoom)) min_x = min([t.x for t in tiles]) min_y = min([t.y for t in tiles]) max_x = max([t.x for t in tiles]) max_y = max([t.y for t in tiles]) tile_size = (256, 256) map_image = ImageSurface( FORMAT_ARGB32, tile_size[0] * (max_x - min_x + 1), tile_size[1] * (max_y - min_y + 1), ) ctx = Context(map_image) def getTileUrl(mapType, zoom, x, y): if mapType == None: server = random.choice(["a", "b", "c"]) return "http://{server}.tile.openstreetmap.org/{zoom}/{x}/{y}.png".format( server=server, zoom=zoom, x=x, y=y) if mapType == "white": return "http://cartodb-basemaps-1.global.ssl.fastly.net/light_all/{zoom}/{x}/{y}.png".format( zoom=zoom, x=x, y=y) if mapType == "dark": return "http://cartodb-basemaps-2.global.ssl.fastly.net/dark_all/{zoom}/{x}/{y}.png".format( zoom=zoom, x=x, y=y) if mapType == "toner": return "http://a.tile.stamen.com/toner/{zoom}/{x}/{y}.png".format( zoom=zoom, x=x, y=y) for t in tiles: headers = { "User-Agent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.3" } url = getTileUrl(mapType, t.z, t.x, t.y) req = Request(url, headers=headers) response = urlopen(req) img = ImageSurface.create_from_png(io.BytesIO(response.read())) ctx.set_source_surface(img, (t.x - min_x) * tile_size[0], (t.y - min_y) * tile_size[0]) ctx.paint() bounds = { "left": min([mercantile.xy_bounds(t).left for t in tiles]), "right": max([mercantile.xy_bounds(t).right for t in tiles]), "bottom": min([mercantile.xy_bounds(t).bottom for t in tiles]), "top": max([mercantile.xy_bounds(t).top for t in tiles]), } kx = map_image.get_width() / (bounds["right"] - bounds["left"]) ky = map_image.get_height() / (bounds["top"] - bounds["bottom"]) left_top = mercantile.xy(west, north) right_bottom = mercantile.xy(east, south) offset_left = (left_top[0] - bounds["left"]) * kx offset_top = (bounds["top"] - left_top[1]) * ky offset_right = (bounds["right"] - right_bottom[0]) * kx offset_bottom = (right_bottom[1] - bounds["bottom"]) * ky result_width = map_image.get_width() - int(offset_left + offset_right) result_height = map_image.get_height() - int(offset_top + offset_bottom) map_image_clipped = ImageSurface(FORMAT_ARGB32, result_width, result_height) ctx = Context(map_image_clipped) ctx.set_source_surface(map_image, -offset_left, -offset_top) ctx.paint() def surface_to_npim(surface): """ Transforms a Cairo surface into a numpy array. """ im = +np.frombuffer(surface.get_data(), np.uint8) H, W = surface.get_height(), surface.get_width() im.shape = (H, W, 4) # for RGBA return im[:, :, :3] return surface_to_npim(map_image_clipped)