Search code examples
exportkivyscale

Kivy: export_to_png() with an arbitrary scale


Is there a way to export a widget to png with an arbitrary scale in Kivy?

As far as I understand, now by default the scale of an exported image is 1:1 relative to size of widget that I see on the screen.

But what if I want to export to 1:10 (and get an image 10 times larger)?

Interested in any ideas how this can be done.


Solution

  • I don't know a straight forward method to do the same, but you can fork export_to_png method of Widget class

    Here is a working example:

    from kivy.uix.widget import Widget
    from kivy.base import runTouchApp
    from kivy.lang import Builder
    from kivy.graphics import (Canvas, Translate, Fbo, ClearColor,
                               ClearBuffers, Scale)
    
    
    kv='''
    BoxLayout:
        orientation: 'vertical'
        MyWidget:
            id: wgt
        BoxLayout:
            size_hint_y: .1
            orientation: 'horizontal'
            Label:
                text: 'enter scale:'
            TextInput:
                id: txtinpt
                text: '2.5'
            Button:
                text: 'Export with new scale'
                on_release: wgt.export_scaled_png('kvwgt.png', image_scale=float(txtinpt.text))
    
    <MyWidget>:
        canvas:
            PushMatrix:
            Color:
                rgba: (0, 0, 1, .75)
            Ellipse:
                pos: (self.x + self.width // 5, self.y + self.height // 5)
                size: (self.width * 3 // 5, self.height * 3 // 5)
            Color:
                rgba: (1, 0, 0, .5)
            Rectangle:
                pos: (self.x + self.width // 4, self.y + self.height // 4)
                size: (self.width // 2, self.height // 2)
            Rotate:
                origin:
                    self.center
                angle:
                    45
        Button:
            text: 'useless child widget\\njust for demonstration'
            center: root.center
            size: (root.width // 2, root.height // 8)
            canvas:
                PopMatrix:
    
    '''
    
    class MyWidget(Widget):
    
        def export_scaled_png(self, filename, image_scale=1):
            re_size = (self.width * image_scale, 
                    self.height * image_scale)
    
            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=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(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)
    
    
    
    runTouchApp(Builder.load_string(kv))
    

    Note re_size variable, which in turn passes to Fbo constructor. And the "Scale(image_scale, -image_scale, image_scale)" instruction inside export_scaled_png method.