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_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 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 make_screen_fbo(self, screen): fbo = Fbo(size=screen.size) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() fbo.add(screen.canvas) return fbo
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 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 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 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 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
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 make_screen_fbo(self, screen): fbo = Fbo(size=screen.size) with fbo: ClearColor(0, 1, 0, 1) ClearBuffers() fbo.add(screen.canvas) return fbo
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 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 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 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 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, **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 make_screen_fbo(self, screen): fbo = Fbo(size=screen.size, with_stencilbuffer=True) with fbo: ClearColor(*self.clearcolor) ClearBuffers() fbo.add(screen.canvas) with fbo.before: PushMatrix() Translate(-screen.x, -screen.y, 0) with fbo.after: PopMatrix() return fbo
def make_screen_fbo(self, screen): fbo = Fbo(size=screen.size) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() fbo.add(screen.canvas) with fbo.before: PushMatrix() Translate(-screen.x, -screen.y, 0) with fbo.after: PopMatrix() return fbo
def make_screen_fbo(self, screen): fbo = Fbo(size=screen.size) with fbo: ClearColor(*self.clearcolor) ClearBuffers() fbo.add(screen.canvas) with fbo.before: PushMatrix() Translate(-screen.x, -screen.y, 0) with fbo.after: PopMatrix() return fbo
class FboCapture(FloatLayout): texture = ObjectProperty(None) texture_thumb = ObjectProperty(None) thumb_size = ListProperty([50, 50]) def __init__(self, **kwargs): self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=self.size) self.fbo_thumb = Fbo(size=self.thumb_size) with self.fbo: Color(0, 0, 0) self.fbo_rect = Rectangle(size=self.size) self.texture = self.fbo.texture with self.fbo_thumb: Color(1, 1, 1) self.fbo_thumb_rect = Rectangle(size=self.thumb_size) super(FboCapture, self).__init__(**kwargs) def on_size(self, instance, value): w, h = value ratio = float(w) / h if w > h: w = 160 h = w / ratio else: h = 160 w = h * ratio w = max(1, w) h = max(1, h) self.thumb_size = int(w), int(h) self.fbo.size = value self.fbo_rect.size = value self.texture = self.fbo.texture self.fbo_thumb_rect.texture = self.fbo.texture def on_thumb_size(self, instance, value): self.fbo_thumb.size = value self.fbo_thumb_rect.size = value self.texture_thumb = self.fbo_thumb.texture def add_widget(self, child): child.parent = self self.children.insert(0, child) self.fbo.add(child.canvas) def remove_widget(self, child): self.children.remove(child) self.fbo.remove(child.canvas)
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 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 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 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 _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 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
def export_to_png(widget, filename, fill_color): from kivy.graphics import (Translate, Fbo, ClearColor, ClearBuffers, Scale) if widget.parent is not None: canvas_parent_index = widget.parent.canvas.indexof(widget.canvas) widget.parent.canvas.remove(widget.canvas) fbo = Fbo(size=widget.size, with_stencilbuffer=True) with fbo: ClearColor(*fill_color) ClearBuffers() Scale(1, -1, 1) Translate(-widget.x, -widget.y - widget.height, 0) fbo.add(widget.canvas) fbo.draw() fbo.texture.save(filename, flipped=False) fbo.remove(widget.canvas) if widget.parent is not None: widget.parent.canvas.insert(canvas_parent_index, widget.canvas) return True
def prepare_preview_widget(self, source_widget): size = source_widget.size widget = self.preview_widget # get the pixels from the source widget if source_widget.parent is not None: canvas_parent_index = source_widget.parent.canvas.indexof( source_widget.canvas) if canvas_parent_index > -1: source_widget.parent.canvas.remove(source_widget.canvas) fbo = Fbo(size=size, with_stencilbuffer=False) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() Scale(1, -1, 1) Translate(-source_widget.x, -source_widget.y - source_widget.height, 0) fbo.add(source_widget.canvas) fbo.draw() self.preview_pixels = fbo.texture.pixels fbo.remove(source_widget.canvas) if source_widget.parent is not None and canvas_parent_index > -1: source_widget.parent.canvas.insert(canvas_parent_index, source_widget.canvas) widget.size = size texture = widget.preview_texture = Texture.create(size=size, colorfmt='RGBA', bufferfmt='ubyte') texture.flip_vertical() texture.add_reload_observer(self._reload_texture) self._reload_texture(texture)
Config.set('graphics', 'resizable', False) class kivy04(App): def build(self): return root root = Widget() # create frame buffer and register Canvas fb = Fbo(size=(300, 150)) root.canvas.add(fb) # draw frame buffer fb.add(Color(1, 0, 0, 1)) fb.add(Rectangle(pos=(0, 0), size=(100, 150))) fb.add(Color(0, 1, 0, 1)) fb.add(Rectangle(pos=(100, 0), size=(100, 150))) fb.add(Color(0, 0, 1, 1)) fb.add(Rectangle(pos=(200, 0), size=(200, 150))) fb.add(Color(1, 1, 1, 1)) fb.add(Rectangle(pos=(0, 75), size=(300, 75))) # draw Canvas root.canvas.add(Rectangle(size=(300, 150), texture=fb.texture)) # get color value def pick_color(self, t): # get window size (win_width, win_height) = Window.size
class Paintbrush(Widget): def __init__(self, **kwargs): super(Paintbrush, self).__init__(**kwargs) self.fbo = Fbo(size=(10, 10)) self.mesh = Mesh() self.points = [] self.vertices = [] self.indices = [] self.line_widths = [] self.cap_vertices_index = 0 self.cap_indices_index = 0 self.mask_lines = [] self.mask_alphas = [] self.canvas = RenderContext() self.canvas.shader.fs = mask_shader self.buffer_container = None self.rgb = (0, 1, 1) # We'll update our glsl variables in a clock Clock.schedule_interval(self.update_glsl, 0) # Maintain a window of history for autocorrelations self.ac_window = [] self.ac_position = 0 self.periodicity_factor = 1.0 def update_glsl(self, *largs): # This is needed for the default vertex shader. self.canvas['projection_mat'] = Window.render_context['projection_mat'] self.canvas['modelview_mat'] = Window.render_context['modelview_mat'] def on_size(self, instance, value): self.canvas.clear() with self.canvas: self.fbo = Fbo(size=value) self.mask_fbo = Fbo(size=(value[0] // 5, value[1] // 5), clear_color=(1, 1, 1, 1)) Color(*self.rgb, 0.9) BindTexture(texture=self.mask_fbo.texture, index=1) self.buffer_container = Rectangle(pos=self.pos, size=value, texture=self.fbo.texture) #Rectangle(pos=self.pos, size=value, texture=self.mask_fbo.texture) self.canvas['texture1'] = 1 with self.fbo: Color(1, 1, 1) self.mesh = Mesh(mode='triangle_strip') def on_pos(self, instance, value): if not self.buffer_container: return self.buffer_container.pos = value def build_line_segment(self, start, end, future, start_width=8.0, end_width=8.0): """Builds a line segment knowing the start and end, as well as one point in the future.""" start = np.array([start[0], start[1]]) end = np.array([end[0], end[1]]) future = np.array([future[0], future[1]]) length = np.linalg.norm(end - start) num_interpolants = max(int(length / DISTANCE_PER_POINT), 3) normal = (end - start) / length * start_width / 2.0 normal = np.array([-normal[1], normal[0]]) end_normal = (future - end) / max(np.linalg.norm(future - end), 0.1) * end_width / 2.0 end_normal = np.array([-end_normal[1], end_normal[0]]) delta_sign = None # if (self.last_normal is not None and # np.linalg.norm(normal - self.last_normal) > np.linalg.norm(normal + self.last_normal)): # self.last_normal *= -1 # Add points deviating in alternating directions around the actual path for i in range(num_interpolants): path_point = start + (i / num_interpolants) * (end - start) delta = normal + (i / num_interpolants) * (end_normal - normal) if delta_sign is None: delta_sign = 1 if len(self.points) > 3: second_last_vertex = np.array(self.vertices[-8:-6]) option_1 = path_point + delta option_2 = path_point - delta if (np.linalg.norm(option_2 - second_last_vertex) < np.linalg.norm(option_1 - second_last_vertex)): delta_sign *= -1 self.vertices.extend([*(path_point + delta * delta_sign), 0, 0]) self.indices.append(len(self.indices)) delta_sign *= -1 def add_cap(self, width): """Adds a round line cap to the end of the vertex/index list.""" self.cap_vertices_index = len(self.vertices) self.cap_indices_index = len(self.indices) if len(self.points) < 3: return # Extend the current line segment using a circular interpolation of line widths start = np.array([self.points[-1][0], self.points[-1][1]]) prev = np.array([self.points[-2][0], self.points[-2][1]]) end = start + (start - prev) / max(np.linalg.norm(start - prev), 0.001) * width / 2.0 length = np.linalg.norm(end - start) num_interpolants = max(int(length / DISTANCE_PER_POINT) * 2, 3) normal = (end - start) / length * width / 2.0 normal = np.array([-normal[1], normal[0]]) end_normal = np.zeros(2) delta_sign = None # Add points deviating in alternating directions around the actual path for i in range(num_interpolants): path_point = start + (i / (num_interpolants - 1)) * (end - start) circ_progress = 1 - np.sqrt(1 - (i / (num_interpolants - 1)) ** 2) delta = normal + circ_progress * (end_normal - normal) if delta_sign is None: delta_sign = 1 if len(self.points) > 3: second_last_vertex = np.array(self.vertices[-8:-6]) option_1 = path_point + delta option_2 = path_point - delta if (np.linalg.norm(option_2 - second_last_vertex) < np.linalg.norm(option_1 - second_last_vertex)): delta_sign *= -1 self.vertices.extend([*(path_point + delta * delta_sign), 0, 0]) self.indices.append(len(self.indices)) delta_sign *= -1 def remove_cap(self): """Removes a cap on the line.""" if self.cap_vertices_index > 0 and self.cap_vertices_index <= len(self.vertices): del self.vertices[self.cap_vertices_index:] del self.indices[self.cap_indices_index:] self.cap_vertices_index = 0 self.cap_indices_index = 0 def current_line_width(self, depth, window=5): """Computes the current line width of the previous `window` points.""" max_width = 120.0 min_width = 5.0 min_dist = 40.0 max_dist = 140.0 last_point = self.points[-1] old_point = self.points[max(0, len(self.points) - window)] if PAINTBRUSH_MODE == 0: dist = np.linalg.norm(np.array([last_point[0], last_point[1]]) - np.array([old_point[0], old_point[1]])) else: dist = 120.0 width = (max_dist - dist) * (max_width * 0.8 - min_width) / (max_dist - min_dist) if PAINTBRUSH_MODE != 0: depth_factor = 1 / (1 + np.exp(-(depth - 0.5) * 4)) width *= depth_factor if PAINTBRUSH_MODE == 2: width *= self.periodicity_factor return np.clip(width, min_width, max_width) def update_periodicity(self, point): """Computes a new autocorrelation magnitude by adding the given point.""" self.ac_window.append(point) if len(self.ac_window) > AUTOCORRELATION_WINDOW: del self.ac_window[0] self.ac_position += 1 if self.ac_position % 8 == 0 and len(self.ac_window) == AUTOCORRELATION_WINDOW: ac_window = np.array(self.ac_window) x_fft = np.abs(np.fft.rfft(ac_window[:,0] * np.hanning(AUTOCORRELATION_WINDOW))) y_fft = np.abs(np.fft.rfft(ac_window[:,1] * np.hanning(AUTOCORRELATION_WINDOW))) x_fft = x_fft[4:20] / np.mean(x_fft[4:20]) y_fft = y_fft[4:20] / np.mean(y_fft[4:20]) # if self.ac_position > 200: # plt.figure() # plt.subplot(121) # plt.plot(ac_window[:,0], ac_window[:,1]) # plt.subplot(122) # plt.plot(x_fft, label='x') # plt.plot(y_fft, label='y') # plt.show() self.periodicity_factor = ((max(1.0, np.max(x_fft) / 4.0) * max(1.0, np.max(y_fft) / 4.0)) - 1) ** 2 + 1 def add_point(self, point, depth=None, width=None, alpha=None): """ point: a point in window space to add to the paintbrush trajectory (x, y). depth: a 0-1 value indicating the depth into the screen of the current point. alpha: a manual 0-1 alpha level for this point. Returns the current line width. """ point = (point[0] - self.pos[0], point[1] - self.pos[1]) self.points.append(point) # Build a segment of line line_width = 0 if len(self.points) > 2: self.update_periodicity(point) line_width = self.current_line_width(depth) if depth is not None else width old_line_width = (sum(self.line_widths) / len(self.line_widths) if self.line_widths else line_width) self.line_widths.append(line_width) if len(self.line_widths) > LINE_WIDTH_WINDOW: self.line_widths.pop(0) if width is None: line_width = sum(self.line_widths) / len(self.line_widths) # Clamp the amount by which the line width can change - results in # smoother lines # line_width = old_line_width + np.clip(line_width - old_line_width, -2.0, 2.0) self.remove_cap() self.build_line_segment(*self.points[-3:], old_line_width, line_width) self.add_cap(line_width) # Update mask if len(self.points) % MASK_INTERVAL == 0 and len(self.points) > MASK_INTERVAL: self.mask_lines.append(Line(points=(self.points[-MASK_INTERVAL - 1][0] / 5, self.points[-MASK_INTERVAL - 1][1] /5 , self.points[-1][0] / 5, self.points[-1][1] / 5), width=(line_width + 8.0) / 10)) if alpha is not None: self.mask_alphas.append(alpha) with self.mask_fbo: self.mask_fbo.clear() self.mask_fbo.clear_buffer() if len(self.mask_alphas) == len(self.mask_lines): white_values = self.mask_alphas else: white_values = 1 / (1 + np.exp(-((np.arange(len(self.mask_lines)) - len(self.mask_lines)) / FADE_FACTOR + 3))) white_values = white_values * (1 - BASE_FADE) + BASE_FADE for i, (white, line) in enumerate(zip(white_values, self.mask_lines)): Color(white, white, white, 1) self.mask_fbo.add(line) # if len(self.points) % 100 == 20: # plt.figure() # plt.plot(self.vertices[::4], self.vertices[1::4]) # plt.plot(self.vertices[::4], self.vertices[1::4], 'b.') # plt.plot([x[0] for x in self.points], [x[1] for x in self.points], 'ro') # plt.plot([x[0] for x in self.points], [x[1] for x in self.points], 'r-') # plt.show() # self.vertices.extend([point[0], point[1], 0, 0]) # if len(self.points) > 1: # self.indices.extend([len(self.points) - 2, len(self.points) - 1]) self.mesh.vertices = self.vertices self.mesh.indices = self.indices return line_width def clear(self): self.points = [] self.vertices = [] self.indices = [] self.mesh.vertices = [] self.mesh.indices = [] self.periodicity_factor = 1.0 self.ac_window = [] self.ac_position = 0 with self.fbo: self.fbo.clear_buffer() self.mask_lines = [] self.mask_colors = [] with self.mask_fbo: self.mask_fbo.clear() self.mask_fbo.clear_buffer() self.on_size(self, self.size)
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()
class QuestionButton(Button): disabled = BooleanProperty() alpha_rotation = NumericProperty(0) background_default = StringProperty() background_wrong = StringProperty() color_wrong = ListProperty([1, 1, 1, 0]) text_wrong = StringProperty() def __init__(self, **kwargs): super(QuestionButton, self).__init__(**kwargs) self._origin = {} Clock.schedule_once(self._prepare_fbo, 0) def on_text(self, *args): self._update_mesh() def _prepare_fbo(self, *args): # put all the current canvas into an FBO # then use the fbo texture into a Quad, for animating when disable # create the Fbo self.fbo = Fbo(size=(1, 1)) with self.fbo.before: self.g_translate = Translate(self.x, self.y) self.orig_canvas = self.canvas self.fbo.add(self.canvas) # create a new Canvas self.canvas = Canvas() self.canvas.add(self.fbo) with self.canvas: Color(1, 1, 1) self.g_quad = Quad(texture=self.fbo.texture) # replace the canvas from the parent with the new one self.parent.canvas.remove(self.orig_canvas) self.parent.canvas.add(self.canvas) # ensure we'll be updated when we'll change position self.bind(pos=self._update_mesh, size=self._update_mesh, alpha_rotation=self._update_mesh) self._update_mesh() def _update_mesh(self, *args): m = self.g_quad alpha = self.alpha_rotation # don't do anything if the fbo size will be messup. if 0 in self.size: return # update fbo size, and reassign the new texture to the quad if self.fbo.size != self.size: self.fbo.size = self.size self.g_quad.texture = self.fbo.texture # change the background to red, and ensure we are not seeing any # changes when clicking if alpha >= 0.5: # and self.background_normal != self.background_wrong: # self._origin = { # 'background_normal': self.background_normal, # 'background_down': self.background_down, # 'color': (1, 1, 1, 1)} self.background_normal = self.background_wrong self.background_down = self.background_wrong self.color = self.color_wrong self.text = self.text_wrong # correctly setup the positionning for the quad rendering self.g_translate.xy = -self.x, -self.y # 3d fake effect dx = sin(alpha * pi / 2.0) * self.width dy = sin(alpha * pi) * 25 if alpha > 0.5: dy = -dy dx = self.width - dx m.points = ( self.x + dx, self.y + dy, self.right - dx, self.y - dy, self.right - dx, self.top + dy, self.x + dx, self.top - dy, ) def disable(self): if self.alpha_rotation > 0: return d = 1.0 hd = 0.16 # at 0.16, the animation will be at the middle t = "out_quart" Animation(alpha_rotation=1.0, t=t, d=d).start(self) (Animation(color=self.color_wrong, t=t, d=hd) + Animation(color=self.color, t=t, d=1 - hd)).start(self) def reset(self, text): self.alpha_rotation = 0 self.disabled = False self.background_normal = "ui/screens/question/qbg.png" self.background_down = "ui/screens/question/qbg_down.png" self.color = (0.96, 0.96, 0.96, 1) self.text = text self._update_mesh()
class ShaderWidget(Widget): def __init__(self, **kwargs): super().__init__(**kwargs) Tex1 = Texture.create(size=T_SIZE, colorfmt="rgba", bufferfmt="float") Tex2 = Texture.create(size=T_SIZE, colorfmt="rgba", bufferfmt="float") Tex3 = Texture.create(size=T_SIZE, colorfmt="rgba", bufferfmt="float") Tex4 = Texture.create(size=T_SIZE, colorfmt="rgba", bufferfmt="float") Tex4.mag_filter = "linear" self.fbo_edit = Fbo(clear_color=(0.5,0.5,0,1),size=(T_SIZE),texture=Tex1) self.fbo_edit.shader.vs = open("data/shaders/vs.glsl").read() self.fbo_edit.shader.fs = open("data/shaders/fs_edit.glsl").read() self.fbo_edit["viewport"] = [float(s) for s in W_SIZE] self.fbo_edit["mode"] = 0 self.fbo_mix = Fbo(clear_color=(0.5,0.5,0,1),size=(T_SIZE),texture=Tex2) self.fbo_mix.shader.vs = open("data/shaders/vs.glsl").read() self.fbo_mix.shader.fs = open("data/shaders/fs_mix.glsl").read() self.fbo_mix["tex1"] = 1 self.fbo_mix["tex2"] = 2 self.fbo_mix["viewport"] = [float(s) for s in W_SIZE] self.fbo_save = Fbo(clear_color=(0.5,0.5,0,1),size=(T_SIZE),texture=Tex3) self.fbo_save.shader.vs = open("data/shaders/vs.glsl").read() self.fbo_save.shader.fs = open("data/shaders/fs_save.glsl").read() self.fbo_save["tex"] = 3 self.fbo_save["viewport"] = [float(s) for s in W_SIZE] self.fbo_warp = Fbo(size=(T_SIZE),texture=Tex4) self.fbo_warp.shader.vs = open("data/shaders/vs.glsl").read() self.fbo_warp.shader.fs = open("data/shaders/fs_warp.glsl").read() self.fbo_warp["tex"] = 4 self.fbo_warp["warp"] = 5 self.fbo_warp["viewport"] = [float(s) for s in W_SIZE] self.tex = Texture.create(size=T_SIZE,colorfmt="rgb",bufferfmt="ubyte") self.tex.blit_buffer(IMG) def draw(self,nap): self.canvas.clear() self.canvas.add(self.fbo_edit) self.canvas.add(self.fbo_mix) self.canvas.add(self.fbo_save) self.canvas.add(self.fbo_warp) self.fbo_mix.add(self.fbo_edit) self.fbo_warp.add(self.fbo_mix) with self.canvas: with self.fbo_edit: Rectangle(pos=(-1,-1),size=(2,2)) with self.fbo_save: BindTexture(texture=self.fbo_mix.texture, index=3) with self.fbo_mix: BindTexture(texture=self.fbo_save.texture, index=1) BindTexture(texture=self.fbo_edit.texture, index=2) Rectangle(pos=(-1,-1),size=(2,2)) with self.fbo_warp: BindTexture(texture=self.tex,index=4) BindTexture(texture=self.fbo_mix.texture,index=5) Rectangle(pos=(-1,-1),size=(2,2)) Rectangle(pos=(0,0),size=W_SIZE,texture=self.fbo_warp.texture) def on_touch_down(self,touch): self.fbo_edit["mode"] = 1 self.fbo_edit["touch_begin"] = (touch.x,touch.y) self.fbo_edit["touch_end"] = (touch.x,touch.y) self.draw(0) def on_touch_move(self, touch): self.fbo_edit["touch_end"] = (touch.x,touch.y) def on_touch_up(self, touch): with self.fbo_save: Rectangle(pos=(-1,-1),size=(2,2))