AccueilClients

Applications et sites

  • Application métiersIntranet, back-office...
  • Applications mobilesAndroid & iOS
  • Sites InternetSites marketings et vitrines
  • Expertises techniques

  • React
  • TypeScript
  • Next.js
  • Expo / React Native
  • Node.js
  • Directus
  • Open SourceBlogContactEstimer

    7 mai 2024

    React Native Camera Vision x Skia : les nouveautés de la v4

    5 minutes de lecture

    React Native Camera Vision x Skia : les nouveautés de la v4
    🇺🇸 This post is also available in english

    Si vous avez déjà développé une application mobile nécessitant l’usage de la caméra, alors le nom de React Native Vision Camera vous dit sûrement quelque chose. Flexible et efficace, cette librairie permet d’intégrer facilement les fonctionnalités vidéo et photo aux applications react native.

    La v4 de la librairie annonce le grand retour du hook useSkiaFrameProcessor, qui promettait une intégration des fonctionnalités de la bibliothèque graphique Skia directement aux frames de la caméra. Un temps considéré sur la v3, ce hook avait finalement été retiré en raison de problèmes de maintenabilité. Mais la détermination de Marc Rousavy le créateur de React Native Vision Camera, a finalement porté ses fruits, et c’est cette dernière version qui accueille le nouveau hook.

    Chez Premier Octet, nous travaillons depuis un certain temps sur notre nouveau projet mobile : Photobooth AI, un studio photo s’appuyant sur l'intelligence artificielle pour réinventer vos portraits. Cette application Expo utilise React Native Vision Camera pour la gestion de la capture d'images. C’est donc l’occasion pour nous d’explorer de nouvelles fonctionnalités pour notre application.

    Photobooth AI

    Configuration de l'application sur Expo

    Avant toute chose, nous devons bien sûr installer React Native Vision Camera

    npx expo install react-native-vision-camera
    

    (par ici pour la doc détaillée)

    Pour gérer les actions au sein de notre frame processor, nous aurons également besoin de React Native Worklets Core, une librairie de gestion des worklet créée par l'agence de Marc Rousavy

    yarn add react-native-worklets-core
    

    N'oubliez pas d'ajouter le plugin à votre babel.config.js

    module.exports = {
      plugins: [['react-native-worklets-core/plugin']],
    }
    

    Et bien entendu React Native Skia pour la partie dessin

    yarn add @shopify/react-native-skia
    cd ios
    pod install
    

    Dessiner sur nos frames avec useSkiaFrameProcessor

    Depuis la v3 ​​de la bibliothèque, la fonctionnalité frameProcessor permet d'appliquer un worklet JavaScript à chaque image capturée par la caméra. Comme les frameProcessor traitent chaque frame de manière synchrone, la vitesse d'exécution de leur code est essentielle pour avoir un affichage fluide. Grâce aux worklets, les opérations de nos frameProcessors sont exécutées sur un thread secondaire, ce qui évite de trop impacter les performances de l'application et de viser les 60 FPS.

    Le nouveau hook Skia rajoute une surcouche à ce fonctionnement en intégrant directement un canvas à nos frames. On peut tracer ce que l’on souhaite en utilisant l’API impérative de React Native Skia sur notre frame :

    CameraScreen.tsx
    import { PaintStyle, Skia } from "@shopify/react-native-skia"
    import {
      Camera,
      useSkiaFrameProcessor,
    } from "react-native-vision-camera"
    
    [...]
    
    // On initialise une couleur
    const paint = Skia.Paint()
    paint.setColor(Skia.Color("red"))
    
    // On définit notre frameProcessor
    const frameProcessor = useSkiaFrameProcessor((frame) => {
       "worklet"
       frame.render() // nécessaire pour voir le rendu caméra
       const centerX = frame.width / 2
       const centerY = frame.height / 2
       frame.drawCircle(centerX, centerY, 50, paint)
    }, [])
    
    [...]
    
    // On passe le frame processor à notre caméra
    <Camera
    ref={camera}
    device={device}
    format={format}
    orientation="portrait"
    photo
    frameProcessor={frameProcessor}
    />
    

    Les coordonnées sont exprimées sur un axe x,y par rapport à l’origine du frame en haut à gauche (0,0).

    Et notre forme apparaît sur notre écran de photobooth : Dessiner des formes sur les frames avec Skia

    Actuellement, les données affichées sur le frame sont visibles uniquement en mode de prévisualisation. Par conséquent, la surcouche Skia ne sera pas intégrée aux vidéos et aux photos capturées par React Native Vision Camera.

    Ajouter des animations avec Reanimated

    Profitons du nouveau hook Skia pour afficher un guide de positionnement du visage à nos utilisateurs. Pour le rendre un peu plus ludique, une animation serait plus sympathique pour afficher la forme. Skia propose une intégration avec Reanimated pour gérer les animations, installons la librairie sur le projet :

    npx expo install react-native-reanimated
    

    Pour obtenir une animation d’apparition progressive du contour avec le temps, nous initialisons une sharedValue et y appliquons le hook withTiming de Reanimated. Afin de s’assurer que notre caméra soit activée avant le début de l'animation, nous décalerons légèrement son démarrage avec le hook withDelay.

    import { Worklets, useSharedValue as useWorkletShareValue } from 'react-native-worklets-core'
    import { PaintStyle, Skia } from '@shopify/react-native-skia'
    import { withTiming, useSharedValue, useAnimatedReaction, withDelay } from 'react-native-reanimated'
    
    const paint = Skia.Paint()
    paint.setColor(Skia.Color('#F1EBE1'))
    
    const reanimatedProgress = useSharedValue(0)
    useEffect(() => {
      reanimatedProgress.value = withDelay(
        500,
        withTiming(1, {
          duration: 2000,
        })
      )
    }, [])
    

    Une petite subtilité pour accéder à notre valeur de progression dans le worklet

    La valeur définie par useSharedValue de reanimated n’est malheureusement pas accessible depuis le frameProcessor. React Native Worklets Core dispose de son propre hook useSharedValue pour accéder à des valeurs au sein du frameProcessor. En attendant une meilleure compatibilité entre les deux (peut-être dans la v5 🤞) un passage de l’une à l’autre des variables est possible en utilisant useAnimatedReaction pour updater la seconde sharedValueavec les valeurs de la première.

    const workletProgress = useWorkletShareValue(0)
    useAnimatedReaction(
      () => reanimatedProgress.value,
      (value, prevValue) => {
        workletProgress.value = value
      }
    )
    

    Nous passons ensuite le paramètre de progression de dessin dans notre frameProcessor pour afficher le guide graduellement :

    const frameProcessor = useSkiaFrameProcessor(
      (frame) => {
        'worklet'
        frame.render()
    
        const width = 340
        const height = 450
        const x = frame.width / 2 - width / 2
        const y = frame.height / 2 - height / 2
        const path = Skia.Path.Make()
    
        path.addOval(Skia.XYWHRect(x, y, width, height))
        path.trim(0, workletProgress.value, false)
    
        paint.setStyle(PaintStyle.Stroke)
        paint.setStrokeWidth(4)
        frame.drawPath(path, paint)
      },
      [paint, workletProgress]
    )
    

    Et l’animation se lance bien au démarrage de la caméra 🥳

    Plus de stabilité sur Android et la géolocalisation en prime

    Enfin cette nouvelle version corrige quelques bugs gênants que nous avions pu expérimenter sur Android (retournement aléatoire de photos et problème d'activation de la caméra au lancement). Initialement basée sur le package Camera2 la v4 utilise dorénavant la lib Android CameraX plus fiable. React Native Vision Camera nous promet donc plus de stabilité avec cette nouvelle version et c’est un soulagement 🥲 !
    On notera aussi l'ajout, de la possibilité de lier des tags de localisation sur les photos et vidéos, ainsi que d'un nouveau hook useLocationPermission pour obtenir les permissions liées.

    Conclusion

    Avec l'introduction de ce nouveau hook Skia, React Native Vision Camera ouvre de nouvelles perspectives passionnantes pour les animations et les interactions avec la caméra. Bien que la documentation de React Native Skia ne soit pas très détaillée concernant l'API impérative, il est assez facile de trouver des moyens d'atteindre ses objectifs, et nous espérons que ce hook marquera le début d'une collaboration fructueuse entre les deux librairies.

    La possibilité d'intégrer des animations avec Reanimated, même si le partage des shared values reste perfectible, rend la fonctionnalité particulièrement attrayante. Nous sommes donc impatients de découvrir les prochaines versions et améliorations à venir, mais cette v4 annonce d’ores et déjà un futur prometteur pour React Native Vision Camera 👏👏👏 !

    À découvrir également

    Premier Octet vous accompagne dans le développement de vos projets avec react-native

    En savoir plusNous contacter
    18 avenue Parmentier
    75011 Paris
    +33 1 43 57 39 11
    hello@premieroctet.com

    Suivez nos aventures

    GitHub

    X

    Flux RSS

    Bluesky

    Naviguez à vue