11

I'm doing some image manipulation on ios on react-native.

The problem is one of the libraries I'm using only supports absolute paths, but I only have the file-asset uri.

Example

I have:

assets-library://asset/asset.HEIC?id=CE542E92-B1FF-42DC-BD89-D61BB70EB4BF&ext=HEIC

I need:

file:///Users/USERNAME/Library/Developer/CoreSimulator/Devices/########-####-####-####-############/data/Containers/Data/Application/########-####-####-####-############/Documents/########-####-####-####-############.jpg

Is there any way to easily get the image absolute path?

Oscar Franco
  • 5,691
  • 5
  • 34
  • 56

4 Answers4

4

This is what I ended up doing, based on @ospfranco's answer. I saved a copy of the asset on the temp folder. Also included a little snippet to generate a random string for the file name.

import RNFS from 'react-native-fs';

getAssetFileAbsolutePath = async (assetPath) => {
    const dest = `${RNFS.TemporaryDirectoryPath}${Math.random().toString(36).substring(7)}.jpg`;

    try {
      let absolutePath = await RNFS.copyAssetsFileIOS(assetPath, dest, 0, 0);
      console.log(absolutePath)
    } catch(err) {
      console.log(err)
    } 
  }
Brunno Vodola Martins
  • 1,582
  • 2
  • 15
  • 17
2

So, the reason why you only get an url is because it image might not be stored on the device (it could be on iCloud). iOS silently downloads the asset for you once you do any operation on it.

That will not help you if you are really trying to manipulate the image from your react-native code though, so here is one workaround:

import RNFS from 'react-native-fs';

getAssetFileAbsolutePath = async (assetPath) => {
    const dest = `${RNFS.TemporaryDirectoryPath}${Math.random().toString(36).substring(7)}.jpg`;

    try {
      let absolutePath = await RNFS.copyAssetsFileIOS(assetPath, dest, 0, 0);
    } catch(err) {
      // ...
    } 
  }

Bare in mind this copies the file to a temporary directory which means it is not permanent, you can also copy it to your application's document directory.

Oscar Franco
  • 5,691
  • 5
  • 34
  • 56
  • Did u find any other way to do so or did you stick on using `copyFileAssetsIOS`? – ZedTuX Jul 17 '18 at 11:42
  • 1
    Nope, there doesn't seem to be a way to do (easily/with a library) it from the react-native side, only from native code. – Oscar Franco Jul 18 '18 at 14:20
  • 2
    Just a minor correction, it's called `copyAssetsFileIOS`: https://github.com/itinance/react-native-fs#copyassetsfileiosimageuri-string-destpath-string-width-number-height-number-scale--number--10-compression--number--10-resizemode--string--contain---promisestring – Brunno Vodola Martins Nov 04 '18 at 17:37
2

I got it to work using RNFS, but I had to add a little 'extra' to the uri path to get it to work.

<TouchableHighlight
          onPress={async () => {
            const destPath = RNFS.CachesDirectoryPath + '/MyPic.jpg';

            try {
              await RNFS.copyAssetsFileIOS(imageUri, destPath, 0, 0);
              console.log('destPath', destPath);
            } catch (error) {
              console.log(error);
            }

            navigation.navigate('SelectedPicture', {
              uri: 'file://' + destPath,
            });
          }}>
          <Image source={{uri: imageUri}} style={styles.image} />
        </TouchableHighlight>
Shah
  • 2,126
  • 1
  • 16
  • 21
1

The question is old but i answer it to help people like me, new in react-native, having the same issue. i were struggling with it trying to get the images from the cameraroll and process them with an OCR library. I was using react-native-photo-framework to get the images and i found that you can get fileurl using the method getImageMetadata with the assets. I need this fileurl because the original URI that has the format 'photo://...' wasn't being recognized as a valid URL for the OCR Library. I haven´t tested it with real devices and with iCloud assets yet. Example:

const statusObj = await RNPhotosFramework.requestAuthorization()
if (statusObj.isAuthorized) {
    const assetList = await RNPhotosFramework.getAssets({
      includeMetadata: true,
      includeResourcesMetadata: true,
      fetchOptions: {
        mediaTypes: ['image'],
        sourceTypes: ['userLibrary', 'cloudShared', 'itunesSynced'],
      }
    })
    const asset = photos.assets[0]
    const metadata = await asset.getImageMetadata()
    const uri = metadata.imageMetadata.fileUrl
}
Makx
  • 21
  • 6