def widgetshot(widget, filename='output.png'): # detach the widget from the parent parent = widget.parent if parent: parent.remove_widget(widget) # put the widget canvas on a Fbo texture = Texture.create(size=widget.size, colorfmt='rgb') fbo = Fbo(size=widget.size, texture=texture) fbo.add(widget.canvas) # clear the fbo background fbo.bind() fbo.clear_buffer() fbo.release() # draw! fbo.draw() # get the fbo data fbo.bind() data = glReadPixels(0, 0, widget.size[0], widget.size[1], GL_RGBA, GL_UNSIGNED_BYTE) fbo.release() # save to a file surf = pygame.image.fromstring(data, widget.size, 'RGBA', True) pygame.image.save(surf, filename) # reattach to the parent if parent: parent.add_widget(widget) return True
def screenshot(path, root_widget=None): """ Take screenshot of the current state of the app and save it under ``path``. The sleep- and mainthread-decorator ensure that the app shows the current state properly. """ if root_widget is None: root_widget = MDApp.get_running_app().root fbo = Fbo( size=(root_widget.width, root_widget.height), with_stencilbuffer=True, ) with fbo: ClearColor(*MDApp.get_running_app().theme_cls.bg_normal) ClearBuffers() Scale(1, -1, 1) Translate(-root_widget.x, -root_widget.y - root_widget.height, 0) fbo.add(root_widget.canvas) fbo.draw() img = KivyImage(fbo.texture) img.save(path)
def export(self, wid, *largs): fbo = Fbo(size=wid.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(wid.canvas) fbo.draw() img = fbo.texture img.save('test.png') fbo.remove(wid.canvas)
def widget_save_canvas(widget, filename, format): parent = widget.parent if parent: parent.remove_widget(widget) size = (int(widget.size[0]), int(widget.size[1])) texture = Texture.create(size=widget.size, colorfmt='rgba') fbo = Fbo(size=widget.size, texture=texture) fbo.add(widget.canvas) fbo.draw() fbo.bind() data = glReadPixels(0, 0, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE) fbo.release() im = PILImage.fromstring('RGBA', size, data) im = im.transpose(PILImage.FLIP_TOP_BOTTOM) im.save(filename, format) if parent: parent.add_widget(widget) return True
def _setup_fbo(self, element, settings): """Setup FBO for a display.""" source = self.machine.displays[element] # put the widget canvas on a Fbo texture = Texture.create(size=source.size, colorfmt='rgb') fbo = Fbo(size=source.size, texture=texture) effect_widget = EffectWidget() effect_list = list() effect_widget.effects = effect_list effect_widget.size = source.size fbo.add(effect_widget.canvas) return [fbo, effect_widget, source, settings, True]
def _setup_fbo(self, element, settings, context): """Setup FBO for a display.""" if element not in self.machine.displays: raise AssertionError("Display {} not found. Please create it to use display_light_player.".format(element)) source = self.machine.displays[element] # put the widget canvas on a Fbo texture = Texture.create(size=source.size, colorfmt='rgba') fbo = Fbo(size=source.size, texture=texture) effect_widget = RelativeLayout() effect_widget.size = source.size fbo.add(effect_widget.canvas) with source.canvas: callback = Callback(partial(self._trigger_render, context, element)) return [fbo, effect_widget, source, settings, True, True, True, callback]
def create_image(self): parent = self.parent if parent: canvas_parent_index = parent.canvas.indexof(self.canvas) if canvas_parent_index > -1: 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() image = Image.frombytes('RGBA', list(map(int, self.size)), fbo.texture.pixels, 'raw', 'RGBA', 0, 1) fbo.remove(self.canvas) if parent is not None and canvas_parent_index > -1: parent.canvas.insert(canvas_parent_index, self.canvas) return image
def screenshot(widget, filename='output.png', region=None): 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 fbo: ClearColor(0, 0, 0, 0) ClearBuffers() Translate(-widget.x, -widget.y, 0) fbo.add(widget.canvas) fbo.draw() fbo.texture.save(filename) fbo.remove(widget.canvas) if widget.parent is not None: widget.parent.canvas.insert(canvas_parent_index, widget.canvas) return True
def _setup_fbo(self, element, settings): """Setup FBO for a display.""" if element not in self.machine.displays: raise AssertionError( "Display {} not found. Please create it to use display_light_player." .format(element)) source = self.machine.displays[element] # put the widget canvas on a Fbo texture = Texture.create(size=source.size, colorfmt='rgb') fbo = Fbo(size=source.size, texture=texture) effect_widget = EffectWidget() effect_list = list() effect_widget.effects = effect_list effect_widget.size = source.size fbo.add(effect_widget.canvas) return [fbo, effect_widget, source, settings, True]
def screenshot_texture(widget, factory_func): 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 fbo: ClearColor(0, 0, 0, 0) ClearBuffers() Translate(-widget.x, -widget.y, 0) fbo.add(widget.canvas) fbo.draw() result = factory_func(fbo.texture) fbo.remove(widget.canvas) if widget.parent is not None: widget.parent.canvas.insert(canvas_parent_index, widget.canvas) return result
class Paint(StencilView): scale = NumericProperty() def __init__(self, app, **kwargs): StencilView.__init__(self, **kwargs) self.app = app self.xx = 0 self.scale = 1.0 self.size_hint = (None, None) self.cursor_pos = (0, 0) self.fbo_size = DEFAULT_IMAGE_SIZE self.fbo = None self.fbo_rect = None self.tool_fbo = None self.tool_fbo_rect = None self.bg_rect = None self.rect = None self.fbo_clear_color = (1, 1, 1, 1) self.layer_undo_stack = [] self.undo_layer_index = 0 self.layer_rect = [] self.fbo_create_on_canvas() self.touches = [] self.move_image = False self.active_layer = None self.tool_buffer_enabled = True self.px = None self.py = None self.grid_texture = None self.active_layer_last_texture = None def grid_create(self, size): self.grid_texture = Texture.create(size=size, colorfmt='rgba', bufferfmt='ubyte') tex = improc.texture_draw_grid(self.grid_texture, 255, 4) return tex def fbo_create(self, size, tex=None): if tex is None: tex = Texture.create(size=size, colorfmt='rgba', bufferfmt='ubyte') tex.mag_filter = 'nearest' tex.min_filter = 'nearest' if self.fbo is None: self.fbo = Fbo(size=size, texture=tex) self.fbo.texture.mag_filter = 'nearest' self.fbo.texture.min_filter = 'nearest' else: self.fbo = Fbo(size=size, texture=tex) self.fbo.texture.mag_filter = 'nearest' self.fbo.texture.min_filter = 'nearest' tool_tex = Texture.create(size=size, colorfmt='rgba', bufferfmt='ubyte') tool_tex.mag_filter = 'nearest' tool_tex.min_filter = 'nearest' if self.tool_fbo is None: self.tool_fbo = Fbo(size=size, texture=tool_tex) self.tool_fbo.texture.mag_filter = 'nearest' self.tool_fbo.texture.min_filter = 'nearest' else: self.tool_fbo = Fbo(size=size, texture=tool_tex) self.tool_fbo.texture.mag_filter = 'nearest' self.tool_fbo.texture.min_filter = 'nearest' return self.fbo def refbo(self): tex = Texture.create(size=self.fbo.texture.size, colorfmt='rgba', bufferfmt='ubyte') self.fbo = Fbo(size=tex.size, texture=tex) self.fbo.texture.mag_filter = 'nearest' self.fbo.texture.min_filter = 'nearest' self.fbo.draw() self.canvas.ask_update() def canvas_put_drawarea(self, texture=None): self.canvas.clear() if texture: self.fbo_size = texture.size self.fbo_create(texture.size, tex=texture) self.bg_rect = layer.Layer.layer_bg_rect with self.canvas: self.canvas.add(self.bg_rect) Color(1, 1, 1, 1) for laybox in layer.LayerBox.boxlist: if laybox.layer: if laybox.layer.texture and laybox.layer.visible: self.canvas.add(laybox.layer.rect) laybox.layer.rect.pos = self.fbo_rect.pos if self.tool_buffer_enabled: self.tool_fbo_rect = Rectangle(pos=self.fbo_rect.pos, size=self.tool_fbo.texture.size, texture=self.tool_fbo.texture) self.fbo_update_pos() self.fbo.draw() self.canvas.ask_update() def fbo_create_on_canvas(self, size=None, pos=(0, 0)): self.canvas.clear() if size is None: size = self.fbo_size else: self.fbo_size = size self.fbo_create(size) with self.canvas: Color(1, 1, 1, 1) self.fbo_rect = Rectangle(texture=self.fbo.texture, pos=pos, size=self.fbo.texture.size) self.tool_fbo_rect = Rectangle(texture=self.tool_fbo.texture, pos=pos, size=self.tool_fbo.texture.size) self.fbo.draw() self.canvas.ask_update() def fbo_clear(self): self.fbo.bind() self.fbo.clear() self.fbo.clear_color = self.fbo_clear_color self.fbo.clear_buffer() self.fbo.release() self.fbo.draw() def fbo_update_pos(self): x = self.app.aPaintLayout.size[0] / self.scale / 2 - self.fbo.size[0] / 2 y = self.app.aPaintLayout.size[1] / self.scale / 2 - self.fbo.size[1] / 2 self.fbo_rect.pos = (x, y) self.tool_fbo_rect.pos = (x, y) if self.bg_rect: self.bg_rect.pos = (x, y) if self.app.layer_ribbon: for lb in layer.LayerBox.boxlist: if lb.layer.rect: lb.layer.rect.pos = self.fbo_rect.pos def fbo_move_by_offset(self, offset): if self.bg_rect: self.bg_rect.pos = self.bg_rect.pos[0] + offset[0], self.bg_rect.pos[1] + offset[1] self.fbo_rect.pos = self.bg_rect.pos self.tool_fbo_rect.pos = self.bg_rect.pos if self.app.layer_ribbon: for lb in layer.LayerBox.boxlist: if lb.layer.rect: lb.layer.rect.pos = self.fbo_rect.pos # self.ox, self.oy = self.bg_rect.pos # def fbo_render(self, touch, width): self.fbo.bind() if touch and touch.ud.has_key('line'): with self.fbo: self.fbo.add(self.app.aColor) d = width self.cursor_pos = ((touch.x - d / 2) / self.scale - self.fbo_rect.pos[0], (touch.y - d / 2) / self.scale - self.fbo_rect.pos[1]) touch.ud['line'].points += self.cursor_pos self.fbo.release() self.fbo.draw() self.canvas.ask_update() def fbo_get_texture(self): return self.fbo.texture def fbo_get_pixel_color(self, touch, format='1'): self.fbo.bind() x = touch.x / self.scale - self.fbo_rect.pos[0] y = touch.y / self.scale - self.fbo_rect.pos[1] data = glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE) self.fbo.release() if format == '1': c = [ord(a) / 255.0 for a in data] else: c = [ord(a) for a in data] return c def fbo_fill_region(self, touch): x = int(touch.x / self.scale - self.fbo_rect.pos[0]) y = int(touch.y / self.scale - self.fbo_rect.pos[1]) improc.fillimage(self.fbo, (x, y), [int(255 * c) for c in self.app.aColor.rgba]) self.canvas.ask_update() def fbo_replace_color(self, touch, width): cx = int(touch.x / self.scale - self.fbo_rect.pos[0]) cy = int(touch.y / self.scale - self.fbo_rect.pos[1]) if self.px is None: self.px = cx if self.py is None: self.py = cy if (cx - self.px) > 0: tg_alpha = float((cy - self.py)) / (cx - self.px) step = int(math.copysign(1, tg_alpha)) if abs(cx - self.px) > abs(cy - self.py): coords = [(x, self.py + (x - self.px) * tg_alpha) for x in xrange(int(self.px), int(cx))] else: coords = [(self.px + (y - self.py) / tg_alpha, y) for y in xrange(int(self.py), int(cy), step)] elif (cx - self.px) < 0: tg_alpha = float((cy - self.py)) / (cx - self.px) step = int(math.copysign(1, tg_alpha)) if abs(cx - self.px) > abs(cy - self.py): coords = [(x, self.py + (x - self.px) * tg_alpha) for x in xrange(int(cx), int(self.px))] else: coords = [(self.px + (y - self.py) / tg_alpha, y) for y in xrange(int(cy), int(self.py), step)] elif (cx - self.px) == 0: if (cy - self.py) > 0: coords = [(cx, y) for y in xrange(int(self.py), int(cy))] elif (cy - self.py) < 0: coords = [(cx, y) for y in xrange(int(cy), int(self.py))] else: coords = [(cx, cy), ] self.fbo.bind() for (x, y) in coords: improc.texture_replace_color(tex=self.fbo.texture, pos=(x, y), color=0, size=(width, width)) self.fbo.release() self.fbo.clear() self.fbo.draw() self.canvas.ask_update() self.px = cx self.py = cy def pos_to_widget(self, touch): return self.to_widget(touch.x, touch.y) def scale_canvas(self, zoom): with self.canvas.before: PushMatrix() self.scale *= zoom context_instructions.Scale(zoom) with self.canvas.after: PopMatrix() self.fbo_update_pos() def on_scale(self, instance, scale): ToolBehavior.scale() def scale_pos(self, pos): return [pos[0] / self.scale - self.fbo_rect.pos[0], pos[1] / self.scale - self.fbo_rect.pos[1]] def scaled_pos(self): return [self.fbo_rect.pos[0] * self.scale, self.fbo_rect.pos[1] * self.scale] def scaled_size(self): return [self.fbo_rect.texture.size[0] * self.scale, self.fbo_rect.texture.size[1] * self.scale] def add_touch(self, touch): if touch and len(self.touches) < 2: self.touches.append(touch) if len(self.touches) >= 2: self.touch_dist = self.touches[0].distance(self.touches[1]) self.touch_dist_const = self.touch_dist self.first_touch = self.touches[0] def double_touch(self): if len(self.touches) > 1: return True # def double_touch_distance(self): # return Vector(self.touches[0].pos).distance(self.touches[1].pos) def touch_responce(self): result = False if len(self.touches) >= 2: pos1 = self.pos_to_widget(self.touches[0]) pos2 = self.touches[1].pos dist = distance(pos1, pos2) if dist > self.touch_dist + 10: self.touch_dist = dist result = 2 elif dist <= self.touch_dist - 10: self.touch_dist = dist result = 1 if abs(self.touch_dist_const - dist) < 10: result = 3 return result return False def on_touch_down(self, touch): self.tool_buffer.on_touch_down(touch) if self.collide_point(*touch.pos): if self.app.config.getint('toolbars', 'toolbar_autohide'): self.app.toolbar.animate_hide() if self.app.config.getint('toolbars', 'palette_autohide'): self.app.palette.animate_hide() if self.app.config.getint('toolbars', 'layer_ribbon_autohide'): self.app.layer_ribbon.animate_hide() if not self.collide_point(*touch.pos): if self.app.active_tool == TOOL_LINE: self.tool_line._render_and_reset_state(self.fbo, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() return False touch.grab(self) self.add_touch(touch) if len(self.touches) == 1: self.active_layer_backup_texture() if self.double_touch(): self.active_layer_set_last_backup_texture() return if not self.app.layer_ribbon.get_active_layer().visible: dialog.PopupMessage("Notification", "The current layer is hidden, make it visible for edit") return if self.app.layer_ribbon.get_active_layer().texture_locked: dialog.PopupMessage("Notification", "The current layer is locked, make it unlock for edit") return if self.app.active_tool == TOOL_PENCIL1: self.fbo.bind() if touch: with self.fbo: self.fbo.add(self.app.aColor) d = 1. self.cursor_pos = ((touch.x - d / 2) / self.scale - self.fbo_rect.pos[0], (touch.y - d / 2) / self.scale - self.fbo_rect.pos[1]) Ellipse(pos=self.cursor_pos, size=(d, d)) touch.ud['line'] = Line(points=self.cursor_pos, width=d) self.fbo.release() self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_PENCIL2: self.fbo.bind() if touch: with self.fbo: self.fbo.add(self.app.aColor) d = 2.1 self.cursor_pos = ((touch.x - d / 2) / self.scale - self.fbo_rect.pos[0], (touch.y - d / 2) / self.scale - self.fbo_rect.pos[1]) Ellipse(pos=self.cursor_pos, size=(d, d)) touch.ud['line'] = Line(points=self.cursor_pos, width=d / 2.0) self.fbo.release() self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_PENCIL3: self.fbo.bind() if touch: with self.fbo: self.fbo.add(self.app.aColor) d = 3. self.cursor_pos = ((touch.x - d / 2) / self.scale - self.fbo_rect.pos[0], (touch.y - d / 2) / self.scale - self.fbo_rect.pos[1]) Ellipse(pos=self.cursor_pos, size=(d, d)) touch.ud['line'] = Line(points=self.cursor_pos, width=d / 2) self.fbo.release() self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_PICKER: if touch: if self.collide_point(touch.x, touch.y): c = self.fbo_get_pixel_color(touch) self.app.aColor = Color(c[0], c[1], c[2], c[3]) self.app.toolbar.tools_select(self.app.prev_tool) elif self.app.active_tool == TOOL_FILL: if touch: if self.collide_point(touch.x, touch.y): self.fbo_fill_region(touch) elif self.app.active_tool == TOOL_ERASE1: if touch: if self.collide_point(touch.x, touch.y): self.fbo_replace_color(touch, width=1) elif self.app.active_tool == TOOL_ERASE2: if touch: if self.collide_point(touch.x, touch.y): self.fbo_replace_color(touch, width=2) elif self.app.active_tool == TOOL_ERASE3: if touch: if self.collide_point(touch.x, touch.y): self.fbo_replace_color(touch, width=3) elif self.app.active_tool == TOOL_SELECT: if touch: if not self.tool_buffer.enabled: self.tool_select.on_touch_down(touch, self.fbo, self.tool_fbo) else: pass elif self.app.active_tool == TOOL_LINE: if touch: self.tool_line.on_touch_down(touch, self.fbo, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_RECT: if touch: self.tool_rect.on_touch_down(touch, self.fbo, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_ELLIPSE: if touch: self.tool_ellipse.on_touch_down(touch, self.fbo, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_MOVE: if touch: if self.collide_point(touch.x, touch.y): self.move_image = True self.ox, self.oy = touch.pos return True def on_touch_move(self, touch): result = self.touch_responce() if result == 2: self.scale_canvas(1.02) return elif result == 1: self.scale_canvas(0.98) return elif result == 3: dist = self.touches[0].distance(self.first_touch) self.fbo_move_by_offset((dist / self.scale, dist / self.scale)) if self.app.active_tool == TOOL_PENCIL1: self.fbo_render(touch, width=1.) elif self.app.active_tool == TOOL_PENCIL2: self.fbo_render(touch, width=2.) elif self.app.active_tool == TOOL_PENCIL3: self.fbo_render(touch, width=3.) elif self.app.active_tool == TOOL_PICKER: c = self.fbo_get_pixel_color(touch) self.app.aColor = Color(c[0], c[1], c[2]) elif self.app.active_tool == TOOL_ERASE1: if touch: if self.collide_point(touch.x, touch.y): self.fbo_replace_color(touch, width=1) elif self.app.active_tool == TOOL_ERASE2: if touch: if self.collide_point(touch.x, touch.y): self.fbo_replace_color(touch, width=2) elif self.app.active_tool == TOOL_ERASE3: if touch: if self.collide_point(touch.x, touch.y): self.fbo_replace_color(touch, width=3) elif self.app.active_tool == TOOL_SELECT: if touch: if not self.tool_buffer.enabled: self.tool_select.on_touch_move(touch, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() else: pass elif self.app.active_tool == TOOL_LINE: if touch: self.tool_line.on_touch_move(touch, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_RECT: if touch: self.tool_rect.on_touch_move(touch, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_ELLIPSE: if touch: self.tool_ellipse.on_touch_move(touch, self.tool_fbo) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_MOVE: if self.move_image: self.fbo_move_by_offset((touch.dx / self.scale, touch.dy / self.scale)) self.tool_buffer.on_touch_move(touch, self.fbo) def on_touch_up(self, touch): self.tool_buffer.on_touch_up(touch) if touch.grab_current is not self: return False if not self.collide_point(*touch.pos): return False touch.ungrab(self) if self.double_touch(): _not_add_too_undo = True else: _not_add_too_undo = False if touch: try: self.touches.remove(touch) except: pass if self.app.active_tool == TOOL_SELECT: if touch: self.tool_select.on_touch_up(touch) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_LINE: if touch: self.tool_line.on_touch_up(touch) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_RECT: if touch: self.tool_rect.on_touch_up(touch) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_ELLIPSE: if touch: self.tool_ellipse.on_touch_up(touch) self.fbo.draw() self.canvas.ask_update() elif self.app.active_tool == TOOL_MOVE: if touch: self.move_image = False elif self.app.active_tool == TOOL_ERASE1 or self.app.active_tool == TOOL_ERASE2 or self.app.active_tool == TOOL_ERASE3: if touch: self.px = None self.py = None if self.app.active_tool == TOOL_PENCIL1 or self.app.active_tool == TOOL_ERASE1 \ or self.app.active_tool == TOOL_PENCIL2 or self.app.active_tool == TOOL_ERASE2 \ or self.app.active_tool == TOOL_PENCIL3 or self.app.active_tool == TOOL_ERASE3 \ or self.app.active_tool == TOOL_FILL: rect = self.app.layer_ribbon.get_active_layer().rect pos = rect.pos[0] * self.scale, rect.pos[1] * self.scale size = rect.size[0] * self.scale, rect.size[1] * self.scale if not _not_add_too_undo: if pos[0] <= touch.x <= pos[0] + size[0] and pos[1] <= touch.y <= pos[1] + size[1]: self.add_undo_stack() return True def add_redo_stack(self): pass def add_undo_stack(self): _active_layer = self.app.layer_ribbon.get_active_layer() _active_layer.backup_texture() self.layer_undo_stack = self.layer_undo_stack[:self.undo_layer_index + 1] self.layer_undo_stack.append(_active_layer) self.undo_layer_index = len(self.layer_undo_stack) - 1 def do_undo(self, *args): if self.layer_undo_stack: if self.undo_layer_index > 0: _layer = self.layer_undo_stack[self.undo_layer_index] _layer.texture_from_backup(direction=-1) _active_layer = self.app.layer_ribbon.get_active_layer() if _layer is _active_layer: self.fbo_create(_active_layer.texture.size, _active_layer.texture) self.undo_layer_index -= 1 self.canvas_put_drawarea() self.fbo_update_pos() def active_layer_backup_texture(self): active_layer = self.app.layer_ribbon.get_active_layer() self.active_layer_last_texture = improc.texture_copy(active_layer.texture) def active_layer_set_last_backup_texture(self): active_layer = self.app.layer_ribbon.get_active_layer() # texture = active_layer.textures_array[-1] active_layer.replace_texture(self.active_layer_last_texture) self.fbo_create(active_layer.texture.size, active_layer.texture) self.canvas_put_drawarea() self.fbo_update_pos() self.canvas.ask_update() def do_redo(self, *args): if self.layer_undo_stack: if self.undo_layer_index < len(self.layer_undo_stack) - 1: self.undo_layer_index += 1 _layer = self.layer_undo_stack[self.undo_layer_index] _layer.texture_from_backup(direction=1) _active_layer = self.app.layer_ribbon.get_active_layer() if _layer is _active_layer: self.fbo_create(_active_layer.texture.size, _active_layer.texture) self.canvas_put_drawarea() self.fbo_update_pos()
class FboFloatLayout(Widget): texture = ObjectProperty(None, allownone=True) vertices = ListProperty([]) fbo = None tmp_fbo = None def __init__(self, **kwargs): self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=self.size) super(FboFloatLayout, self).__init__(**kwargs) # -- # preload FBO with background texture def initFbo(self): with self.fbo: ClearColor(0, 0, 0, 0) ClearBuffers() #Rectangle(source = 'data/background.jpg', size=self.size, pos=self.pos) self.texture = self.fbo.texture # -- # add the content of the widget to the FBO # this will literally render the widget into the texture def render_widget(self, widget): # create an FBO to render the widget to self.tmp_fbo = Fbo(size=self.size) self.tmp_fbo.add(ClearColor(0, 0, 0, 0)) self.tmp_fbo.add(ClearBuffers()) self.tmp_fbo.add(widget.canvas) self.tmp_fbo.draw() # render a rectangle in the main fbo containing the content from the widget with self.fbo: Color(1, 1, 1, 1) Rectangle(texture=self.tmp_fbo.texture, size=self.tmp_fbo.size) #def add_widget(self, *largs): # trick to attach graphics instruction to fbo instead of canvas # canvas = self.canvas # self.canvas = self.fbo # ret = super(FboFloatLayout, self).add_widget(*largs) # self.canvas = canvas # remove widget after next frame, this makes sure that # we do not use the widget for more than one frame #Clock.schedule_once(lambda dt: self.remove_widget(*largs)) # return ret #def remove_widget(self, *largs): # canvas = self.canvas # self.canvas = self.fbo # super(FboFloatLayout, self).remove_widget(*largs) # self.canvas = canvas def on_size(self, instance, value): self.size = value self.fbo.size = value #self.fbo_rect.size = value #self.fbo_background.size = value #self.fbo_rect.texture = self.fbo.texture # setup simple quad mesh to be rendered # the quad is used for actual resizing self.vertices = [] self.vertices.extend([0, 0, 0, 0]) self.vertices.extend([0, self.height, 0, 1]) self.vertices.extend([self.width, self.height, 1, 1]) self.vertices.extend([self.width, 0, 1, 0]) #self.updateFbo() self.initFbo()
def generate_movie(self, filename, out_fmt='yuv420p', codec='libx264', lib_opts={'crf': '0'}, video_fmt='mp4', start=None, end=None, canvas_size=(0, 0), canvas_size_hint=(1, 1), projector_pos=(0, 0), projector_pos_hint=(None, None), paint_funcs=(), stimulation_transparency=1., lum=1., speed=1., hidden_shapes=None): from kivy.graphics import (Canvas, Translate, Fbo, ClearColor, ClearBuffers, Scale) from kivy.core.window import Window rate = float(self.view_controller.frame_rate) rate_int = int(rate) if rate != rate_int: raise ValueError('Frame rate should be integer') orig_w, orig_h = (self.view_controller.screen_width, self.view_controller.screen_height) canvas_w, canvas_h = canvas_size cv_hint_w, cv_hint_h = canvas_size_hint w = int(canvas_w if cv_hint_w is None else orig_w * cv_hint_w) h = int(canvas_h if cv_hint_h is None else orig_h * cv_hint_h) projector_x, projector_y = projector_pos projector_hint_x, projector_hint_y = projector_pos_hint x = int(projector_x if projector_hint_x is None else orig_w * projector_hint_x) y = int(projector_y if projector_hint_y is None else orig_h * projector_hint_y) Window.size = w, h intensities = self.shapes_intensity n = len(intensities[next(iter(intensities.keys()))]) if start is not None: start = int(start * rate) if start >= n: raise Exception('Start time is after the end of the data') else: start = 0 if end is not None: end = int(math.ceil(end * rate)) + 1 if end <= start: raise Exception('End time is before or at the start time') else: end = n stream = { 'pix_fmt_in': 'rgba', 'pix_fmt_out': out_fmt, 'width_in': w, 'height_in': h, 'width_out': w, 'height_out': h, 'codec': codec, 'frame_rate': (int(speed * rate_int), 1) } writer = MediaWriter(filename, [stream], fmt=video_fmt, lib_opts=lib_opts) fbo = Fbo(size=(w, h), with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() Scale(1, -1, 1) Translate(0, -h, 0) config = { 'canvas': fbo, 'pos': (x, y), 'size': (w, h), 'orig_size': (orig_w, orig_h), 'rate': rate } paint_funcs = [func(config) for func in paint_funcs] paint_funcs = [func for func in paint_funcs if func is not None] fbo.draw() img = Image(plane_buffers=[fbo.pixels], pix_fmt='rgba', size=(w, h)) writer.write_frame(img, 0.) fbo.add(Translate(x, y)) shape_views = self.stage_factory.get_shapes_gl_color_instructions( fbo, 'stage_replay') fbo.add(Translate(-x, -y)) pbar = tqdm(total=(end - 1 - start) / rate, file=sys.stdout, unit='second', unit_scale=1) # all shapes listed in intensities must be in shape_views. However, # we don't want to show shapes not given values in intensities or if # they are to be hidden unused_shapes = set(shape_views) - set(intensities) unused_shapes.update(set(hidden_shapes or [])) for name in unused_shapes: if name in shape_views: shape_views[name].rgba = 0, 0, 0, 0 for i in range(start, end): pbar.update(1 / rate) for name, intensity in intensities.items(): r, g, b, a = intensity[i] if name in unused_shapes: a = 0 shape_views[name].rgba = \ r * lum, g * lum, b * lum, a * stimulation_transparency try: for func in paint_funcs: func(i) except EndOfDataException: break fbo.draw() img = Image(plane_buffers=[fbo.pixels], pix_fmt='rgba', size=(w, h)) writer.write_frame(img, (i - start + 1) / (rate * speed)) pbar.close()
def texture_merge(texture1, texture2): fbo = Fbo(size=texture2.size, texture=texture2) fbo.add(Rectangle(pos=(0, 0), texture=texture1, size=texture1.size)) fbo.draw() return fbo.texture
class FboFloatLayout(Widget): texture = ObjectProperty(None, allownone=True) vertices = ListProperty([]) fbo = None tmp_fbo = None def __init__(self, **kwargs): self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=self.size) super(FboFloatLayout, self).__init__(**kwargs) # -- # preload FBO with background texture def initFbo(self): with self.fbo: ClearColor(0,0,0,0) ClearBuffers() #Rectangle(source = 'data/background.jpg', size=self.size, pos=self.pos) self.texture = self.fbo.texture # -- # add the content of the widget to the FBO # this will literally render the widget into the texture def render_widget(self, widget): # create an FBO to render the widget to self.tmp_fbo = Fbo(size = self.size) self.tmp_fbo.add(ClearColor(0,0,0,0)) self.tmp_fbo.add(ClearBuffers()) self.tmp_fbo.add(widget.canvas) self.tmp_fbo.draw() # render a rectangle in the main fbo containing the content from the widget with self.fbo: Color(1,1,1,1) Rectangle(texture=self.tmp_fbo.texture, size=self.tmp_fbo.size) #def add_widget(self, *largs): # trick to attach graphics instruction to fbo instead of canvas # canvas = self.canvas # self.canvas = self.fbo # ret = super(FboFloatLayout, self).add_widget(*largs) # self.canvas = canvas # remove widget after next frame, this makes sure that # we do not use the widget for more than one frame #Clock.schedule_once(lambda dt: self.remove_widget(*largs)) # return ret #def remove_widget(self, *largs): # canvas = self.canvas # self.canvas = self.fbo # super(FboFloatLayout, self).remove_widget(*largs) # self.canvas = canvas def on_size(self, instance, value): self.size = value self.fbo.size = value #self.fbo_rect.size = value #self.fbo_background.size = value #self.fbo_rect.texture = self.fbo.texture # setup simple quad mesh to be rendered # the quad is used for actual resizing self.vertices = [] self.vertices.extend([0,0,0,0]) self.vertices.extend([0,self.height,0,1]) self.vertices.extend([self.width,self.height,1,1]) self.vertices.extend([self.width,0,1,0]) #self.updateFbo() self.initFbo()
def count_it(num): if num == 0: fbo = Fbo(size=self.stencil.size, with_stencilbuffer=True) with fbo: ClearColor(1, 1, 1, 0) ClearBuffers() img2 = self.paintscreen.bg.texture fbo.add(self.stencil.canvas) fbo.draw() img = fbo.texture fbo.remove(self.stencil.canvas) self.remove_widget(self.paintscreen) im = np.frombuffer(img.pixels, np.uint8) data = np.reshape(im, (im.shape[0], 1)).tostring() data2 = str(data) data2 = str.encode(data2) pix = np.frombuffer(data, np.uint8) a = np.empty_like(pix) a[:] = pix texture = Texture.create(size=self.stencil.size) texture.blit_buffer(a, colorfmt='rgba', bufferfmt='ubyte') self.imge = Image(pos=(0, 0), size=self.paintscreen.stencil.size, texture=texture) #self.paintscreen.stencil.add_widget(self.imge) #img2 = self.paintscreen.grid_layout.bg.texture im2 = np.frombuffer(img2.pixels, np.uint8) data = np.reshape(im2, (im2.shape[0], 1)).tostring() data2 = str(data) data2 = str.encode(data2) pix = np.frombuffer(data, np.uint8) a2 = np.empty_like(pix) a2[:] = pix img2 = a2 print(img2.shape) print(img2) img1 = a print(img1.shape) import cv2 #setting alpha=1, beta=1, gamma=0 gives direct overlay of two images # in theory this would give a direct overlay... #img3 = cv2.addWeighted(img1, 1, img2, 1, 0) #print(img3.shape) im = img1.reshape(1200, 1200, 4) # for i in range(0, 1200): # for j in range(0,1200): # points = im[i,j,:] # if (points[3] == 0):#points[0] == 255 & points[1] == 255 & points[2] == 255): # im[i,j,:] = [255,255,255,0] img_2 = img2.reshape((1200, 1200, 4)) for i in range(0, 1200): for j in range(0, 1200): points1 = im[i, j, :] if (points1[3] != 0): img_2[i, j, :] = im[i, j, :] socket_client.send(img_2) while MESSAGE is None: pass if MESSAGE is not None: new_img = MESSAGE else: new_img = img_2 texture = Texture.create(size=(1200, 1200)) texture.blit_buffer(np.reshape(new_img, (1200 * 1200 * 4, )), colorfmt='rgba', bufferfmt='ubyte') self.paintscreen = PaintScreen() self.add_widget(self.paintscreen) self.paintscreen.bg.texture = texture return num -= 1 self.count.text = str(num) Clock.schedule_once(lambda dt: count_it(num), 1)
class DmdBase(object): """Base class for DMD devices.""" dmd_name_string = 'DMD' def __init__(self, mc: "MpfMc", name: str, config: dict) -> None: """Initialise DMD.""" self.mc = mc self.name = name self.mc.log.info('Initializing DMD') self.config = self._get_validated_config(config) self.source = self.mc.displays[self.config['source_display']] self.prev_data = None # put the widget canvas on a Fbo texture = Texture.create(size=self.source.size, colorfmt='rgb') self.fbo = Fbo(size=self.source.size, texture=texture) self.effect_widget = EffectWidget() effect_list = list() effect_list.append(FlipVerticalEffect()) if self.config['brightness'] != 1.0: if not 0.0 <= self.config['brightness'] <= 1.0: raise ValueError("DMD brightness value should be between 0.0 " "and 1.0. Yours is {}".format( self.config['brightness'])) effect_list.append(GainEffect(gain=self.config['brightness'])) if self.config['gamma'] != 1.0: effect_list.append(GammaEffect(gamma=self.config['gamma'])) self.effect_widget.effects = effect_list self.effect_widget.size = self.source.size self.fbo.add(self.effect_widget.canvas) self._set_dmd_fps() def _get_validated_config(self, config: dict) -> dict: raise NotImplementedError def _set_dmd_fps(self) -> None: # fps is the rate that the connected client requested. We'll use the # lower of the two mc_fps = self.config['fps'] if mc_fps == 0: # pylint: disable-msg=protected-access mc_fps = Clock._max_fps # pylint: disable-msg=protected-access if mc_fps > Clock._max_fps: self.mc.log.warning( "%s fps is higher than mpf-mc fps. " "Will use mpf-mc fps setting for the DMD.", DmdBase.dmd_name_string) # pylint: disable-msg=protected-access fps = Clock._max_fps update = 0 # pylint: disable-msg=protected-access elif Clock._max_fps > mc_fps > 0: fps = mc_fps update = 1 / fps else: # pylint: disable-msg=protected-access fps = Clock._max_fps update = 0 Clock.schedule_interval(self.tick, update) self.mc.log.info("Setting %s to %sfps", DmdBase.dmd_name_string, fps) def tick(self, dt) -> None: """Draw image for DMD and send it.""" del dt widget = self.source fbo = self.fbo # detach the widget from the parent parent = widget.parent if parent: parent.remove_widget(widget) self.effect_widget.add_widget(widget) # clear the fbo background fbo.bind() fbo.clear_buffer() fbo.release() fbo.draw() fbo.bind() data = glReadPixels(0, 0, widget.native_size[0], widget.native_size[1], GL_RGB, GL_UNSIGNED_BYTE) fbo.release() # reattach to the parent if parent: self.effect_widget.remove_widget(widget) parent.add_widget(widget) if not self.config['only_send_changes'] or self.prev_data != data: self.prev_data = data self.send(data) def send(self, data: bytes) -> None: """Send data to DMD via BCP.""" raise NotImplementedError
def generate_movie( self, filename, out_fmt='yuv420p', codec='libx264', lib_opts={'crf': '0'}, video_fmt='mp4', start=None, end=None, canvas_size=(0, 0), canvas_size_hint=(1, 1), projector_pos=(0, 0), projector_pos_hint=(None, None), paint_funcs=(), stimulation_transparency=1., lum=1., speed=1.): from kivy.graphics import ( Canvas, Translate, Fbo, ClearColor, ClearBuffers, Scale) from kivy.core.window import Window rate = float(self.view_controller.frame_rate) rate_int = int(rate) if rate != rate_int: raise ValueError('Frame rate should be integer') orig_w, orig_h = ( self.view_controller.screen_width, self.view_controller.screen_height) canvas_w, canvas_h = canvas_size cv_hint_w, cv_hint_h = canvas_size_hint w = int(canvas_w if cv_hint_w is None else orig_w * cv_hint_w) h = int(canvas_h if cv_hint_h is None else orig_h * cv_hint_h) projector_x, projector_y = projector_pos projector_hint_x, projector_hint_y = projector_pos_hint x = int(projector_x if projector_hint_x is None else orig_w * projector_hint_x) y = int(projector_y if projector_hint_y is None else orig_h * projector_hint_y) Window.size = w, h intensities = self.shapes_intensity n = len(intensities[next(iter(intensities.keys()))]) if start is not None: start = int(start * rate) if start >= n: raise Exception('Start time is after the end of the data') else: start = 0 if end is not None: end = int(math.ceil(end * rate)) + 1 if end <= start: raise Exception('End time is before or at the start time') else: end = n stream = { 'pix_fmt_in': 'rgba', 'pix_fmt_out': out_fmt, 'width_in': w, 'height_in': h, 'width_out': w, 'height_out': h, 'codec': codec, 'frame_rate': (int(speed * rate_int), 1)} writer = MediaWriter( filename, [stream], fmt=video_fmt, lib_opts=lib_opts) fbo = Fbo(size=(w, h), with_stencilbuffer=True) with fbo: ClearColor(0, 0, 0, 1) ClearBuffers() Scale(1, -1, 1) Translate(0, -h, 0) config = {'canvas': fbo, 'pos': (x, y), 'size': (w, h), 'orig_size': (orig_w, orig_h), 'rate': rate} paint_funcs = [func(config) for func in paint_funcs] paint_funcs = [func for func in paint_funcs if func is not None] fbo.draw() img = Image(plane_buffers=[fbo.pixels], pix_fmt='rgba', size=(w, h)) writer.write_frame(img, 0.) fbo.add(Translate(x, y)) shape_views = self.stage_factory.get_shapes_gl_color_instructions( fbo, 'stage_replay') fbo.add(Translate(-x, -y)) pbar = tqdm( total=(end - 1 - start) / rate, file=sys.stdout, unit='second', unit_scale=1) for i in range(start, end): pbar.update(1 / rate) for name, intensity in intensities.items(): r, g, b, a = intensity[i] if not r and not g and not b: a = 0 shape_views[name].rgba = \ r * lum, g * lum, b * lum, a * stimulation_transparency try: for func in paint_funcs: func(i) except EndOfDataException: break fbo.draw() img = Image(plane_buffers=[fbo.pixels], pix_fmt='rgba', size=(w, h)) writer.write_frame(img, (i - start + 1) / (rate * speed)) pbar.close()