NativeScript: ImageSourceModule method toBase64String not working (both iOS and Android)

On line 140 of image-source-android.js this.android.compress(targetFormat, quality, base64Stream); I’m getting this error this.android.compress is not a function. I’m using the nativescript-camera to take a picture and then save it to base64 string. Also, the image is saving to my photos even when I set saveToGallery: false.

Here my code:

cameraModule.takePicture({
        width: 1280, height: 720, keepAspectRatio: false, saveToGallery: false
    }).then(function (imageAsset) {
        console.log("Result is an image asset instance");
        viewModel.set("BoardingPassSource", imageAsset);
        var image = ImageSourceModule.fromNativeSource(imageAsset);
        var base64 = image.toBase64String("jpeg");
        // var image = new imageModule.Image();
        // image.imageSource = imageAsset;
        // image.toBase64String("jpeg");
        viewModel.set("base64String", base64);
    }).catch(function (err) {
        console.log("Error -> " + err.message);
    });

package.json

{
  "description": "NativeScript Application",
  "license": "SEE LICENSE IN <your-license-filename>",
  "readme": "NativeScript Application",
  "repository": "<fill-your-repository-here>",
  "nativescript": {
    "id": "org.nativescript.****",
    "tns-android": {
      "version": "2.5.0"
    }
  },
  "dependencies": {
    "nativescript-background-http": "^2.4.2",
    "nativescript-barcodescanner": "^2.3.3",
    "nativescript-camera": "0.0.8",
    "nativescript-drawingpad": "^1.1.2",
    "nativescript-drop-down": "^1.5.1",
    "nativescript-loading-indicator": "^2.2.2",
    "nativescript-telerik-ui": "^1.5.1",
    "nativescript-theme-core": "^1.0.2",
    "nativescript-timedatepicker": "^1.1.0",
    "tns-core-modules": "^2.5.0"
  },
  "devDependencies": {
    "babel-traverse": "6.21.0",
    "babel-types": "6.21.0",
    "babylon": "6.14.1",
    "lazy": "1.0.11"
  }
}

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 25 (9 by maintainers)

Most upvoted comments

I found another alternative!

cameraModule.takePicture({\
        width: 1280, height: 720, keepAspectRatio: false, saveToGallery: false
    }).then(function (imageAsset) {
        imageAsset.getImageAsync(function (res){
            console.log(res);
            viewModel.set("BoardingPassSource", imageSource); 
            var image = ImageSourceModule.fromNativeSource(imageSource);
            viewModel.set("base64String", image.toBase64String('png'));
            // var stream;
            // var comp = image.android.compress("png", 70, stream);
            console.log("image selected"); 
        });
    }).catch(function (err) {
        console.log("Error -> " + err.message);
    });    

now I want to find a way to compress the ImageAsset or the ImageSource. Any suggestions? @pap5508 @NickIliev

I used the nativescript-camera and nativescript-imagepicker to take a picture, save it and convert it to base 64. I hope it helps. If anyone has another workaround please let me know.

    // nativescript-camera
    cameraModule.requestPermissions();
    cameraModule.takePicture({
        width: 1280, height: 720, keepAspectRatio: false, saveToGallery: true
    }).then(function (imageAsset) {
        console.log("Result is an image asset instance");
 
        var context = imagepicker.create({
            mode: "single"
        });
    
        context
        .authorize()
        .then(function() {
            return context.present();
        })
        .then(function(selection) {
            console.log("Selection done:");
            selection.forEach(function(selected) {
                selected.getImage().then(res =>{
                    var d = new Date();
                    _photoDateTime = d.getFullYear()+"-"+(d.getMonth()+1)+"-"+d.getDate()+" "+
                                     d.getHours()+":"+d.getMinutes()+":"+d.getSeconds();
                    viewModel.set("PhotoDateTime", _photoDateTime);

                    viewModel.set("BoardingPassSource", res); 
                    viewModel.set("base64String", res.toBase64String("png"));
                    console.log("image selected");                    
                });
            });
        }).catch(function (e) {
            console.log(e);
        });
        
    }).catch(function (err) {
        console.log("Error -> " + err.message);
    });

Hello @emmanuel128, @pap5508 and All,

The API could be misleading here and as @emmanuel128 suggested, the proper way to implement this is as follow:

cameraModule.takePicture({
        width: 1280, height: 720, keepAspectRatio: false, saveToGallery: false
    }).then(function (imageAsset) {
        console.log("Result is an image asset instance");
        viewModel.set("BoardingPassSource", imageAsset);
        imageAsset.getImageAsync(image => {
            let imageSource = ImageSourceModule.fromNativeSource(image);
            let encodedString = imageSource.toBase64String("jpeg");
            console.log(encodedString);
        })
    }).catch(function (err) {
        console.log("Error -> " + err.message);
    });

I opened https://github.com/NativeScript/NativeScript/pull/5273 in order to throw if the source is not a correct native instance. A sample application could be found here.

@emmanuel128 Where is viewModel defined?

Thanks! My problem ended up being that I wasnt passing an acceptable image object. I was trying to derive the native source from a Web Image object from this plugin: https://www.npmjs.com/package/nativescript-web-image-cache but couldnt figure it out. So I got the image source from the URL. More on that here: https://discourse.nativescript.org/t/how-to-save-an-imagesource-object-to-the-devices-photo-library-on-both-ios-and-android/1126