在Android上的React-Native中压缩base64编码的图像无法识别' data'协议 [英] Compressing base64 encoded images in React-Native on Android does not recognise 'data' protocol

查看:78
本文介绍了在Android上的React-Native中压缩base64编码的图像无法识别' data'协议的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题

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

Within a React-Native (0.43) application we are using a component that uses a SectionList to render photos sorted by day. Each section can contain multiple images. Photos are taken using the react-native-image-crop-picker library and uploaded to the backend, or queued locally if no internet connection is available, encoded in base64 format. The image resolution is set to 800x800 pixels (requirement for other purposes of the images). On phones with lower memory, rendering ~20 images will crash the app due to insufficient memory. This issue can only be reproduced on low-end Android phones but I expect this to be a low memory issue and not related to the OS. To tackle this issue, thumbnails need to be generated to test if this is the case. Independent of when these thumbnails are generated (before sending to server or on-the-fly before loading component). The code below works fine for iOS but for Android it throws the error: Unknown protocol: data which comes from the ImageEditor.cropImage() function.

主.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上的数据协议问题

有关Github的问题解决了同一问题,但没有解决方案假如.

Issue on Github from RN addresses the same issue but no solution is provided.

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

尽管由于增加的通信/延迟而不利,但另一种方法是通过提供由ImageStore提供的临时URI来避免数据协议问题.请参见下面适用于Android的代码.

Although less favourable due to the added communication/delay, another approach is to avoid the data protocol issue by providing a temporary URI provided by ImageStore. See the adapted code below for 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))  
}

不幸的是, ImageStore.addImageFromBase64 在Android上无法识别.

Unfortunately ImageStore.addImageFromBase64 is not recognised on Android.

是否有人在Android上使用过 ImageEditor ImageStore 可能对这种情况有所帮助?也欢迎任何其他方法!

Does anyone have any experience with ImageEditor and ImageStore on Android that might be helpful in this situation? Any other approaches are welcome too!

推荐答案

我设法通过使用 react-native-fetch-blob react-native-image解决此问题-resizer (适用于iOS和Android).与上述问题的实现相比,性能出乎意料的好.我分享了以下代码供其他人使用:)

I managed to resolve the issue with the use of react-native-fetch-blob and react-native-image-resizer for both iOS and Android. Performance is unexpectedly good in comparison to the implementation in the question above. I shared the code below for others to use :)

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中再次读取该图像以供使用.

The gist is storing base64 encoded picture in the cache-directory and using imageResizer to fetch the image, compress it, and read it again in base64 for use.

这篇关于在Android上的React-Native中压缩base64编码的图像无法识别' data'协议的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆