Esempio n. 1
0
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
Esempio n. 2
0
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
Esempio n. 3
0
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)
Esempio n. 4
0
    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)
Esempio n. 5
0
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
Esempio n. 6
0
    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]
Esempio n. 7
0
    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]
Esempio n. 8
0
 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
Esempio n. 9
0
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
Esempio n. 10
0
    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]
Esempio n. 11
0
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
Esempio n. 12
0
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()
Esempio n. 13
0
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()
Esempio n. 14
0
    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()
Esempio n. 15
0
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
Esempio n. 16
0
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()
Esempio n. 17
0
        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)
Esempio n. 18
0
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
Esempio n. 19
0
    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()