Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Base64 encoding/decoding #1158

Closed
michalraska opened this issue May 5, 2015 · 25 comments
Closed

Base64 encoding/decoding #1158

michalraska opened this issue May 5, 2015 · 25 comments
Labels
Resolution: Locked This issue was locked by the bot.

Comments

@michalraska
Copy link

Hi,
is there some module for base64 encoding/decoding which works well with react native?
Thank you.

@nicklockwood
Copy link
Contributor

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).

@xiekw2010
Copy link

@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

@starquake
Copy link

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.

@starquake
Copy link

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

@avishayil
Copy link

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?

@nicklockwood
Copy link
Contributor

@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.

@avishayil
Copy link

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.

@nicklockwood
Copy link
Contributor

@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.

@nicklockwood
Copy link
Contributor

@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.

@avishayil
Copy link

@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?

@nicklockwood
Copy link
Contributor

@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.

@avishayil
Copy link

@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?

@nicklockwood
Copy link
Contributor

@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.

@avishayil
Copy link

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.

@daesan
Copy link
Contributor

daesan commented Feb 23, 2016

@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.

@nicklockwood
Copy link
Contributor

@daesan ah, good point. I know why that's happening - I'll put up a fix.

@lananelson
Copy link

@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>

@nicklockwood
Copy link
Contributor

@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'}}/>

@lananelson
Copy link

oh thats great! thanks @nicklockwood

@nicklockwood
Copy link
Contributor

@daesan FYI, the alpha/png issue should be fixed now.

@daesan
Copy link
Contributor

daesan commented Mar 18, 2016

@nicklockwood That's great! Thanks for letting me know.

@felipembbraga
Copy link

felipembbraga commented Jul 22, 2016

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.

@semiautomatix
Copy link

Also having an issue displaying base64 images in Android 6.

@perrosnk
Copy link

@nicklockwood Could you please help me with this issue #12114 ? I followed your steps but I am getting an error

@gengjiawen
Copy link
Contributor

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'));

@facebook facebook locked as resolved and limited conversation to collaborators May 29, 2018
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Jul 22, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

No branches or pull requests