Gregor Srdic
Gregor Srdic

Reputation: 446

Ionic Capacitor cordova plugin unable to write image to library on Android

I am trying to use cordova-plugin-document-scanner with Ionic Capacitor for Android, but after the image is captured and when image crop UI should be displayed, it just returns to the capture screen again. This is the issue on the github repo. This is what seems relevant in the logcat console:

2020-08-03 13:26:05.320 27707-27707/si.test.app D/ViewRootImpl@9f2e8cd[ScanActivity]: Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)4 dur=8 res=0x1 s={false 0} ch=false 2020-08-03 13:26:05.321 27707-27707/si.test.app D/ViewRootImpl@9f2e8cd[ScanActivity]: stopped(false) old=true 2020-08-03 13:26:05.328 27707-27707/si.test.app W/System.err: java.io.FileNotFoundException: open failed: ENOENT (No such file or directory)

2020-08-03 13:42:50.749 1278-1278/? E/Util: writeImageDataToRequestedUri : failed to make directory or the directory already existed.

2020-08-03 13:42:50.760 1278-1278/? E/Util: writeImageDataToRequestedUri : Returned because outputStream IOException.

This is my configuration:

Is it possible, that Cordova and Capacitor have different paths to files on the device? Where could I fix that? Any help greatly appriciated :)

Upvotes: 0

Views: 1880

Answers (1)

Janitha Rasanga
Janitha Rasanga

Reputation: 1126

I implemented this in my project using Ionic 5 and Capacitor. It is long code. Try this and maybe help you.

Install this npms

npm install cordova-plugin-crop
npm install @ionic-native/crop

npm install cordova-plugin-ionic-webview
npm install @ionic-native/ionic-webview

Then create service file. ex: photo.service

Then add below code according to your case. I added my full code to here because it include all things.

There are two method.

getImageCam() - get image from camera > source: CameraSource.Camera

getImageGall() - get image from gallery > source: CameraSource.Photos

import { Injectable } from "@angular/core";
import {
  Plugins,
  CameraResultType,
  CameraPhoto,
  CameraSource,
} from "@capacitor/core";
import { Crop } from "@ionic-native/crop/ngx";
import { WebView } from "@ionic-native/ionic-webview/ngx";
//import { File } from "@ionic-native/file/ngx";

const { Camera, Filesystem, Storage } = Plugins;

@Injectable({
  providedIn: "root",
})
export class PhotoService {
  newCapturedImg: any = null;
  ImgNameStart: any = "yourName";
  formDataImage: any;
  cropImage: CameraPhoto;

  constructor(private crop: Crop, private webview: WebView) {}

  public async getImageCam() {
    // Take a photo
    const capturedPhoto = await Camera.getPhoto({
      resultType: CameraResultType.Uri,
      source: CameraSource.Camera,
      quality: 100,
      // allowEditing: true,
      // height: 300,
      // width: 300
    });

    console.log(capturedPhoto);

    this.crop
      .crop(capturedPhoto.path, {
        quality: 100,
      })
      .then(
        (newImage) => {
          this.newCapturedImg = this.webview.convertFileSrc(newImage);

          //console.log("new image path is: " + newImage);
          //console.log("new image webpath is: " + this.newCapturedImg);

          this.cropImage = {
            path: newImage,
            webPath: this.newCapturedImg,
            format: "jpeg",
          };

          const savedImageFile =  this.savePicture(this.cropImage);
        },
        (error) => console.error("Error cropping image", error)
      );
  }

  public async getImageGall() {
    // Take a photo
    const capturedPhoto = await Camera.getPhoto({
      resultType: CameraResultType.Uri,
      source: CameraSource.Photos,
      quality: 100,
      // allowEditing: true,
      // height: 300,
      // width: 300,
    });

    this.crop
      .crop(capturedPhoto.path, {
        quality: 100,
      })
      .then(
        (newImage) => {
          this.newCapturedImg = this.webview.convertFileSrc(newImage);

          //console.log("new image path is: " + newImage);
          //console.log(this.newCapturedImg);

          this.cropImage = {
            path: newImage,
            webPath: this.newCapturedImg,
            format: "jpeg",
          };

          const savedImageFile = this.savePicture(this.cropImage);
        },
        (error) => console.error("Error cropping image", error)
      );

  }    


  private async savePicture(cameraPhoto: CameraPhoto) {
    const blobData = await this.readABlob(cameraPhoto);
    this.formDataImage = blobData;
  }

  private async readABlob(cameraPhoto: CameraPhoto) {
    const response = await fetch(cameraPhoto.webPath!);
    const blob = await response.blob();
    console.log("blob --> ", blob);
    return blob;
  }


  createFileName() {
    let d = new Date();
    let n = d.getTime();
    let newFileName = `${this.ImgNameStart + n}.jpg`;
    return newFileName;
  }
}

interface Photo {
  filepath: string;
  webviewPath: string;
  base64?: string;
}

You can access service variable like this from any component.

example.page.ts

import { PhotoService } from "../../services/photo.service";

...

  constructor(public photoService: PhotoService) {}

...

yourMethod() {
  this.photoService.getImageCam() // or getImageGall()


  let formDataImage = this.photoService.formDataImage;
  let imageName = this.photoService.createFileName();
  let urlToImageSrc = this.photoService.newCapturedImg;
}

Upvotes: 1

Related Questions