import { ImagePickerResponse, launchCamera, launchImageLibrary } from 'react-native-image-picker'
import { getBoolean } from './storage'
import navigationUtils from './navigationUtils'
import { RouteName, StorageType } from '@/types'
import PrivilegeUtil from './PrivilegeUtil'
import ImageResizer from '@bam.tech/react-native-image-resizer'
import RNFS from 'react-native-fs'
import { formatError } from '.'
import { Platform } from 'react-native'
let imageCallback: ((result: ImagePickerResponse) => void) | null = null
export const setImageCallback = (callback: (result: ImagePickerResponse) => void) => {
imageCallback = callback
}
const isIos = Platform.OS === 'ios'
export const clearImageCallback = () => {
imageCallback = null
}
export const handlePhotoResult = ({
photo,
width,
height,
base64,
}: {
photo: string
width: number
height: number
base64: string
}) => {
if (imageCallback) {
const fileName = photo.split('/')?.pop()
const result: ImagePickerResponse = {
assets: [
{
base64,
uri: photo,
type: 'image/jpeg',
fileName,
width,
height,
},
],
}
imageCallback(result)
clearImageCallback()
}
}
export const chooseImage = async (
accept: Array<'photo' | 'camera'>,
isMultiple = false
): Promise<ImagePickerResponse> => {
if (accept.length === 1) {
const type = accept[0]
const result = type === 'camera' ? await handlelaunchCamera() : await handleLaunchImageLibrary(isMultiple)
const { uri, width, height, fileSize, fileName } = result?.assets?.[0] ?? {}
handleEventTracking({
tip: '完成拍照,即将上传--chooseImage.ts--67',
data: {
fileInfo: {
uri,
width,
height,
fileSize,
fileName,
},
},
})
return result
} else {
return new Promise((resolve, reject) => {
const modalId = NormalModal.ActionSheet({
options: ['拍摄', '从相册选择'],
autoCloseModal: false,
onSelect: (_, index) => {
NormalModal.hide(modalId)
const result = index === 0 ? handlelaunchCamera() : handleLaunchImageLibrary(isMultiple)
result.then(resolve, reject)
},
})
})
}
}
const handleLaunchImageLibrary = async (isMultiple: boolean): Promise<ImagePickerResponse> => {
const result: ImagePickerResponse = await launchImageLibrary({
mediaType: 'photo',
selectionLimit: isMultiple ? 0 : 1,
includeBase64: false,
quality: isIos ? 0.6 : 0.8,
maxWidth: 1440,
maxHeight: 1440,
presentationStyle: 'fullScreen',
})
return handleCameraResult(result)
}
const handlelaunchCamera = async (): Promise<ImagePickerResponse> => {
const permission = await PrivilegeUtil.checkAndRequestCameraPermission()
let result: ImagePickerResponse = {}
if (!permission) return result
const customcamera = getBoolean(StorageType.CUSTOMCAMERA) || false
if (customcamera) {
result = await new Promise<ImagePickerResponse>((resolve) => {
setImageCallback(resolve)
navigationUtils.navigate(RouteName.CustomCamera)
})
} else {
result = await launchCamera({
mediaType: 'photo',
cameraType: 'back',
includeBase64: false,
quality: isIos ? 0.6 : 0.8,
maxWidth: 1440,
maxHeight: 1440,
presentationStyle: 'overFullScreen',
})
}
return await handleCameraResult(result)
}
const handleCameraResult = async (result: ImagePickerResponse) => {
const newResult = result
try {
if (newResult?.assets?.[0]?.uri) {
const response = await clearImageExif(newResult.assets[0].uri)
if (response) {
newResult.assets[0].base64 = response.base64String
newResult.assets[0].uri = response.uri
newResult.assets[0].fileSize = response.size
newResult.assets[0].width = response.width
newResult.assets[0].height = response.height
} else {
const { uri } = newResult.assets[0]
const base64 = await imageConversionBase64(uri)
if (base64) {
newResult.assets[0].base64 = base64
} else {
handleEventTracking({
tip: '本地图片转换base64地址失败--chooseImage.ts--141',
data: {
base64: base64,
uri,
},
})
}
}
}
} catch (error) {}
return newResult
}
export const clearImageExif = async (uri: string) => {
try {
if (isIos) return
const response = await ImageResizer.createResizedImage(uri, 1440, 1440, 'JPEG', 80, 0, null, false)
const base64String = await imageConversionBase64(response.uri)
return {
...response,
base64String,
}
} catch (error) {
handleEventTracking({
tip: '去除图片原数据失败--chooseImage.ts--130',
data: {
errorObj: formatError(error),
uri,
},
})
}
}
const imageConversionBase64 = async (uri: string) => {
try {
const base64String = await RNFS.readFile(uri, 'base64')
return base64String
} catch (error) {
handleEventTracking({
tip: '本地图片转换base64失败--chooseImage.ts--139',
data: {
errorObj: formatError(error),
uri,
},
})
return ''
}
}