Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance Warning in amplify-liveness: Canvas2D getImageData should use willReadFrequently #5482

Open
4 tasks done
nonimusCode opened this issue Jul 26, 2024 · 3 comments
Open
4 tasks done
Labels
feature-request Request a new feature Liveness

Comments

@nonimusCode
Copy link

Before creating a new issue, please confirm:

On which framework/platform are you having an issue?

React, Other

Which UI component?

Liveness

How is your app built?

My app is built using the following system: Framework: Next.js 13.4.10 Build System: Webpack 5

What browsers are you seeing the problem on?

Chrome, Firefox, Microsoft Edge

Which region are you seeing the problem in?

us-east-1

Please describe your bug.

When I enable the camera in the Amplify Liveness component in my Next.js application, I receive a warning related to Canvas2D performance. The warning message is as follows:

Canvas2D: Multiple readback operations using getImageData are faster with the willReadFrequently attribute set to true. See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext

This warning indicates that multiple readback operations using getImageData could be optimized by setting the willReadFrequently attribute to true.

image

What's the expected behaviour?

I expected the Amplify Liveness component to run without any performance-related warnings in the console when the camera is enabled.

Help us reproduce the bug!

  1. Set up a Next.js application: Create or use an existing Next.js project with version 13.4.10.

  2. Install the necessary libraries: Add @aws-amplify/ui-react-liveness and aws-amplify to your project.

  3. Configure Amplify: Set up AWS Amplify with the appropriate configuration in your project.

  4. Add the Amplify Liveness component: Include the AmplifyLiveness component in one of your pages.

  5. Run the application: Start the development server.

  6. Open the page with Liveness component: Navigate to the page in your browser.

  7. Enable the camera: Follow the prompts to access the camera.

  8. Check the console: Look for a performance warning related to Canvas2D.

Code Snippet

import React, { useState, useContext, useEffect } from 'react'
import { FaceLivenessDetector } from '@aws-amplify/ui-react-liveness'
import { useServiceAwsRecognition } from '../../hooks/fecth/rekogniton'
import { View, Flex, ThemeProvider } from '@aws-amplify/ui-react'
import '@aws-amplify/ui-react/styles.css'
import { AuthEmailContext } from '../../context/AuthContext'
import { useRouter } from 'next/router'
import { Button } from 'react-daisyui'
import { useTranslation } from 'react-i18next'
import Image from 'next/image'
import { Cookies } from 'react-cookie'
import { ErrorsLivenessInterface } from '../../interfaces/liveness.interfaces'
import { OverlayModal } from '@components/modal/OverlayModal'
import { LoadingDinamic } from '@components/loading/loadingDinamic'
import { LivenessError } from '@aws-amplify/ui-react-liveness/dist/types/components/FaceLivenessDetector/service'
import { useLocation } from '../../hooks/location/useGetLocation'
import { useDeviceDetected } from '../../hooks/deviceDetect/useDeviceDetected'
import { useIPAddress } from '../../hooks/fecth/ipAddress'

const cookies = new Cookies()

interface Prop {
setNumberFails: (param: number | ((prevFails: number) => number)) => void
numberFails: number
}

export function LivenessQuickStartReact({ setNumberFails, numberFails }: Prop) {
const router = useRouter()
const { connectWithFace } = useContext(AuthEmailContext)
const [loading, setLoading] = useState(true)
const [modalHandleErrors, setModalHandleErrors] = useState(false)
const [manageErrors, setManageErrors] = useState<string | null>(null)
const { t } = useTranslation()
const [createLivenessApiData, setCreateLivenessApiData] = useState<{
SessionId: string
}>({ SessionId: '' })
const [loadingFaceId, setLoadingFaceId] = useState(false)
const { positionLocation } = useLocation()
const { InformationUser } = useDeviceDetected()
const { Ip } = useIPAddress()
const dictionary = {
hintTooFarText: t('hintTooFarText'),
hintTooCloseText: t('hintTooCloseText'),
hintHoldFaceForFreshnessText: t('hintHoldFaceForFreshnessText'),
hintConnectingText: t('hintConnectingText'),
hintVerifyingText: t('hintVerifyingText'),
tryAgainText: t('tryAgainText'),
landscapeMessageText: t('landscapeMessageText'),
landscapeHeaderText: t('landscapeHeaderText'),
cameraNotFoundHeadingText: t('cameraNotFoundHeadingText'),
cameraNotFoundMessageText: t('cameraNotFoundMessageText'),
retryCameraPermissionsText: t('retryCameraPermissionsText')
}

const ErrorsLiveness: ErrorsLivenessInterface = {
TIMEOUT: {
title: t('liveness_TIMEOUT.title'),
description: t('liveness_TIMEOUT.description')
},
MOBILE_LANDSCAPE_ERROR: {
title: t('liveness_MOBILE_LANDSCAPE_ERROR.title'),
description: t('liveness_MOBILE_LANDSCAPE_ERROR.description')
},
FACE_DISTANCE_ERROR: {
title: t('liveness_FACE_DISTANCE_ERROR.title'),
description: t('liveness_FACE_DISTANCE_ERROR.description')
},
MULTIPLE_FACES_ERROR: {
title: 'Multiple faces detected',
description: 'More than one face cannot be detected'
}
}

const handleCloseModal = () => {
setLoadingFaceId(!loadingFaceId)
}
const { createFaceLiveness, getFaceLiveness, loginFaceID } =
useServiceAwsRecognition()

useEffect(() => {
getSessionId()
}, [])
const getSessionId = async () => {
const SessionId = await createFaceLiveness()
if (typeof SessionId === 'string') {
return SessionId
}
setCreateLivenessApiData(SessionId)
setLoading(false)
}
const handleAnalysisComplete = async () => {
const responseResultsFaces = await getFaceLiveness(
createLivenessApiData.SessionId
)
const dataMachine = InformationUser()
const ip: any = await Ip()
const data: any = {
imageName:
responseResultsFaces.data.responselivvenesseccion.ReferenceImage
.S3Object.Name,
bucketName:
responseResultsFaces.data.responselivvenesseccion.ReferenceImage
.S3Object.Bucket,
session: 'FLAS',
fingerprint: cookies.get('deviceFingerprint')
}
const percentage: number =
responseResultsFaces.data.responselivvenesseccion.Confidence
if (percentage <= 65) {
setNumberFails((prevFails) => prevFails + 1)
setLoadingFaceId(true)
return
}
data.dataMachine = { ...dataMachine }
data.ip = ip
if (positionLocation) {
data.latitude = positionLocation.latitude
data.longitude = positionLocation.longitude
data.acurrency = positionLocation.accuracy
data.type = 'login'
}
handleLoginVerify(data)
}

const handleError = async (error: LivenessError) => {
if (error.state === 'FACE_DISTANCE_ERROR') {
createSessionId()
return
}
if (ErrorsLiveness[error.state]) {
await setManageErrors(error.state)
setModalHandleErrors(true)
} else {
console.error(JSON.stringify(error))
}
}
const createSessionId = () => {
setLoading(true)
getSessionId().finally(() => {
setLoading(false)
})
}

const handleLoginVerify = async (data: any) => {
try {
const response: any = await loginFaceID(data)
await connectWithFace(response)

  // if success redirect to dashboard wih next router
  if (response.data.user.roleId === 8) {
    return router.push('/generation')
  }
  return router.push('/dashboard')
} catch (err) {
  console.log(err)

  setNumberFails((prevFails) => prevFails + 1)
  setLoadingFaceId(true)
  return
}

}

return (

{loading ? (
<LoadingDinamic
height={100}
width={100}
text={t('establishing_connection')}
/>
) : (
<Flex
justifyContent="center"
alignItems="center"
width={{
base: '80vh',
small: '70vh',
medium: '50vh',
large: '50vh',
xl: '400px',
xxl: '700px'
}}>
<View
width={{
base: '100%',
small: '100%',
medium: '100%',
large: '100%',
xl: '100%',
xxl: '100%'
}}
position={'flex justify-center'}
backgroundColor="#00d40f">
<FaceLivenessDetector
sessionId={createLivenessApiData.SessionId}
region="us-east-1"
onUserCancel={createSessionId}
onAnalysisComplete={handleAnalysisComplete}
onError={handleError}
disableInstructionScreen={true}
displayText={dictionary}
components={{
ErrorView: () => {
return


}
}}
/>


)}

  <OverlayModal
    className="z-999"
    activeModal={modalHandleErrors}
    closeModal={() => {
      setModalHandleErrors(!modalHandleErrors)
      createSessionId()
    }}>
    <OverlayModal.Header>
      {manageErrors && ErrorsLiveness[manageErrors]['title']}
    </OverlayModal.Header>

    <OverlayModal.Body>
      {manageErrors && ErrorsLiveness[manageErrors]['description']}
    </OverlayModal.Body>
  </OverlayModal>

  <OverlayModal
    className="z-999"
    activeModal={loadingFaceId}
    closeModal={() => {
      handleCloseModal()
      createSessionId()
    }}>
    <OverlayModal.Header>No se reconoce el rostro</OverlayModal.Header>

    <OverlayModal.Body>
      <div className="mt-2 gap-4">
        <div className="flex flex-row justify-center item text-6xl text-red-600 mb-5">
          <Image src={'/red.svg'} alt="error" width={100} height={100} />
        </div>
        <span className="text-xl text-primary">Asegurate de tener:</span>
        <div className="flex justify-start  flex-col">
          <p>• Buena iluminación</p>
          <p>• Cámara Limpia</p>
        </div>
        <p className="text-primary">
          Te quedan {`(${3 - numberFails}) `}intentos
        </p>
      </div>
    </OverlayModal.Body>
    <OverlayModal.Actions className="flex justify-center">
      <Button
        className="rounded-full text-xl"
        color="primary"
        id="button-cookies"
        onClick={() => {
          handleCloseModal()
          createSessionId()
        }}>
        Volver a Intentar
      </Button>
    </OverlayModal.Actions>
  </OverlayModal>
</ThemeProvider>

)
}

Console log output

No response

Additional information and screenshots

"dependencies": {
"@aws-amplify/ui-react-liveness": "^2.0.4",
"aws-amplify": "^5.3.8",
}

image

@github-actions github-actions bot added the pending-triage Issue is pending triage label Jul 26, 2024
@reesscot reesscot added pending-triage Issue is pending triage and removed pending-triage Issue is pending triage labels Jul 26, 2024
@esauerbo
Copy link
Contributor

Hey @nonimusCode thanks for creating this issue. We'll take this into consideration for our roadmap.

@esauerbo esauerbo removed the pending-triage Issue is pending triage label Jul 29, 2024
@jacoblogan jacoblogan added the feature-request Request a new feature label Aug 12, 2024
@andresem
Copy link

andresem commented Oct 1, 2024

@esauerbo any update about this?

@github-actions github-actions bot added the pending-maintainer-response Issue is pending response from an Amplify UI maintainer label Oct 1, 2024
@cwomack
Copy link
Member

cwomack commented Oct 7, 2024

@andresem, we don't have any updates at this point or an ETA on when this will be implemented. We'll update this issue as progress is made however. Thanks!

@github-actions github-actions bot removed the pending-maintainer-response Issue is pending response from an Amplify UI maintainer label Oct 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request Request a new feature Liveness
Projects
None yet
Development

No branches or pull requests

8 participants
@reesscot @jacoblogan @andresem @cwomack @esauerbo @nonimusCode @jordanvn and others