Hi,
is there some module for base64 encoding/decoding which works well with react native?
Thank you.
If you just want to encode data on the JS side, you should just be able to pull in any 3rd party base64 module (here's one: https://github.com/dankogai/js-base64).
@nicklockwood I use npm i js-base64 --save to include this to my react-native project.
but the redbox tells unable to resolve module from .../node_modules/js-base64/base64.js
This piece of code in js-base64 triggers the error:
// if node.js, we use Buffer
var buffer;
if (typeof module !== 'undefined' && module.exports) {
try {
buffer = require('buffer').Buffer;
} catch (err) {}
}
The error doesn't get catched. Don't know if this is a bug of React.
Buffer seems to be working: (just tested it)
https://www.npmjs.com/package/buffer
See here on how to use it:
http://www.hacksparrow.com/base64-encoding-decoding-in-node-js.html
I also successfully used this one:
https://www.npmjs.com/package/base-64
Hi,
How do you get an image from the web ('i.e http://www.example.com/img.png') and convert it to base64 string on JS?
@avishayil The short answer is that you probably shouldn't :-)
The longer answer is that you could do it on iOS as follows:
1) Use Image.getSize(uri) to get the image dimensions.
2) Use ImageEditor.cropImage(uri, cropData) to store a copy of the image in the ImageStore (if you pass the width and height you got in step 1) then cropImage won't actually crop the image, although it may still make a copy of it.
3) Use ImageStore.getBase64ForTag(uri) to get the base64 data of the new image (pass the uri you got from the cropImage function, not the original).
4) Don't forget to call ImageStore.removeImageForTag(uri) once you're done to delete the copy.
That may seem cumbersome, and it is, but that's because we generally don't encourage converting images to base64 data. If you can explain what you're trying to do, there might be a better approach, or we might be able to create a better API for it.
Hi Nick, thanks for the answer.
I'm building a reader app, and my current efforts are making article available for reading offline.
Currently, i'm building the list of articles with the preview images. I'm using AsyncStorage to store all the article details offline, then fetch them when needed.
async handleAddFavourite(article) {
AsyncStorage.getItem(FAV).then(function(value) {
if (value !== null) {
value = JSON.parse(value);
index = value.map(function(e) { return e.id; }).indexOf(article.id);
if (index > -1) {
console.log('exists');
} else {
try {
// article['base64_image'] = base64.encode(article.image); --> HERE THE BASE64 NEEDED
value.push(article);
AsyncStorage.setItem(FAV, JSON.stringify(value));
console.log('Saved selection to disk: ' + value);
} catch (error) {
console.log('AsyncStorage error: ' + error.message);
}
}
} else {
value = [];
try {
value.push(article);
AsyncStorage.setItem(FAV, JSON.stringify(value));
console.log('Saved selection to disk: ' + value);
} catch (error) {
console.log('AsyncStorage error: ' + error.message);
}
}
});
};
One option that I had, is to do the base64 encoding on the server, but it turns out to be 'costly' operation for the API. That's why I'm trying to do it on the client side.
@avishayil gotcha. The problem with that is obviously that you're sending the image data from native to JS (as base64 strings) and then back again via AsyncStorage, which is hugely wasteful.
The problem is that we don't currently have an API for saving uris directly to the file system on the native side without transferring the data to and from JS.
I've been thinking about ways we might be able to expose such an API. I'll keep doing so :-)
For your particular use case, your best solution right now would be to implement the archiving entirely on the native side with a custom module. But I can understand why you might not want to do that.
@avishayil FWIW, we cache images to disk once they are downloaded, so you could probably get away with just saving the image url in asyncstorage (rather than the image data), because it should be possible to view the image url offline after the first time it's been loaded.
The only problem is that this will be slightly nondeterministic - the image cache size is limited, so the images may get evicted to make room, and we don't expose any controls for the cache size, etc.
@nicklockwood How would I do that? currently i'm fetching the images using the Image component. Do I have a way to access the cached image afterwards?
@avishayil you don't have to do anything special. The first time you load a uri in an <Image> it's downloaded and cached. The second time you display it, it's loaded from the cache, even if the app has been closed in the meantime.
@nicklockwood Indeed, awesome! do you know if it's cached permanently (until user is clearing data, of course). Can I count on it for offline storage?
@avishayil there are no guarantees I'm afraid. The OS is free to clear the cache if the device is low on space, and we limit the cache size (to 200MB IIRC), so if you download more than that, the new images will evict the old ones.
I can't believe it would come to that sizes, but it's good to know. Anyway, if you have a better, stable solution i'd be glad to know about it.
@nicklockwood Thanks for telling us how to use ImageEditor.cropImage!
I am using it to resize images before uploading them to the server. However, I noticed that the uploaded images are saved in PNG format, not JPEG format as the original image.
It seems to have something to do with cropped/resized image getting alpha channel which causes later logic to think it should be in PNG format.
@daesan ah, good point. I know why that's happening - I'll put up a fix.
@nicklockwood I got exactly the same exact use case here trying to save images locally for offline viewing. Correct me if I am wrong but it seems to me that even if I save images with native module to local file system I still won't be able to render them with <Image>
@Iananelson wrong; as long as you can have a uri for the image, you can display it. That works with file:// type uris as well as remote ones, and you can use relative uris for files saved locally, e.g:
<Image source={{uri: '~/Library/Caches/someimage.png'}}/>
oh thats great! thanks @nicklockwood
@daesan FYI, the alpha/png issue should be fixed now.
@nicklockwood That's great! Thanks for letting me know.
How can I do the reverse process? How do I create a image file from the string base64? I have a very specific problem and I don't know how to fix it. In some Motorola devices, like Moto G (2015) and Moto X (2015), the image does not appear when I use source={{ uri: base64string }}. Theses devices use Android 6, but it works on emulator using Android 6. I have a Moto g 1st, running on Android 5, and works too, only in the cases cited above that this problem happens. I think the way to solve this is to save a cache image and show it, but I have no idea to do this.
Update
Well, I don't know really if this problem occurs only in theses cases specifically or in general devices running on android 6.
Also having an issue displaying base64 images in Android 6.
@nicklockwood Could you please help me with this issue #12114 ? I followed your steps but I am getting an error
Normal base64 for react native from https://stackoverflow.com/a/47925467/1713757
yarn add buffer
Usage
console.log(Buffer.from("Hello World").toString('base64'));
console.log(Buffer.from("SGVsbG8gV29ybGQ=", 'base64').toString('ascii'));
Most helpful comment
@avishayil The short answer is that you probably shouldn't :-)
The longer answer is that you could do it on iOS as follows:
1) Use Image.getSize(uri) to get the image dimensions.
2) Use ImageEditor.cropImage(uri, cropData) to store a copy of the image in the ImageStore (if you pass the width and height you got in step 1) then cropImage won't actually crop the image, although it may still make a copy of it.
3) Use ImageStore.getBase64ForTag(uri) to get the base64 data of the new image (pass the uri you got from the cropImage function, not the original).
4) Don't forget to call ImageStore.removeImageForTag(uri) once you're done to delete the copy.
That may seem cumbersome, and it is, but that's because we generally don't encourage converting images to base64 data. If you can explain what you're trying to do, there might be a better approach, or we might be able to create a better API for it.