onfido-sdk-ui
Version:
JavaScript SDK view layer for Onfido identity verification
144 lines (122 loc) • 3.99 kB
text/typescript
import supportsWebP from 'supports-webp'
import loadImage from 'blueimp-load-image'
import 'blueimp-load-image/js/load-image-orientation'
import 'blueimp-load-image/js/load-image-exif'
type Base64ResultCallback = (result: string) => void
type CanvasResultCallback = (canvas: HTMLCanvasElement) => void
type ErrorCallback = (error: Event) => void
type BlobResultCallback = (blob: Blob) => void
type FileReaderCallback = (error: ProgressEvent<FileReader>) => void
type Base64Blob = {
integerArray: Uint8Array
mimeString: string
}
type ImageOptions = {
canvas?: boolean
maxHeight?: number
maxWidth?: number
orientation?: boolean
}
const blobToBase64 = (
blob: Blob,
callback: Base64ResultCallback,
errorCallback: FileReaderCallback
): void => {
const reader = new FileReader()
reader.readAsDataURL(blob)
reader.onload = () => {
callback(reader.result as string)
}
reader.onerror = function (error) {
console.warn('File Reading Error: ', error)
errorCallback(error)
}
}
const blobToCanvas = (
blob: Blob,
callback: CanvasResultCallback,
errorCallback: ErrorCallback,
options?: ImageOptions
): void => {
const {
maxWidth = 960,
maxHeight = 960,
orientation = true,
// `blueimp-load-image` doesn't fallback to use a canvas tag if image
// orientation is supported by the browser (see https://caniuse.com/#feat=css-image-orientation).
// We rely on a <canvas /> rather than a <img /> for our image operations.
// This option forces the library to always use a canvas tag.
canvas = true,
} = options || {}
loadImage(
blob,
(canvasOrEventError) => {
if (canvasOrEventError instanceof Event) {
errorCallback(canvasOrEventError)
} else if (canvasOrEventError instanceof HTMLCanvasElement) {
callback(canvasOrEventError)
} else {
console.warn('Result mismatched:', canvasOrEventError)
}
},
{ maxWidth, maxHeight, orientation, canvas }
)
}
const decodeBase64 = (image: string): Base64Blob => {
const byteString = atob(image.split(',')[1])
const mimeString = image.split(',')[0].split(':')[1].split(';')[0]
const integerArray = new Uint8Array(byteString.length)
for (let i = 0; i < byteString.length; i++) {
integerArray[i] = byteString.charCodeAt(i)
}
return { integerArray, mimeString }
}
const base64toBlob = (image: string): Blob => {
const base64Data = decodeBase64(image)
return new Blob([base64Data.integerArray], { type: base64Data.mimeString })
}
const toDataUrl = (type: string) => (
canvas: HTMLCanvasElement,
callback: (dataURL: string) => void
) => callback(canvas.toDataURL(type))
export const canvasToBlob = (
canvas: HTMLCanvasElement,
callback: BlobResultCallback,
mimeType = 'image/png'
): void => {
if (!HTMLCanvasElement.prototype.toBlob) {
// Handle browsers that do not support canvas.toBlob() like Edge
const dataUrlImg = canvas.toDataURL()
callback(base64toBlob(dataUrlImg))
return
}
canvas.toBlob((blob) => blob && callback(blob), mimeType)
}
export const blobToLossyBase64 = (
blob: Blob,
callback: Base64ResultCallback,
errorCallback: FileReaderCallback,
options?: ImageOptions
): void => {
const browserSupportedLossyFormat = `image/${supportsWebP ? 'webp' : 'jpeg'}`
const toLossyImageDataUrl = toDataUrl(browserSupportedLossyFormat)
const asBase64 = () => blobToBase64(blob, callback, errorCallback)
const asLossyBase64 = () =>
blobToCanvas(
blob,
(canvas) => toLossyImageDataUrl(canvas, callback),
asBase64,
options
)
isOfMimeType(['pdf'], blob) ? asBase64() : asLossyBase64()
}
export const mimeType = (blob?: Blob): Optional<string> => {
if (!blob || !blob.type) {
return null
}
return blob.type.split('/')[1]
}
export const isOfMimeType = (mimeTypeList: string[], blob: Blob): boolean =>
mimeTypeList.some(
(acceptableMimeType) => acceptableMimeType === mimeType(blob)
)