def export_as_image(self, *args, **kwargs): # overwrite the function, because ClearColor is set to black per default from kivy.core.image import Image scale = kwargs.get('scale', 1) if self.parent is not None: canvas_parent_index = self.parent.canvas.indexof(self.canvas) if canvas_parent_index > -1: self.parent.canvas.remove(self.canvas) fbo = Fbo(size=(self.width * scale, self.height * scale), with_stencilbuffer=True) with fbo: ClearColor(1, 1, 1, 1) ClearBuffers() Scale(1, -1, 1) Scale(scale, scale, 1) Translate(-self.x, -self.y - self.height, 0) fbo.add(self.canvas) fbo.draw() img = Image(fbo.texture) fbo.remove(self.canvas) if self.parent is not None and canvas_parent_index > -1: self.parent.canvas.insert(canvas_parent_index, self.canvas) return img
def create_texture(state, text, font_name): """ TODO """ font_def = state[globals.IDX_STATE_TEXT][font_name] text_lines = text.split("\n") n_lines = len(text_lines) max_line_length = len(max(text_lines, key=len)) texture_w = max_line_length * font_def[IDX_TEXT_WIDTH] texture_h = n_lines * font_def[IDX_TEXT_HEIGHT] texture = Texture.create(size=(texture_w, texture_h), colorfmt='rgba') fbo = Fbo(size=(texture_w, texture_h), texture=texture) for row in xrange(n_lines): cur_row = text_lines[row] for col in xrange(len(cur_row)): char = cur_row[col] char_texture = get_character_texture(state, font_name, char) x_pos = col * font_def[IDX_TEXT_WIDTH] y_pos = (n_lines - row - 1) * font_def[IDX_TEXT_HEIGHT] with fbo: Rectangle(pos=(x_pos, y_pos), size=(font_def[IDX_TEXT_WIDTH], font_def[IDX_TEXT_HEIGHT]), texture=char_texture) fbo.draw() return texture
def export_as_image(self, *args, **kwargs): '''Return an core :class:`~kivy.core.image.Image` of the actual widget. .. versionadded:: 1.11.0 ''' from kivy.core.image import Image scale = kwargs.get('scale', 1) if self.parent is not None: canvas_parent_index = self.parent.canvas.indexof(self.canvas) if canvas_parent_index > -1: self.parent.canvas.remove(self.canvas) fbo = Fbo(size=(self.width * scale, self.height * scale), with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 0) ClearBuffers() Scale(1, -1, 1) Scale(scale, scale, 1) Translate(-self.x, -self.y - self.height, 0) fbo.add(self.canvas) fbo.draw() img = Image(fbo.texture) fbo.remove(self.canvas) if self.parent is not None and canvas_parent_index > -1: self.parent.canvas.insert(canvas_parent_index, self.canvas) return img
def capture_image(self, filename): if self.parent is not None: canvas_parent_index = self.parent.canvas.indexof(self.canvas) if canvas_parent_index > -1: self.parent.canvas.remove(self.canvas) nw, nh = self.norm_image_size fbo = Fbo(size=(nw, nh), with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 0) ClearBuffers() Scale(1, -1, 1) x = -self.x - (self.width - nw) / 2 y = -self.y - (self.height - nh) / 2 - nh Translate(x, y, 0) fbo.add(self.canvas) fbo.draw() fbo.texture.save(filename, flipped=False) fbo.remove(self.canvas) if self.parent is not None and canvas_parent_index > -1: self.parent.canvas.insert(canvas_parent_index, self.canvas) return True
def export_to_png(self, filename, *args): '''Saves an image of the widget and its children in png format at the specified filename. Works by removing the widget canvas from its parent, rendering to an :class:`~kivy.graphics.fbo.Fbo`, and calling :meth:`~kivy.graphics.texture.Texture.save`. ''' if self.parent is not None: canvas_parent_index = self.parent.canvas.indexof(self.canvas) self.parent.canvas.remove(self.canvas) fbo = Fbo(size=self.size) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() Translate(-self.x, -self.y, 0) fbo.add(self.canvas) fbo.draw() fbo.texture.save(filename) fbo.remove(self.canvas) if self.parent is not None: self.parent.canvas.insert(canvas_parent_index, self.canvas) return True
def capture_image(self, filename): """ Capture only the visible part of the camera, without the black border. Similar to export_to_png but with adjusted coordinates. :param filename: path to the target file name :return True """ if self.parent is not None: canvas_parent_index = self.parent.canvas.indexof(self.canvas) if canvas_parent_index > -1: self.parent.canvas.remove(self.canvas) nw, nh = self.norm_image_size fbo = Fbo(size=(nw, nh), with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 0) ClearBuffers() Scale(1, -1, 1) x = -self.x-(self.width-nw)/2 y = -self.y-(self.height-nh)/2 - nh Translate(x, y, 0) fbo.add(self.canvas) fbo.draw() fbo.texture.save(filename, flipped=False) fbo.remove(self.canvas) if self.parent is not None and canvas_parent_index > -1: self.parent.canvas.insert(canvas_parent_index, self.canvas) return True
def save_png(self, filename): if not self.done_draw: # Don't save a blank drawing. return False self.do_drawing = False ### Kivy 1.8.1 has an export_to_png function in the widget class. I'm not using 1.8.1 so I'm writing my own. ## Mostly copy-pasted from: https://github.com/kivy/kivy/blob/master/kivy/uix/widget.py (2014/06/16) if self.parent is not None: canvas_parent_index = self.parent.canvas.indexof(self.canvas) self.parent.canvas.remove(self.canvas) fbo = Fbo(size=self.size_const) with fbo: ClearColor(0, 0, 0, 0) # I changed this from 0,0,0,1 to 0,0,0,0 so that I could have a transparent background. ClearBuffers() Translate(-self.draw_const[0], -self.draw_const[2], 0) fbo.add(self.canvas) fbo.draw() try: fbo.texture.save(filename) success = True kivy.logger.Logger.debug("PaintWidget: Saved file %s" % filename) except Exception as e: success = False kivy.logger.Logger.error("PaintWidget: Can't save file: %s" % filename) kivy.logger.Logger.exception(e) finally: fbo.remove(self.canvas) if self.parent is not None: self.parent.canvas.insert(canvas_parent_index, self.canvas) self.do_drawing = True return success
class FboTest(Widget): def __init__(self, **kwargs): super(FboTest, self).__init__(**kwargs) self.positions = [ (260.0, 260.0), (192.0, 192.0), (96.0, 192.0), (192.0, 96.0), (96.0, 96.0), (32.0, 192.0), (192.0, 32.0), (32.0, 32.0) ] self.fbo = Fbo(size=(256, 256)) with self.fbo: Color(0.56789, 0, 0, 1) Rectangle(size=(256, 64)) Color(0, 0.56789, 0, 1) Rectangle(size=(64, 256)) Color(0.56789, 0, 0, .5) Rectangle(pos=(64, 64), size=(192, 64)) Color(0, 0.56789, 0, .5) Rectangle(pos=(64, 64), size=(64, 192)) self.fbo.draw()
def insert_combined(state, texture_size, texture_name, texture_list): """ TODO """ tile_size = screen.get_tile_size(state) texture_size *= tile_size if len(texture_list) == 0: raise YapygTextureDbException( "insert_combined() called with empty list") elif len(texture_list) == 1: # Single texture, just load it and enter it with the # tile name as key to texture dict load(state, texture_name, texture_list[0]) else: # Combine several textures into one texture = Texture.create(size=(texture_size, texture_size), colorfmt='rgba') for texture_filename in texture_list: other_texture = Image(source=texture_filename).texture fbo = Fbo(size=(texture_size, texture_size), texture=texture) with fbo: Color(1, 1, 1) Rectangle(pos=(0, 0), size=other_texture.size, texture=other_texture) fbo.draw() insert(state, texture_name, texture)
def export_to_png(self, filename, *args): if self.parent is not None: canvas_parent_index = self.parent.canvas.indexof(self.canvas) if canvas_parent_index > -1: self.parent.canvas.remove(self.canvas) fbo = Fbo(size=self.size, with_stencilbuffer=True) with fbo: ClearColor(1, 1, 1, 1) ClearBuffers() Scale(1, -1, 1) Translate(-self.x, -self.y - self.height, 0) fbo.add(self.canvas) fbo.draw() fbo.texture.save(filename, flipped=False) fbo.remove(self.canvas) if self.parent is not None and canvas_parent_index > -1: self.parent.canvas.insert(canvas_parent_index, self.canvas) return True
def get_widget_pos_pixel(self, widget, positions): from kivy.graphics import Fbo, ClearColor, ClearBuffers canvas_parent_index = -2 if widget.parent is not None: canvas_parent_index = widget.parent.canvas.indexof(widget.canvas) if canvas_parent_index > -1: widget.parent.canvas.remove(widget.canvas) w, h = int(widget.width), int(widget.height) fbo = Fbo(size=(w, h), with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 0) ClearBuffers() fbo.add(widget.canvas) fbo.draw() pixels = fbo.pixels fbo.remove(widget.canvas) if widget.parent is not None and canvas_parent_index > -1: widget.parent.canvas.insert(canvas_parent_index, widget.canvas) values = [] for x, y in positions: x = int(x) y = int(y) i = y * w * 4 + x * 4 values.append(tuple(pixels[i:i + 4])) return values
def get_frame_data(self, *args): """Return the content of this display as buffer. @see: widget.export_to_png """ del args if self._slide_manager_parent.parent is not None: canvas_parent_index = self._slide_manager_parent.parent.canvas.indexof(self._slide_manager_parent.canvas) if canvas_parent_index > -1: self._slide_manager_parent.parent.canvas.remove(self._slide_manager_parent.canvas) fbo = Fbo(size=self._slide_manager_parent.size, with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() Scale(1, -1, 1) Translate(-self._slide_manager_parent.x, -self._slide_manager_parent.y - self._slide_manager_parent.height, 0) fbo.add(self._slide_manager_parent.canvas) fbo.draw() data = fbo.texture.pixels fbo.remove(self._slide_manager_parent.canvas) if self._slide_manager_parent.parent is not None and canvas_parent_index > -1: self._slide_manager_parent.parent.canvas.insert(canvas_parent_index, self._slide_manager_parent.canvas) return data
def bitmap(self): # self.export_to_png('test.png') # remove cross self.canvas.after.clear() image_scale = 36 / self.width fbo = Fbo(size=(36, 27), with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 0) ClearBuffers() Scale(image_scale, -image_scale, image_scale) Translate(-self.x, -self.y - self.height, 0) fbo.add(self.canvas) fbo.draw() # fbo.texture.save('test_small.png', flipped=False) bm = np.fromstring(fbo.pixels, dtype=np.uint8).reshape(fbo.size[1], fbo.size[0], 4) fbo.remove(self.canvas) # return cross self.add_cross() return np.int64(np.all(bm[:, :, :3] == 0, axis=2))
def export_to_png(self, filename, *args): '''Saves an image of the widget and its children in png format at the specified filename. Works by removing the widget canvas from its parent, rendering to an :class:`~kivy.graphics.fbo.Fbo`, and calling :meth:`~kivy.graphics.texture.Texture.save`. ''' if self.parent is not None: canvas_parent_index = self.parent.canvas.indexof(self.canvas) self.parent.canvas.remove(self.canvas) fbo = Fbo(size=self.size, with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() Translate(-self.x, -self.y, 0) fbo.add(self.canvas) fbo.draw() fbo.texture.save(filename, flipped=False) fbo.remove(self.canvas) if self.parent is not None: self.parent.canvas.insert(canvas_parent_index, self.canvas) return True
def get_root_pixels(self): """Returns all the pixels values of the widget containing the shapes, as well as the size of that widget. This is how you can save an image of whatever is currently displayed on screen. """ widget = self.root.ids.display_canvas canvas_parent_index = widget.parent.canvas.indexof(widget.canvas) if canvas_parent_index > -1: widget.parent.canvas.remove(widget.canvas) fbo = Fbo(size=widget.size, with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() Scale(1, -1, 1) Translate(0, -widget.height, 0) fbo.add(widget.canvas) fbo.draw() pixels = fbo.pixels fbo.remove(widget.canvas) if canvas_parent_index > -1: widget.parent.canvas.insert(canvas_parent_index, widget.canvas) return pixels, widget.size
def save_montage(background): fbo = Fbo(size=PAPER_SIZE) w, h = fbo.size length = int(0.9 * w) # Picture will be square of 90% of paper width length = min(length, int(h * 0.85 / NPHOTOS)) with fbo: Rectangle(size=fbo.size, pos=(0, 0), texture=background) for i in range(NPHOTOS): Rectangle(size=(length, length), pos=(int(0.5 * (w - length)), int(h - (i + 1) * (0.25 * (w - length) + length))), texture=self.snaps[i]) # Carry the actual draw fbo.draw() # Save the final composition stamp = datetime.now().strftime("%Y%m%d_%H%M%S") montage_file = osp.join(curdir, STORAGE_FOLDER, "picture_{}.jpg".format(stamp)) fbo.bind() fbo.texture.save(montage_file, flipped=True) fbo.release() del fbo return montage_file
def load_walls(state, base_name, background_file, tile_file, with_collisions=True): """ TODO """ tile_size = screen.get_tile_size(state) int_tile_size = int(tile_size) background_texture = Image(source=background_file).texture walls_texture = Image(source=tile_file).texture for tile_name, origin_xy, collision in tiles_origin_table: full_tile_name = base_name + tile_name wall_texture = walls_texture.get_region( origin_xy[0] * int_tile_size, origin_xy[1] * int_tile_size, int_tile_size, int_tile_size) tile_texture = Texture.create(size=(int_tile_size, int_tile_size), colorfmt='rgba') fbo = Fbo(size=(int_tile_size, int_tile_size), texture=tile_texture) with fbo: Color(1, 1, 1) Rectangle(pos=(0, 0), size=tile_texture.size, texture=background_texture) Rectangle(pos=(0, 0), size=tile_texture.size, texture=wall_texture) fbo.draw() if not with_collisions: collision = None tiles.add_tile_def(state, full_tile_name, tile_texture, collision)
def add_image(self, widget): filename = f"tmp_{self.img_counter}.png" output_size = (self.meta_data["width"], self.meta_data["height"]) if self.meta_data["WH_ratio"] != widget.width // widget.height: raise Exception("W/H ratio does not match") img_scale = self.meta_data["width"] / widget.width if widget.parent is not None: canvas_parent_index = widget.parent.canvas.indexof(widget.canvas) if canvas_parent_index > -1: widget.parent.canvas.remove(widget.canvas) fbo = Fbo(size=output_size, with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 0) ClearBuffers() Scale(img_scale, -img_scale, img_scale) Translate(-widget.x, -widget.y - widget.height, 0) fbo.add(widget.canvas) fbo.draw() fbo.texture.save(self.tmp_imgs_path + filename, flipped=False) fbo.remove(widget.canvas) if widget.parent is not None and canvas_parent_index > -1: widget.parent.canvas.insert(canvas_parent_index, widget.canvas) self.img_counter += 1
def toImage(self, bg_color=(1,1,1,0)): #create image widget with texture == to a snapshot of me from kivy.graphics import Translate, Fbo, ClearColor, ClearBuffers, Scale from kivy.core.image import Image as CoreImage if self.parent is not None: canvas_parent_index = self.parent.canvas.indexof(self.canvas) self.parent.canvas.remove(self.canvas) fbo = Fbo(size=self.size, with_stencilbuffer=True) with fbo: ClearColor(*bg_color) ClearBuffers() Scale(1, -1, 1) Translate(-self.x, -self.y - self.height, 0) fbo.add(self.canvas) fbo.draw() #EventLoop.idle() cim = CoreImage(fbo.texture, filename = '%s.png'%id(self)) fbo.remove(self.canvas) if self.parent is not None: self.parent.canvas.insert(canvas_parent_index, self.canvas) return cim
def export_to_png(self, filename, *args, **kwargs): '''Saves an image of the widget and its children in png format at the specified filename. Works by removing the widget canvas from its parent, rendering to an :class:`~kivy.graphics.fbo.Fbo`, and calling :meth:`~kivy.graphics.texture.Texture.save`. .. note:: The image includes only this widget and its children. If you want to include widgets elsewhere in the tree, you must call :meth:`~Widget.export_to_png` from their common parent, or use :meth:`~kivy.core.window.WindowBase.screenshot` to capture the whole window. .. note:: The image will be saved in png format, you should include the extension in your filename. .. versionadded:: 1.9.0 :Parameters: `filename`: str The filename with which to save the png. `scale`: float The amount by which to scale the saved image, defaults to 1. .. versionadded:: 1.11.0 ''' scale = kwargs.get('scale', 1) if self.parent is not None: canvas_parent_index = self.parent.canvas.indexof(self.canvas) if canvas_parent_index > -1: self.parent.canvas.remove(self.canvas) fbo = Fbo(size=(self.width * scale, self.height * scale), with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 0) ClearBuffers() Scale(1, -1, 1) Scale(scale, scale, 1) Translate(-self.x, -self.y - self.height, 0) fbo.add(self.canvas) fbo.draw() fbo.texture.save(filename, flipped=False) fbo.remove(self.canvas) if self.parent is not None and canvas_parent_index > -1: self.parent.canvas.insert(canvas_parent_index, self.canvas) return True
def circle_fs(size=(64, 64)): fbo = Fbo(size=size) fbo.shader.fs = circle_test with fbo: Color(1, 1, 1) Rectangle(size=size) fbo.draw() return fbo.texture
def test_fbo_pixels(self): from kivy.graphics import Fbo, ClearColor, ClearBuffers, Ellipse fbo = Fbo(size=(512, 512)) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() Ellipse(pos=(100, 100), size=(100, 100)) fbo.draw() data = fbo.pixels fbo.texture.save('results.png')
def hue_transform(source, hue, size=(64, 64)): fbo = Fbo(size=size) fbo.shader.fs = hue_xfo # use the shader on the entire surface fbo['hueAdjust'] = float(hue) with fbo: Color(1, 1, 1) Rectangle(size=size, source=source) fbo.draw() return fbo.texture
def advanced_gradient(border_color=(1, 1, 0), center_color=(1, 0, 0), size=(64, 64),fs=radial_grd_fs): fbo = Fbo(size=size) fbo.shader.fs = fs # use the shader on the entire surface fbo['border_color'] = map(float, border_color) fbo['center_color'] = map(float, center_color) with fbo: Color(1, 1, 1) Rectangle(size=size) fbo.draw() return fbo.texture
def test_fbo_pixels(self): from kivy.graphics import Fbo, ClearColor, ClearBuffers, Ellipse fbo = Fbo(size=(512, 512)) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() Ellipse(pos=(100, 100), size=(100, 100)) fbo.draw() data = fbo.pixels import pygame surface = pygame.image.fromstring(data, (512, 512), 'RGBA', True) pygame.image.save(surface, "results.png")
def insert_color_ellipse(state, texture_w, texture_h, texture_name, c_r, c_g, c_b): """ TODO """ tile_size = screen.get_tile_size(state) texture_w *= tile_size texture_h *= tile_size texture = Texture.create(size=(texture_w, texture_h), colorfmt='rgba') fbo = Fbo(size=(texture_w, texture_h), texture=texture) with fbo: Color(c_r, c_g, c_b) Ellipse(pos=(0, 0), size=(texture_w, texture_h)) fbo.draw() insert(state, texture_name, texture)
def export_scaled_png(self): re_size = (720, 480) image_scale = 720/self.width fbo = Fbo(size=re_size, with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 0) ClearBuffers() Scale(image_scale, -image_scale, image_scale) Translate(-self.x, -self.y - self.height, 0) fbo.add(self.canvas) fbo.draw() fbo.texture.save('images/complete/%s_mask.jpg'%self.img_name[:-4], flipped=False) fbo.remove(self.canvas)
def export_to_png(self, filename, *args): if self.parent is not None: canvas_parent_index = self.parent.canvas.indexof(self.canvas) self.parent.canvas.remove(self.canvas) fbo = Fbo(size=self.size, with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() Scale(1, -1, 1) Translate(-self.x, -self.y - self.height, 0) fbo.add(self.canvas) fbo.draw() fbo.texture.save(filename, flipped=False) fbo.remove(self.canvas) if self.parent is not None: self.parent.canvas.insert(canvas_parent_index, self.canvas) return True
def toImage(self, bg_color=(1,1,1,0), for_print = False): #print 'toImage with bg_color', self, bg_color #create image widget with texture == to a snapshot of me from kivy.graphics import Translate, Fbo, ClearColor, ClearBuffers, Scale from kivy.core.image import Image as CoreImage if self.parent is not None: canvas_parent_index = self.parent.canvas.indexof(self.canvas) self.parent.canvas.remove(self.canvas) if for_print:# make all not printed element disappear disappear = set() from fields import BaseField for children in self.walk(): if not isinstance(children, BaseField): continue if children.printed: continue Logger.debug('Hiding item not printed %s'%children) disappear.add((children, children.opacity)) children.opacity = 0 fbo = Fbo(size=self.size, with_stencilbuffer=True) with fbo: ClearColor(*bg_color) ClearBuffers() Scale(1, -1, 1) Translate(-self.x, -self.y - self.height, 0) fbo.add(self.canvas) fbo.draw() cim = CoreImage(fbo.texture, filename='%s.png'%id(self)) fbo.remove(self.canvas) if for_print: for (children, opacity) in disappear: children.opacity = opacity if self.parent is not None: self.parent.canvas.insert(canvas_parent_index, self.canvas) return cim
def export_to_png(self, filename, *args): '''Saves an image of the widget and its children in png format at the specified filename. Works by removing the widget canvas from its parent, rendering to an :class:`~kivy.graphics.fbo.Fbo`, and calling :meth:`~kivy.graphics.texture.Texture.save`. .. note:: The image includes only this widget and its children. If you want to include widgets elsewhere in the tree, you must call :meth:`~Widget.export_to_png` from their common parent, or use :meth:`~kivy.core.window.WindowBase.screenshot` to capture the whole window. .. note:: The image will be saved in png format, you should include the extension in your filename. .. versionadded:: 1.9.0 ''' if self.parent is not None: canvas_parent_index = self.parent.canvas.indexof(self.canvas) if canvas_parent_index > -1: self.parent.canvas.remove(self.canvas) fbo = Fbo(size=self.size, with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() Scale(1, -1, 1) Translate(-self.x, -self.y - self.height, 0) fbo.add(self.canvas) fbo.draw() fbo.texture.save(filename, flipped=False) fbo.remove(self.canvas) if self.parent is not None and canvas_parent_index > -1: self.parent.canvas.insert(canvas_parent_index, self.canvas) return True
def export_to_png(self, filename, *args): '''Saves an image of the widget and its children in png format at the specified filename. Works by removing the widget canvas from its parent, rendering to an :class:`~kivy.graphics.fbo.Fbo`, and calling :meth:`~kivy.graphics.texture.Texture.save`. .. note:: The image includes only this widget and its children. If you want to include widgets elsewhere in the tree, you must call :meth:`~Widget.export_to_png` from their common parent, or use :meth:`~kivy.core.window.Window.screenshot` to capture the whole window. .. note:: The image will be saved in png format, you should include the extension in your filename. .. versionadded:: 1.8.1 ''' if self.parent is not None: canvas_parent_index = self.parent.canvas.indexof(self.canvas) self.parent.canvas.remove(self.canvas) fbo = Fbo(size=self.size) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() Translate(-self.x, -self.y, 0) fbo.add(self.canvas) fbo.draw() fbo.texture.save(filename) fbo.remove(self.canvas) if self.parent is not None: self.parent.canvas.insert(canvas_parent_index, self.canvas) return True
def radial_gradient(border_color=(1, 1, 0), center_color=(1, 0, 0), size=(64, 64)): fbo = Fbo(size=size) fbo.shader.fs = ''' $HEADER$ uniform vec3 border_color; uniform vec3 center_color; void main (void) { float d = clamp(distance(tex_coord0, vec2(0.5, 0.5)), 0., 1.); gl_FragColor = vec4(mix(center_color, border_color, d), 1); } ''' # use the shader on the entire surface fbo['border_color'] = [float(x) for x in border_color] fbo['center_color'] = [float(x) for x in center_color] with fbo: Color(1, 1, 1) Rectangle(size=size) fbo.draw() return fbo.texture
def get_frame_data(self, *args): """Return the content of this display as buffer. @see: widget.export_to_png """ del args fbo = Fbo(size=self._slide_manager_parent.size, with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() Scale(1, -1, 1) Translate(-self.x, -self.y - self.height, 0) fbo.add(self.canvas) fbo.draw() data = fbo.texture.pixels fbo.remove(self.canvas) return data
def export_scaled_jpg(self, widget, filename, image_scale=1): from kivy.graphics import (Translate, Fbo, ClearColor, ClearBuffers, Scale) re_size = (widget.width * image_scale, widget.height * image_scale) if widget.parent is not None: canvas_parent_index = widget.parent.canvas.indexof(widget.canvas) if canvas_parent_index > -1: widget.parent.canvas.remove(widget.canvas) try: fbo = Fbo(size=re_size, with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 0) ClearBuffers() Scale(image_scale, -image_scale, image_scale) Translate(-widget.x, -widget.y - widget.height, 0) fbo.add(widget.canvas) fbo.draw() from io import BytesIO image_bytes = BytesIO() fbo.texture.save(image_bytes, flipped=False, fmt='png') image_bytes.seek(0) from PIL import Image image = Image.open(image_bytes) image = image.convert('RGB') image.save(filename) exported = True except Exception as ex: exported = str(ex) try: fbo.remove(widget.canvas) except: pass if widget.parent is not None and canvas_parent_index > -1: widget.parent.canvas.insert(canvas_parent_index, widget.canvas) return exported
def render_background(self, *args): fbo = Fbo(size=app.root.size, with_stencilbuffer=True) with fbo: Scale(1, -1, 1) Translate(-app.root.x, -app.root.y - app.root.height, 0) fbo.add(app.root.canvas) fbo.draw() fbo.remove(app.root.canvas) tex = fbo.texture img = Image.frombytes('RGBA', tex.size, tex.pixels) img = img.filter(ImageFilter.GaussianBlur(50)) tex = Texture.create(size=img.size) tex.blit_buffer(pbuffer=img.tobytes(), size=img.size, colorfmt='rgba') tex.flip_vertical() self.canvas.before.get_group('blur')[0].texture = tex Window.canvas.insert(0, app.root.canvas)
def make_screen_fbo(self, screen, mode=None): assert(mode is not None) attr = 'fbo_' + mode fbo = getattr(self, attr) w, h = screen.size w = (w - w % TILE) + TILE h = (h - h % TILE) + TILE size = w, h if not fbo: fbo = Fbo(size=size) setattr(self, attr, fbo) fbo.clear() with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() fbo.add(screen.canvas) fbo.draw() return fbo
def get_root_pixels(self): widget = self.root.ids.display_canvas canvas_parent_index = widget.parent.canvas.indexof(widget.canvas) if canvas_parent_index > -1: widget.parent.canvas.remove(widget.canvas) fbo = Fbo(size=widget.size, with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() Scale(1, -1, 1) Translate(0, -widget.height, 0) fbo.add(widget.canvas) fbo.draw() pixels = fbo.pixels fbo.remove(widget.canvas) if canvas_parent_index > -1: widget.parent.canvas.insert(canvas_parent_index, widget.canvas) return pixels, widget.size
def make_fbo(self, *args): if self.parent is not None: canvas_parent_index = self.parent.canvas.indexof(self.canvas) if canvas_parent_index > -1: self.parent.canvas.remove(self.canvas) fbo = Fbo(size=self.size, with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 0) ClearBuffers() Scale(1, -1, 1) Translate(-self.x, -self.y - self.height, 0) fbo.add(self.canvas) fbo.draw() fbo.remove(self.canvas) if self.parent is not None and canvas_parent_index > -1: self.parent.canvas.insert(canvas_parent_index, self.canvas) return fbo
def create_texture(state, text, font_name): """ TODO """ font_def = state[IDX_STATE_TEXT][font_name] text_lines = text.split("\n") n_lines = len(text_lines) max_line_length = len(max(text_lines, key=len)) texture_w = max_line_length * font_def[IDX_TEXT_WIDTH] texture_h = n_lines * font_def[IDX_TEXT_HEIGHT] texture = Texture.create(size=(texture_w, texture_h), colorfmt='rgba') fbo = Fbo(size=(texture_w, texture_h), texture=texture) for row in xrange(n_lines): cur_row = text_lines[row] for col in xrange(len(cur_row)): char = cur_row[col] char_texture = get_character_texture(state, font_name, char) x_pos = col * font_def[IDX_TEXT_WIDTH] y_pos = (n_lines - row - 1) * font_def[IDX_TEXT_HEIGHT] with fbo: Rectangle(pos=(x_pos, y_pos), size=(font_def[IDX_TEXT_WIDTH], font_def[IDX_TEXT_HEIGHT]), texture=char_texture) fbo.draw() return texture
def _get_canvas_instructions(self): """ Returns canvas instructions used to manipulate the visual appearance of the widget. Canvas instructions from here are singleton, that way to parallel animation can operate on the same set of instructions""" if self.uid in CanvasWidget._reg: CanvasWidget._reg[self.uid][-1] += 1 else: widget = self.widget # Grab widget.canvas texture. (From Widget.export_to_png) if widget.parent is not None: canvas_parent_index = widget.parent.canvas.indexof( widget.canvas) if canvas_parent_index > -1: widget.parent.canvas.remove(widget.canvas) fbo = Fbo(size=widget.size, with_stencilbuffer=True) with fbo: Translate(-widget.x, -widget.y, 0) fbo.add(widget.canvas) fbo.draw() fbo.remove(widget.canvas) if widget.parent is not None and canvas_parent_index > -1: widget.parent.canvas.insert(canvas_parent_index, widget.canvas) # End grab c = (1, 1, 1, 1) if not self._debug else (1, 0, 1, 0.5) with self.root_widget.canvas: PushMatrix() scale = Scale(1, 1, 1) rotate = Rotate(angle=0, axis=(0, 0, 1)) color = Color(*c) rect = Rectangle( size=widget.size, pos=widget.pos, texture=fbo.texture) PopMatrix() CanvasWidget._reg[self.uid] = [scale, rotate, color, rect, 1] return CanvasWidget._reg[self.uid][:-1]
def insert_combined(state, texture_size, texture_name, texture_list): """ TODO """ tile_size = screen.get_tile_size(state) texture_size *= tile_size if len(texture_list) == 0: raise YapygTextureDbException("insert_combined() called with empty list") elif len(texture_list) == 1: # Single texture, just load it and enter it with the # tile name as key to texture dict load(state, texture_name, texture_list[0]) else: # Combine several textures into one texture = Texture.create(size=(texture_size, texture_size), colorfmt='rgba') for texture_filename in texture_list: other_texture = Image(source=texture_filename).texture fbo = Fbo(size=(texture_size, texture_size), texture=texture) with fbo: Color(1, 1, 1) Rectangle(pos=(0, 0), size=other_texture.size, texture=other_texture) fbo.draw() insert(state, texture_name, texture)
class Slide(Factory.ButtonBehavior, Factory.Image): ctrl = ObjectProperty(None) slide_rotation = NumericProperty(0) slide_scale = NumericProperty(1.) slide_pos = ListProperty([0,0]) selected = BooleanProperty(False) index = NumericProperty(0) def __init__(self, **kwargs): # get raw rgb thumb is available self.thumb = kwargs.get('thumb', None) del kwargs['thumb'] # extract controler now, we need it. self.ctrl = kwargs.get('ctrl') # create fbo for tiny texture self.fbo = Fbo(size=(160, 120)) with self.fbo: Color(1, 1, 1) Rectangle(size=self.fbo.size) self.fborect = Rectangle(size=self.fbo.size) if self.thumb: self.upload_thumb() else: self.update_capture() super(Slide, self).__init__(**kwargs) def on_press(self, touch): if touch.is_double_tap: self.ctrl.remove_slide(self) else: self.ctrl.select_slide(self) def update_capture(self, *largs): edit_mode = self.ctrl.is_edit self.ctrl.is_edit = False # update main fbo fbo = self.ctrl.capture.fbo fbo.ask_update() fbo.draw() # update our tiny fbo self.fborect.texture = fbo.texture self.fbo.ask_update() self.fbo.draw() # then bind the texture to our texture image self.texture = self.fbo.texture self.texture_size = self.texture.size self.ctrl.is_edit = edit_mode self.ctrl.set_dirty() self.thumb = None def download_thumb(self): if self.thumb is None: fbo = self.fbo fbo.draw() fbo.bind() tmp = glReadPixels(0, 0, fbo.size[0], fbo.size[1], GL_RGBA, GL_UNSIGNED_BYTE) fbo.release() # remove alpha tmp = list(tmp) del tmp[3::4] tmp = ''.join(tmp) self.thumb = (fbo.size[0], fbo.size[1], tmp) def upload_thumb(self): from kivy.graphics.texture import Texture w, h, pixels = self.thumb texture = Texture.create((w, h), 'rgb', 'ubyte') texture.blit_buffer(pixels, colorfmt='rgb') self.texture = texture self.texture_size = texture.size
class CameraAndroid(CameraBase): """ Implementation of CameraBase using Android API """ def __init__(self, **kwargs): self._android_camera = None self._preview_cb = PreviewCallback(self._on_preview_frame) self._buflock = threading.Lock() super(CameraAndroid, self).__init__(**kwargs) def __del__(self): self._release_camera() def init_camera(self): self._release_camera() self._android_camera = Camera.open(self._index) params = self._android_camera.getParameters() width, height = self._resolution params.setPreviewSize(width, height) self._android_camera.setParameters(params) # self._android_camera.setDisplayOrientation() self.fps = 30. pf = params.getPreviewFormat() assert(pf == ImageFormat.NV21) # default format is NV21 self._bufsize = int(ImageFormat.getBitsPerPixel(pf) / 8. * width * height) self._camera_texture = Texture(width=width, height=height, target=GL_TEXTURE_EXTERNAL_OES, colorfmt='rgba') self._surface_texture = SurfaceTexture(int(self._camera_texture.id)) self._android_camera.setPreviewTexture(self._surface_texture) self._fbo = Fbo(size=self._resolution) self._fbo.shader.fs = ''' #extension GL_OES_EGL_image_external : require #ifdef GL_ES precision highp float; #endif /* Outputs from the vertex shader */ varying vec4 frag_color; varying vec2 tex_coord0; /* uniform texture samplers */ uniform sampler2D texture0; uniform samplerExternalOES texture1; void main() { gl_FragColor = texture2D(texture1, tex_coord0); } ''' with self._fbo: self._texture_cb = Callback(lambda instr: self._camera_texture.bind) Rectangle(size=self._resolution) def _release_camera(self): if self._android_camera is None: return self.stop() self._android_camera.release() self._android_camera = None self._texture = None # clear texture and it'll be reset in `_update` pointing to new FBO del self._fbo, self._surface_texture, self._camera_texture def _on_preview_frame(self, data, camera): with self._buflock: if self._buffer is not None: self._android_camera.addCallbackBuffer(self._buffer) # add buffer back for reuse self._buffer = data # print self._buffer, len(self.frame_data) # check if frame grabbing works def _refresh_fbo(self): self._texture_cb.ask_update() self._fbo.draw() def start(self): super(CameraAndroid, self).start() with self._buflock: self._buffer = None for k in range(2): # double buffer buf = '\x00' * self._bufsize self._android_camera.addCallbackBuffer(buf) self._android_camera.setPreviewCallbackWithBuffer(self._preview_cb) self._android_camera.startPreview() Clock.unschedule(self._update) Clock.schedule_interval(self._update, 1./self.fps) def stop(self): super(CameraAndroid, self).stop() Clock.unschedule(self._update) self._android_camera.stopPreview() self._android_camera.setPreviewCallbackWithBuffer(None) # buffer queue cleared as well, to be recreated on next start with self._buflock: self._buffer = None def _update(self, dt): self._surface_texture.updateTexImage() self._refresh_fbo() if self._texture is None: self._texture = self._fbo.texture self.dispatch('on_load') self._copy_to_gpu() def _copy_to_gpu(self): """ A dummy placeholder (the image is already in GPU) to be consistent with other providers. """ self.dispatch('on_texture') def grab_frame(self): """ Grab current frame (thread-safe, minimal overhead) """ with self._buflock: if self._buffer is None: return None buf = self._buffer.tostring() return buf def decode_frame(self, buf): """ Decode image data from grabbed frame. This method depends on OpenCV and NumPy - however it is only used for fetching the current frame as a NumPy array, and not required when this :class:`CameraAndroid` provider is simply used by a :class:`~kivy.uix.camera.Camera` widget. """ import numpy as np from cv2 import cvtColor w, h = self._resolution arr = np.fromstring(buf, 'uint8').reshape((h+h/2, w)) arr = cvtColor(arr, 93) # NV21 -> BGR return arr def read_frame(self): """ Grab and decode frame in one call """ return self.decode_frame(self.grab_frame()) @staticmethod def get_camera_count(): """ Get the number of available cameras. """ return Camera.getNumberOfCameras()
class EffectWidget(RelativeLayout): ''' Widget with the ability to apply a series of graphical effects to its children. See the module documentation for more information on setting effects and creating your own. ''' background_color = ListProperty((0, 0, 0, 1)) '''This defines the background color to be used for the fbo in the EffectWidget. :attr:`background_color` is a :class:`ListProperty` defaults to (0, 0, 0, 1) ''' texture = ObjectProperty(None) '''The output texture of the final :class:`~kivy.graphics.Fbo` after all effects have been applied. texture is an :class:`~kivy.properties.ObjectProperty` and defaults to None. ''' effects = ListProperty([]) '''List of all the effects to be applied. These should all be instances or subclasses of :class:`EffectBase`. effects is a :class:`ListProperty` and defaults to []. ''' fbo_list = ListProperty([]) '''(internal) List of all the fbos that are being used to apply the effects. fbo_list is a :class:`ListProperty` and defaults to []. ''' _bound_effects = ListProperty([]) '''(internal) List of effect classes that have been given an fbo to manage. This is necessary so that the fbo can be removed if the effect is no longer in use. _bound_effects is a :class:`ListProperty` and defaults to []. ''' def __init__(self, **kwargs): # Make sure opengl context exists EventLoop.ensure_window() self.canvas = RenderContext(use_parent_projection=True, use_parent_modelview=True) with self.canvas: self.fbo = Fbo(size=self.size) with self.fbo.before: PushMatrix() with self.fbo: ClearColor(0, 0, 0, 0) ClearBuffers() self._background_color = Color(*self.background_color) self.fbo_rectangle = Rectangle(size=self.size) with self.fbo.after: PopMatrix() super(EffectWidget, self).__init__(**kwargs) Clock.schedule_interval(self._update_glsl, 0) fbind = self.fbind fbo_setup = self.refresh_fbo_setup fbind('size', fbo_setup) fbind('effects', fbo_setup) fbind('background_color', self._refresh_background_color) self.refresh_fbo_setup() self._refresh_background_color() # In case thi was changed in kwargs def _refresh_background_color(self, *args): self._background_color.rgba = self.background_color def _update_glsl(self, *largs): '''(internal) Passes new time and resolution uniform variables to the shader. ''' time = Clock.get_boottime() resolution = [float(size) for size in self.size] self.canvas['time'] = time self.canvas['resolution'] = resolution for fbo in self.fbo_list: fbo['time'] = time fbo['resolution'] = resolution def refresh_fbo_setup(self, *args): '''(internal) Creates and assigns one :class:`~kivy.graphics.Fbo` per effect, and makes sure all sizes etc. are correct and consistent. ''' # Add/remove fbos until there is one per effect while len(self.fbo_list) < len(self.effects): with self.canvas: new_fbo = EffectFbo(size=self.size) with new_fbo: ClearColor(0, 0, 0, 0) ClearBuffers() Color(1, 1, 1, 1) new_fbo.texture_rectangle = Rectangle(size=self.size) new_fbo.texture_rectangle.size = self.size self.fbo_list.append(new_fbo) while len(self.fbo_list) > len(self.effects): old_fbo = self.fbo_list.pop() self.canvas.remove(old_fbo) # Remove fbos from unused effects for effect in self._bound_effects: if effect not in self.effects: effect.fbo = None self._bound_effects = self.effects # Do resizing etc. self.fbo.size = self.size self.fbo_rectangle.size = self.size for i in range(len(self.fbo_list)): self.fbo_list[i].size = self.size self.fbo_list[i].texture_rectangle.size = self.size # If there are no effects, just draw our main fbo if len(self.fbo_list) == 0: self.texture = self.fbo.texture return for i in range(1, len(self.fbo_list)): fbo = self.fbo_list[i] fbo.texture_rectangle.texture = self.fbo_list[i - 1].texture # Build effect shaders for effect, fbo in zip(self.effects, self.fbo_list): effect.fbo = fbo self.fbo_list[0].texture_rectangle.texture = self.fbo.texture self.texture = self.fbo_list[-1].texture for fbo in self.fbo_list: fbo.draw() self.fbo.draw() def add_widget(self, widget): # Add the widget to our Fbo instead of the normal canvas c = self.canvas self.canvas = self.fbo super(EffectWidget, self).add_widget(widget) self.canvas = c def remove_widget(self, widget): # Remove the widget from our Fbo instead of the normal canvas c = self.canvas self.canvas = self.fbo super(EffectWidget, self).remove_widget(widget) self.canvas = c def clear_widgets(self, children=None): # Clear widgets from our Fbo instead of the normal canvas c = self.canvas self.canvas = self.fbo super(EffectWidget, self).clear_widgets(children) self.canvas = c
def export_to_png(self, filename, *args): '''Saves an image of the widget and its children in png format at the specified filename. Works by removing the widget canvas from its parent, rendering to an :class:`~kivy.graphics.fbo.Fbo`, and calling :meth:`~kivy.graphics.texture.Texture.save`. .. note:: The image includes only this widget and its children. If you want to include widgets elsewhere in the tree, you must call :meth:`~Widget.export_to_png` from their common parent, or use :meth:`~kivy.core.window.Window.screenshot` to capture the whole window. .. note:: The image will be saved in png format, you should include the extension in your filename. .. versionadded:: 1.8.1 ''' if self.parent is not None: canvas_parent_index = self.parent.canvas.indexof(self.canvas) self.parent.canvas.remove(self.canvas) fbo = Fbo(size=self.size) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() Translate(-self.x, -self.y, 0) fbo.add(self.canvas) fbo.draw() fbo.texture.save(filename) fbo.remove(self.canvas) if self.parent is not None: self.parent.canvas.insert(canvas_parent_index, self.canvas) return True kv = ''' cameraWidget: orientation: 'vertical' Camera: id: camera resolution: (640, 480) play: False ToggleButton: text: 'Play' on_press: camera.play = not camera.play size_hint_y: None height: '48dp' Button: text: "Take picture" on_press: root.TakePicture() height: '48dp' ''' class cameraWidget(BoxLayout): def TakePicture(self, *args): self.export_to_png = export_to_png self.export_to_png(self.ids.camera, filename='test2.png') class MyApp(App): def build(self): return Builder.load_string(kv) if __name__ == '__main__': MyApp().run()