Kivy : accès à l’appareil photo sous Android

Introduction

Depuis une application Kivy, il est possible d’appeler des objets Android et les faire interagir en utilisant Python. Pour ce faire, une interface est disponible sous le nom de « jnius ». En effet, c’est très pratique et génial…

Voici un exemple d’utilisation de l’appareil photo, le tout réutilisable dans vos applications Kivy, car dans un module à part (genre « Service »).

 

Appel de l’appareil photo dans l’application Kivy

Attention, avant de procéder à l’appel de caméra pour prendre une photo, il faut savoir une chose : l’application Kivy se mets en pause. Pour ce faire, il est nécessaire que l’instance de App définisse la méthode « pause » et renvoie « True ». C’est un peu comme si Kivy disant « je mets en pause l’appli, est-ce que j’en ait le droit ? ». Si « True », je passe à la suite. Si « False », je stoppe.

 

Le service d’appel de la photo est défini comme ceci (basé sur le tuto « takepicture ») :

from jnius import autoclass, cast
from android import activity
from functools import partial
from kivy.clock import Clock
import os

Intent = autoclass('android.content.Intent')
PythonActivity = autoclass('org.renpy.android.PythonActivity')
MediaStore = autoclass('android.provider.MediaStore')
Uri = autoclass('android.net.Uri')
Environment = autoclass('android.os.Environment') 

class CameraService(object):
    '''
    Service pour acceder a la camera du device.
    Attention, seules les images JPG sont autorisées.
    '''

    def __init__(self, savingPath = None, aFilename = None):
        '''
        Constructeur
        savingPath doit se terminer par le separateur de répertoire
        '''
        if savingPath is None:
            savingPath = Environment.getExternalStorageDirectory().getPath()
        self.path = savingPath
        self.filename = aFilename
        self.picture = None

    def __define_new_filename(self):
        index = 0
        while True:
            index += 1
            fn = os.path.join(self.path, 'takepicture{}.jpg'.format(index))
            if not os.path.exists(fn):
                return fn

    def take_picture(self, aCallbackFunction):
        self.callbackFunction = aCallbackFunction
        if self.filename is None:
            self.filename = self.__define_new_filename()
        uri = Uri.parse('file://' + os.path.join(self.path, self.filename) )
        uri = cast('android.os.Parcelable', uri)

        activity.bind(on_activity_result=self.__on_activity_result)

        intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
        PythonActivity.mActivity.startActivityForResult(intent, 0x123)

    def __on_activity_result(self, requestCode, resultCode, intent):
        if requestCode == 0x123:
            Clock.schedule_once(partial(self.__add_picture, self.filename), 0)

    def __add_picture(self, fn, *args):
        self.picture = fn
        self.callbackFunction(self.picture)
        activity.unbind(on_activity_result=self.__on_activity_result)

 

Son appel se fait dans une instance de Screen, par exemple :

class myScreen(Screen):
    #...

    def btn_take_photo(self):
        camera = CameraService()
        camera.take_picture(self.set_picture)

    def set_picture(self, newPicture_name):
        self.logLabel.text = "Photo : %s" % str(newPicture_name)

Lorsqu’un bouton est cliqué, la méthode « btn_take_photo() » est appelée. Celle-ci fait appel au service (sans paramètre dans ce cas) et lance la prise de photo avec un paramètre : la méthode à appeler lorsque l’utilisateur aura terminé : « self.set_picture ».

Cette méthode prend un paramètre : le nom du fichier sauvegardé par l’appareil photo du smartphone. Attention, seul le format JPEG est autorisé…

 

Conclusion

Pour reprendre cette photo, je vous conseille de la réduire avec PIL pour éviter d’avoir une image en 4128 x 2322 pixels.

im = Image.open(filename)
width, height = im.size
im.thumbnail( (width/4,height/4) , Image.ANTIALIAS)
im.save(filename,quality=95)

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>