Search code examples
pythonkivy

Python Kivy - Save canvas to a file


Here I have a simple kivy paint app taken from their docs https://kivy.org/doc/stable/tutorials/firstwidget.html and modified by me, attempting to add a save button which would save the canvas to the file image.jpg

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.graphics import Color, Ellipse, Line

class MyPaintWidget(Widget):
    def on_touch_down(self, touch):
        with self.canvas:
            Color(255, 255, 255)
            Ellipse(pos=(touch.x/ 2, touch.y/ 2), size=(1, 1))
            touch.ud['line'] = Line(points=(touch.x, touch.y))

    def on_touch_move(self, touch):
        touch.ud['line'].points += [touch.x, touch.y]

class MyPaintApp(App):
    def build(self):
        parent = Widget()
        self.painter = MyPaintWidget()
        clearbtn = Button(text='Clear',font_size=30,pos=(100,0))
        clearbtn.bind(on_release=self.clear)
        savebtn = Button(text='Save',font_size=30)
        savebtn.bind(on_release=self.save)
        parent.add_widget(self.painter)
        parent.add_widget(savebtn)
        parent.add_widget(clearbtn)
        return parent

    def save(self, obj):
        self.painter.export_as_image().save('image.jpg')

    def clear(self, obj):
        self.painter.canvas.clear()

MyPaintApp().run()

the save button does appear next to the clear button, and it does create the file image.jpg when I click it. But for some reason the file is always a blank black image with nothing on it, instead of the canvas with whatever I have drawn.


Solution

  • The problem is that your MyPainter widget has its default size of (100,100), and its default position of (0,0), so it is actually behind your Save Button. Any drawing that you do in the middle of the App display is not in the MyPainter widget, so saving to an image will be blank.

    The fix is to set pos and size of the MyPainter widget so that it can be drawn on. You probably also want to use collide_point() in your on_touch_down() and on_touch_move() methods to ensure that you can only draw in the MyPainter widget.