How do I store an image locally, then display the image?

  1. SDK Version: “expo”: “~39.0.2”,
  2. Platforms(Android/iOS/web/all): Testing on iphone

I am trying to take an image from the image picker, save it locally (within the app, db, or filesystem, not in the camera roll.) Then load that image in an component. I have tinkered around a good bit without success. Here is a stackoverflow question I posted asking for help some time ago.

Most recently I have been trying to debug by making a dummy app with only that functionality.

Here is some code from that app.

app.js

import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import ImagePickerExample from './image-picker'

export default function App() {
  return (
    <View style={styles.container}>
      <Text>Open up App.js to start working on your app!</Text>
      <StatusBar style="auto" />
      <ImagePickerExample></ImagePickerExample>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

image-picker.js

import React, { useState, useEffect } from 'react';
import { Button, Image, View, Platform } from 'react-native';
import * as ImagePicker from 'expo-image-picker';
import Constants from 'expo-constants';
import * as FileSystem from 'expo-file-system';


const imgDir = FileSystem.documentDirectory + 'images/';


async function ensureDirExists() {
    const dirInfo = await FileSystem.getInfoAsync(imgDir)
    if (!dirInfo.exists) {
      console.log('Gif directory doesn\'t exist, creating...');
      await FileSystem.makeDirectoryAsync(imgDir, { intermediates: true });
    }
  }
  ensureDirExists();

export default function ImagePickerExample() {
  const [image, setImage] = useState(null);

  useEffect(() => {
    (async () => {
      if (Platform.OS !== 'web') {
        const { status } = await ImagePicker.requestCameraRollPermissionsAsync();
        if (status !== 'granted') {
          alert('Sorry, we need camera roll permissions to make this work!');
        }
      }
    })();
  }, []);

  const pickImage = async () => {
    let result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.All,
      allowsEditing: true,
      aspect: [4, 3],
      quality: 1,
      base64: true,
    });

    // console.log(result);

    if (!result.cancelled) {
    await FileSystem.writeAsStringAsync(
        imgDir + `image.png`,
        result.base64
        );
      setImage(result.uri);
    }
  };

  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button title="Pick an image from camera roll" onPress={pickImage} />
      {image && <Image source={{ uri: image }} style={{ width: 200, height: 200 }} />}
      {image && 
      <View style={{width: 100, height: 100, backgroundColor: 'blue'}}>
          <Image style={{width: 50, height: 50}} source={{uri:`data:image/png;base64,${imgDir+'image.png'}`}}/>
      </View>
          }
    </View>
  );
}

Most of it is from the example in the documentation. The result I get from this code appears to store the binary of the image as a file, but doesn’t successfully render it as the source of the image component.