UNPKG

onfido-sdk-ui

Version:

JavaScript SDK view layer for Onfido identity verification

156 lines (132 loc) 4.13 kB
import { findKey } from '~utils/object' import { isOfMimeType, canvasToBlob } from '~utils/blob' import type { ImageResizeInfo } from '~types/commons' type ImageSize = { width: number height: number } type ImageResizePayload = { resizedImage: Blob imgDiff: ImageResizeInfo } type ImageResizeCallback = (payload: ImageResizePayload) => void const INVALID_IMAGE_SIZE = 'INVALID_IMAGE_SIZE' const INVALID_SIZE = 'INVALID_SIZE' const INVALID_TYPE = 'INVALID_TYPE' type ImageValidationTypes = | typeof INVALID_IMAGE_SIZE | typeof INVALID_SIZE | typeof INVALID_TYPE type ImageValidationCallback = (file: Blob) => boolean const DEFAULT_ACCEPTED_FILE_TYPES = ['jpg', 'jpeg', 'png', 'pdf'] const MAX_FILE_SIZE_ACCEPTED_BY_API = 10000000 // The Onfido API only accepts files below 10 MB const MAX_IMAGE_FILE_SIZE_ACCEPTED = 3000000 const MAX_SIZE_IN_PIXEL = 1440 const validateFileTypeAndSize = ( file: Blob, acceptedTypes = DEFAULT_ACCEPTED_FILE_TYPES ): ImageValidationTypes => { const imageValidators: Record< ImageValidationTypes, ImageValidationCallback > = { INVALID_TYPE: (file) => !isOfMimeType(acceptedTypes, file), INVALID_IMAGE_SIZE: (file) => file.type.match(/image.*/) != null && file.size > MAX_IMAGE_FILE_SIZE_ACCEPTED, INVALID_SIZE: (file) => file.size > MAX_FILE_SIZE_ACCEPTED_BY_API, } return findKey(imageValidators, (checkFn) => checkFn(file)) } const resizeImageFile = ( file: Blob, onImageResize: ImageResizeCallback ): void => { const reader = new FileReader() reader.onload = (readerEvent) => { const image = new Image() image.onload = () => { const resizeTo = getDimensionsToResizeTo(image) const tempCanvas = document.createElement('canvas') tempCanvas.width = resizeTo.width tempCanvas.height = resizeTo.height tempCanvas .getContext('2d') ?.drawImage(image, 0, 0, resizeTo.width, resizeTo.height) const imgDiff = { resizedFrom: { width: image.width, height: image.height, fileSize: file.size, }, resizedTo: { width: resizeTo.width, height: resizeTo.height, }, } return canvasToBlob( tempCanvas, (blob) => onImageResize({ resizedImage: blob, imgDiff }), file.type ) } if (typeof readerEvent.target?.result === 'string') { image.src = readerEvent.target?.result } } reader.readAsDataURL(file) } export const getDimensionsToResizeTo = ( originalImage: ImageSize ): ImageSize => { // 1440px because we want to conservatively resize for Web SDK // compared to mobile SDKs' 720p (1280×720px) as their UI always has a frame let newWidth = originalImage.width let newHeight = originalImage.height const ratio = originalImage.width / originalImage.height if (ratio > 1) { // landscape orientation newWidth = MAX_SIZE_IN_PIXEL newHeight = (originalImage.height * newWidth) / originalImage.width return { width: newWidth, height: newHeight, } } // portrait orientation newHeight = MAX_SIZE_IN_PIXEL newWidth = (originalImage.width * newHeight) / originalImage.height return { width: newWidth, height: newHeight, } } export const validateFile = ( file: Blob, onSuccess: (file: Blob, imageResizeInfo?: ImageResizeInfo) => void, onError: (error: ImageValidationTypes) => void ): void => { const fileError = validateFileTypeAndSize(file) const imageResizeInfo: ImageResizeInfo | undefined = undefined if (fileError === INVALID_IMAGE_SIZE) { resizeImageFile(file, ({ resizedImage, imgDiff }) => { if (resizedImage.size >= file.size) { onSuccess(file, imageResizeInfo) } else { onSuccess(resizedImage, { resizedFrom: { ...imgDiff.resizedFrom, }, resizedTo: { ...imgDiff.resizedTo, fileSize: resizedImage.size, }, }) } }) } else if (fileError) { onError(fileError) } else { onSuccess(file, imageResizeInfo) } }