Image 在Android上的React Native中压缩base64编码图像无法识别';数据';协议

Image 在Android上的React Native中压缩base64编码图像无法识别';数据';协议,image,react-native,react-native-android,Image,React Native,React Native Android,问题 在React原生(0.43)应用程序中,我们使用一个组件,该组件使用SectionList渲染按天排序的照片。每个部分可以包含多个图像。照片使用react native image crop picker库拍摄并上载到后端,如果没有可用的internet连接,则在本地排队,并以base64格式编码。图像分辨率设置为800x800像素(图像的其他用途要求)。在内存较低的手机上,由于内存不足,渲染约20幅图像将使应用程序崩溃。这个问题只能在低端Android手机上重现,但我认为这是一个内存不足

问题

在React原生(0.43)应用程序中,我们使用一个组件,该组件使用SectionList渲染按天排序的照片。每个部分可以包含多个图像。照片使用react native image crop picker库拍摄并上载到后端,如果没有可用的internet连接,则在本地排队,并以base64格式编码。图像分辨率设置为800x800像素(图像的其他用途要求)。在内存较低的手机上,由于内存不足,渲染约20幅图像将使应用程序崩溃。这个问题只能在低端Android手机上重现,但我认为这是一个内存不足的问题,与操作系统无关。为了解决这个问题,需要生成缩略图来测试是否存在这种情况。与生成这些缩略图的时间无关(在发送到服务器之前或在加载组件之前)。下面的代码在iOS上运行良好,但在Android上会抛出错误:未知协议:来自ImageEditor.cropImage()函数的数据

main.js文件中的代码片段

    //The mergeReduxWithMeteor function takes care of merging the redux state, 
    //containing images not yet uploaded to the server, 
    //and the Meteor data as received by the server.
    //No issues here...

    helpers.mergeReduxWithMeteor(props.photoStore, props.SynergySummaryReady ? props.SynergyData : [])

        //The imageHelper.compressPhoto does the actual compression
        //No issues with the promise chain as is.

        .then((data) => {
            return Promise.all(data.map(imageHelper.compressPhoto))
        })

        // The remaining functions take care of the formatting for the SectionList.
        // No issues here either... :)

        .then((data) => {
            return helpers.clusterDataByDay(data)
        })

        //We populate the resulting data in the state that is used for the SectionList

        .then((data) => {
            this.setState({NotHorusData: data})
        })
        .catch((error) => console.error(error))
imageHelper.compressphoto()

方法1:修复Android上的数据协议问题

from RN解决了相同的问题,但没有提供解决方案

方法2:通过在Android上提供uri绕过数据协议问题

尽管由于增加了通信/延迟而不太有利,但另一种方法是通过提供ImageStore提供的临时URI来避免数据协议问题。请参阅下面针对Android的改编代码

if(Platform.OS === 'android'){
  ImageStore.addImageFromBase64(`data:image/jpeg;base64,${photo.data.userPhoto}`, (tempURI) => {
    ImageEditor.cropImage(tempURI, imageSize, (imageURI) => {
         ImageStore.getBase64ForTag(imageURI, (base64Data) => {
           ImageStore.removeImageForTag(tempURI)
           resolve({
             ...photo,
             data: {
               ...photo.data,
               userPhoto: base64Data,
             }
           })
       }, (error) => reject(error))
     }, (error) => reject(error))
  }, (error) => reject(error))  
}
不幸的是,Android上无法识别ImageStore.addImageFromBase64


有没有人拥有Android上ImageEditor和ImageStore的经验,在这种情况下可能会有所帮助?任何其他方法也欢迎

我通过在iOS和Android上使用react-native fetch blob和react-native image resizer解决了这个问题。与上述问题中的实现相比,性能出人意料地好。我将下面的代码共享给其他人使用:)


gist将base64编码的图片存储在缓存目录中,并使用imageResizer获取图像,对其进行压缩,然后在base64中再次读取以供使用

干得好!!
if(Platform.OS === 'android'){
  ImageStore.addImageFromBase64(`data:image/jpeg;base64,${photo.data.userPhoto}`, (tempURI) => {
    ImageEditor.cropImage(tempURI, imageSize, (imageURI) => {
         ImageStore.getBase64ForTag(imageURI, (base64Data) => {
           ImageStore.removeImageForTag(tempURI)
           resolve({
             ...photo,
             data: {
               ...photo.data,
               userPhoto: base64Data,
             }
           })
       }, (error) => reject(error))
     }, (error) => reject(error))
  }, (error) => reject(error))  
}
export function compressPhoto(photo) {
return new Promise((resolve, reject) => {

    let tempUri = `${cache}/Vire_${photo.data.userPhotoDate}.jpg`

    fs.writeFile(tempUri, photo.data.userPhoto, "base64")
        .then(() => {
            ImageResizer.createResizedImage(
                `file:${tempUri}`, IMAGE_TARGET_SIZE, IMAGE_TARGET_SIZE, "JPEG", 100, 0).then((resizedImageUri) => {
                fs.readFile(`${resizedImageUri}`, "base64")
                    .then( data => {
                        resolve({...photo, data: { ...photo.data, userPhoto: data }})
                    })
                    .catch(error => reject(`readFile:error: ${error}`))
            },
            (error) => reject(`createResizedImage:error: ${error}`)
            )
        })
        .catch( error => {
            reject(`writeFile:error: ${error}`)
        })

     })
}