繁体   English   中英

在 Android 上压缩 React-Native 中的 base64 编码图像无法识别“数据”协议

[英]Compressing base64 encoded images in React-Native on Android does not recognise 'data' protocol

问题

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

来自 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()

export function compressPhoto(photo) {
  return new Promise((resolve, reject) => {

    let imageSize = {
      offset: {
        x: 0,
        y: 0
      },
      size: {
        width: IMAGE_SIZE,
        height: IMAGE_SIZE
      },
      displaySize: {
        width: IMAGE_TARGET_SIZE,
        height: IMAGE_TARGET_SIZE,
      },
      resizeMode: 'contain'
    }


    ImageEditor.cropImage(`data:image/jpeg;base64,${photo.data.userPhoto}`, imageSize, (imageURI) => {
      ImageStore.getBase64ForTag(imageURI, (base64Data) => {
        resolve({
          ...photo,
          data: {
            ...photo.data,
            userPhoto: base64Data,
          }
        })
      }, (error) => reject(error))
    }, (error) => reject(error))

  })
}

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

来自 RN 的Github 上的问题解决了相同的问题,但没有提供解决方案。

方法 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 上的ImageEditorImageStore有任何经验,在这种情况下可能会有所帮助? 也欢迎任何其他方法!

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

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}`)
        })

     })
}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM