Konubinix' opinionated web of thoughts

Simple Camera With Kivy

Fleeting

The simple pwa offline camera works well, but has one issue: it reloads when scrolling down.

Let’s try building a simple camera with kivy, using the camera example as basis.

from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
from jnius import autoclass
import time
from android.runnable import run_on_ui_thread
from kivy.animation import Animation
from kivy import platform
import plyer

Builder.load_string('''
<CameraClick>:
    Camera:
        id: camera
        resolution: (640, 480)
        # resolution: (-1, -1) # best
        play: True
        allow_stretch: True
    Button:
        id: button
        pos: ((self.parent.width - self.width), (self.parent.height - self.height) / 2)
        size_hint: (None, None)
        size: (200, 200)
        on_press: root.capture()
        background_color: (1, 1, 1, 0) # transparent
        AsyncImage:
            source: "https://cdn.icon-icons.com/icons2/865/PNG/96/Citycons_camera_icon-icons.com_67912.png"
            allow_stretch: True
            keep_ratio: True
            # center in the parent button
            y: self.parent.y + self.parent.height / 2 - self.height / 2
            x: self.parent.x + self.parent.width / 2 - self.width / 2
            # fit to the parent button (keep_ratio will prevent it from being distorded)
            size: (self.parent.width, self.parent.height)

''')


class CameraClick(FloatLayout):
    def __init__(self, *args, **kwargs):
        super(CameraClick, self).__init__(*args, **kwargs)
        self.doing = False
        print("camera click")

    def done(self, *args):
        self.doing = False

    def shoot(self, *args):
        timestr = time.strftime("%Y%m%d_%H%M%S")
        camera = self.ids['camera']
        camera.export_to_png("/sdcard/Download/IMG_{}.png".format(timestr))
        button = self.ids['button']
        self.anim2 = Animation(background_color=(0, 0, 0, 1), duration=0.5)
        self.anim2 &= Animation(size=(200, 200), duration=0.3)
        self.anim2 &= Animation(pos=((self.width - 200), (self.height - 200) / 2), duration=0.5)
        self.anim2.bind(on_complete=self.done)
        self.anim2.start(button)

    def capture(self):
        if self.doing:
            return

        self.doing = True
        button = self.ids['button']
        self.anim = Animation(background_color=(1, 1, 1, 1), duration=0.2)
        self.anim &= Animation(size=(self.height, self.height), duration=0.2)
        self.anim &= Animation(pos=((self.width - self.height) / 2, 0), duration=0.2)
        self.anim.bind(on_complete=self.shoot)
        self.anim.start(button)


class TestCamera(App):

    def build(self):
        Window.bind(on_keyboard=self.hook_keyboard)
        # the following only works on android recent enough
        plyer.orientation.set_landscape()
        # self.do_window_stuff()
        return CameraClick()

    @run_on_ui_thread
    def do_window_stuff(self):
        from android import mActivity
        View = autoclass('android.view.View')
        Context = autoclass('android.content.Context')
        PowerManager = autoclass('android.os.PowerManager')
        option = View.SYSTEM_UI_FLAG_FULLSCREEN

        pm = mActivity.getSystemService(Context.POWER_SERVICE)
        wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 'TAG')
        wl.acquire()
        mActivity.getWindow().getDecorView().setSystemUiVisibility(option)


    def hook_keyboard(self, window, key, *args):
        if key == 27:
            # exit(0)
            return False

def run():
    TestCamera().run()

Notes linking here