Rasmus - I can certainly relate to your problem and may have found a solution. Hopefully the documentation can / will be updated to clarify the best approach as well. In my example below I am using React Native and react-native-image-picker. This is probably additional detail than you needed, but including everything in case it helps others.
Addressing the Specific Issue
If you want convert the image to base64, try the following:
Buffer.from(image.Body).toString('base64')
for anyone reading this and uncertain what ‘image.Body’ represents, it should be a buffer with the following form:
{"data": [23,4,5,6,...], "type": "Buffer"}
If you do this in javascript be sure to import the native dependency (no import required for Realm functions) via
import { Buffer } from 'buffer'
Image Upload
const [image, setImage] = useState(null)
const onPressUploadImage = async () => {
launchImageLibrary({
mediaType: 'photo',
maxWidth: 256,
maxHeight: 256,
selectionLimit: 1,
includeBase64: true
}, (response) => {
const imageToUpload = response.assets[0].base64
setImage(imageToUpload)
})
}
At this point, an image has been successfully saved to ‘image’ as base64. You can confirm this by rendering the following (note that defining the height and width is required):
<Image
style={{ height: 50, width: 50 }}
source={{ uri: `data:image/jpg;base64,${image}`}}
/>
You should be able to see your image was saved to a variable on the frontend. Knowing that is the case, I added a button to upload the image to aws s3. On press, I simply did the following:
const onPressSendToS3 = async () => {
try {
await user.functions.uploadImageToS3(image)
} catch (error) {
console.error(error)
}
Alright, so what is happening in our Realm function…
exports = async function(athleteId, image) {
const S3 = require('aws-sdk/clients/s3')
const s3 = new S3({
accessKeyId: context.values.get("AWS_ACCESS_KEY"),
secretAccessKey: context.values.get("AWS_SECRET_ACCESS_KEY_LINKED"),
region: "us-west-1",
});
const putResult = await s3.putObject({
Bucket: "bucketName",
Key: 'any image name',
ContentType: "image/jpeg",
Body: Buffer.from(image, 'base64') ,
ContentEncoding: 'base64'
}).promise();
}
A few comments on the function above (based on some issues I ran into / read about)
- You need to upload ‘aws-sdk’ as a dependency. The version needs to be v2 as v3 is not supported yet, I used 2.737.0 in this example.
- When accessing a secret, you must create the secret and then create another variable that links to the secret.
- The bucket name should match what is set up in s3 as a string.
- The key should be a string and can be custom, whatever you want to call the image.
- Buffer.from is built in and you do not need a dependency for this to work.
- ContentEncoding: this is required (I think after testing)
Fetch and View an Image
Including this as these issues are related for the most part. Create the following function in Realm.
exports = async function(picture) {
const S3 = require('aws-sdk/clients/s3')
const s3 = new S3({
accessKeyId: context.values.get("AWS_ACCESS_KEY"),
secretAccessKey: context.values.get("AWS_SECRET_ACCESS_KEY_LINKED"),
region: "us-west-1",
});
const getResult = await s3.getObject({
Bucket: "bucketName",
Key: picture,
}).promise();
const image = await JSON.parse(JSON.stringify(getResult))
return image
}
Then in React Native I did the following
const [picture, setPicture] = useState('picture key in AWS s3')
useEffect(() => {
async function fetchImage () {
try {
if (picture.length > 0) {
const image = await user.functions.getS3Image.picture)
const imageClean = Buffer.from(image.Body).toString('base64')
setPicture(imageClean)
}
} catch (error) {
console.error(error)
}
}
fetchImage()
}, [])
Lastly, to read the image
<ImageBackground
style={styles.activityImage}
source={{ uri: `data:image/jpeg;base64,${activityPicture}`}}
>
</ImageBackground>
Hope this helps and always welcome feedback. I am currently trying to find a way to enhance the speed of these functions, but at least this is a start!