'how to simply read barcode with kivy from camera and send the result to a method to process the barcode?

I would like to have a button on the screen that would open the camera and read a barcode and I would like to show the image of the product based on the barcode and if I press the button again It opens the camera again and does the same job.

Before asking here, I searched examples but couldn't make it working with my limited understanding of kivy.

I have tried using: https://github.com/kivy-garden/zbarcam It has following issues for my usecase.

  1. Camera is always open, would like to open only at button click
  2. Doesn't show the output of barcode not sure if it is reading or not.
  3. doesn't say what is the way to pass the output to a method so it can be processed further

Thanks in advance.



Solution 1:[1]

Unfortunately zbarcam of kivy-garden is designed in such away it will always keep the camera running in the background which heats up the device and consumes a lot of power.

Here is an implementation of zbarcam and qrcode that I have created earlier(username:admin ,password:admin). The actual implementation requests the username and password from Mysql database, let me know if you need that.

calc method can be used to get the qrcode string and display the image of the product.

Update

My implementation uses KivyMD here https://github.com/kivymd/KivyMD so you need to have it installed by using

pip install kivymd==0.104.1

It has QR generator from kivygarden here https://pypi.org/project/kivy-garden.qrcode/ you also need to have it installed.

pip install kivy-garden.qrcode

And of course you need pyzbar installed as it is a dependency for both packages

pip install pyzbar

enter image description here

demo.kv

#:import ZBarCam kivy_garden.zbarcam.ZBarCam
#:import ZBarSymbol pyzbar.pyzbar.ZBarSymbol
#:import QRCodeWidget kivy_garden.qrcode

MyLayout:
    scr_mngr: scr_mngr
    orientation: 'vertical'
    ScreenManager:
        id: scr_mngr
        Screen:
            id: screen1
            name: 'screen1'
            MDSpinner:
                id:spinner
                size_hint: None, None
                size: dp(46), dp(46)
                pos_hint: {'center_x': .5, 'center_y': .5}
                active: False
            MDToolbar:
                md_bg_color: 0, 0, 1, 1
                title: "Login Screen"
                pos_hint:{"top": 1}
                elevation: 11
            BoxLayout:
                orientation: "vertical"
                padding: "16dp"
                spacing: "16dp"
                size_hint_y: None
                height: self.minimum_height
                pos_hint: {"center_y": .6}
                
                MDLabel:
                    text: "Log In"
                    halign: "center"
                    font_style: "H4"
                    size_hint_y: None
                MDTextField:
                    id: username
                    hint_text: "Username "
                    helper_text_mode: "on_focus"
                    required: True
                
                MDTextField:
                    id: password
                    hint_text: "Password "
                    helper_text_mode: "on_focus"
                    required: True
                    password: True


            MDRaisedButton:
                text: "LOGIN"
                pos_hint: {"center_x": 0.5, "center_y": 0.3}

                on_release: root.check_data_login()
        Screen:
            id: screen2
            name: 'screen2'
            BoxLayout:
                orientation: 'vertical'
                MDToolbar:
                    md_bg_color: 0, 0, 1, 1
                    id: toolbar
                    title: "Page 2"
                BoxLayout:
                    orientation: 'vertical'
                    MDTabs:
                        Tab:
                            text: "Scan"        
                            ZBarCam:
                                id: zbarcam
                                # optional, by default checks all types
                                code_types: ZBarSymbol.QRCODE, ZBarSymbol.EAN13
                                pos_hint: {'center_x': 0.5, 'center_y': 0.75}
                                size_hint: [1, 1]
                            MDLabel:
                                id: qrlabel
                                #size_hint: None, None
                                size: self.texture_size[0], 50
                                pos_hint: {'center_x': 0.5, 'center_y': 0.3}
                                halign: "center"
                                text: ', '.join([str(symbol.data) for symbol in zbarcam.symbols])
                                on_text: root.calc(self.text)
                                opacity: 1
                        Tab:
                            text: "Generate"
                            BoxLayout:
                                orientation: 'vertical'
                                padding: "16dp"
                                spacing: "16dp"
                                MDTextField:
                                    id: txtfld
                                    pos_hint: {'center_x': 0.5, 'center_y': 0.75}
                                    size_hint: [0.8,0.2]
                                    hint_text: "Text to be encoded"
                                    mode: "rectangle"
                                    on_text: qr.data = txtfld.text
                                QRCodeWidget:
                                    id: qr
                                    data: ''
                                    size_hint: [0.8,0.3]
                                    pos_hint: {'center_x': 0.5, 'center_y': 0.3}
                                    show_border: False 
                        

login.py

#!/usr/bin/env python
from kivymd.app import MDApp
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager as scr_mngr
from kivymd.toast import toast
from kivy.core.window import Window
from kivymd.uix.tab import MDTabsBase
from kivy.uix.floatlayout import FloatLayout
        
class Tab(FloatLayout, MDTabsBase):
    pass

class MyLayout(BoxLayout):
        
    def check_data_login(self):
                
        self.ids['spinner'].active=True
        username = self.ids['username'].text
        password = self.ids['password'].text
        print(username)
        print(password)
        if  not username and not password:
            toast("Username and password are required")
        elif  not username:
            toast("Username is required ")
        elif not password:
            toast("Password is required")
        else:
            if username == "admin" and  password == "admin":
                self.ids['spinner'].active=False
                self.change_screen("screen2")
            else:
                self.ids['spinner'].active=False
                toast("Wrong username or password")
        
    def change_screen(self, screen, *args):
        self.scr_mngr.current = screen
        
    def calc(self, instance):
        print(self.ids['qrlabel'].text)
        
class DemoApp(MDApp):
        pass
    
if __name__ == '__main__':
    Window.show_cursor = True
    Window.size = (360, 680)
    DemoApp().run()

Solution 2:[2]

I recently created a android qr code scanner app with ZBarCam. You can control the camera via the xcamera like this with ids. self.ids.<zbarcam_ids>.xcamera.play = True

I set it to false when the app is build and use screen manager to with on_enter/leave to enable/disble the camera.

Solution 3:[3]

I'm trying to do the same think, my way hope it helps:

try: import kivy from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.image import Image from kivy.uix.button import Button from kivy.uix.label import Label from kivy.uix.screenmanager import ScreenManager, Screen from kivy_garden.zbarcam import ZBarCam except: import subprocess subprocess.check_call(["python", '-m', 'pip', 'install', 'kivy']) subprocess.check_call(["python", '-m', 'pip', 'install', 'kivy_garden']) subprocess.check_call(["python", '-m', 'pip', 'install', 'pyzbar'])
class MainScreen(Screen):
    def __init__(self, **kw):
        super().__init__(**kw)
        self.box = BoxLayout()
        self.box.orientation = 'vertical'
        self.box.spacing = 20
        self.box.padding = 20
        self.logo = Image(source='logo.png')
        self.box.add_widget(self.logo)
        self.btn_add_pick = Button(font_size=30, text='Add Pick')
        self.box.add_widget(self.btn_add_qr)
        self.btn_remove_pick = Button(font_size=30, text='Delet Pick')
        self.box.add_widget(self.btn_remove_pick)
        self.add_widget(self.box)

class CameraScreen(Screen):
    def __init__(self, **kw):
        super().__init__(**kw)
        self.box = BoxLayout(orientation = 'vertical')
        self.cam = ZBarCam()
        self.cam.play = False 
        self.btn_close = Button(font_size=30, size_hint_y=None, text='Get')
        self.box.add_widget(self.cam)
        self.box.add_widget(self.btn_close)
        self.add_widget(self.box)

class WindowManager(ScreenManager):
    def __init__(self, **kv):
        super().__init__(**kv)
        ms = MainScreen(name="main")
        ms.btn_add_pick.bind(on_press=self.switch_to_camera)
        ms.btn_remove_pick.bind(on_press=self.switch_to_camera)
        self.add_widget(ms)
        cs = CameraScreen(name = "camera")
        cs.btn_close.bind(on_press=self.switch_to_main)
        self.add_widget(cs)

    def switch_to_camera(self, instance):
        self.current='camera'
        self.transition.direction='down'
    

    def switch_to_main(self, instance):
        self.current = 'main'
        self.transition.direction='up'

class WoodWQApp(App):
    def build(self):
        wm = WindowManager()
        wm.current = 'main'
        return wm

if __name__=="__main__":
   WoodWQApp().run()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 TEA
Solution 3