I want to use camera and sent to data to api. Help me please ionic 5

How to coding camera ionic 5 and send picture to api?

I’ve written a simple Ionic images guide on that topic.

Capturing an image as as easy as calling the according plugin with some options:

var options: CameraOptions = {
        quality: 100,
        sourceType: sourceType,
        saveToPhotoAlbum: false,
        correctOrientation: true
    };
 
    this.camera.getPicture(options).then(imagePath => {
      // Handle the image result
    })

For the upload you can read the file and convert it to a blob:

readFile(file: any) {
    const reader = new FileReader();
    reader.onload = () => {
        const formData = new FormData();
        const imgBlob = new Blob([reader.result], {
            type: file.type
        });
        formData.append('file', imgBlob, file.name);
        this.uploadImageData(formData);
    };
    reader.readAsArrayBuffer(file);
}

Then you simply attach the formdata to a request like:

this.http.post("http://localhost:8888/upload.php", formData)

Native: tried calling Camera.getPicture, but Cordova is not available. Make sure to include cordova.js or run in a device/simulator


and when Click TakePhoto

ERROR Error: Uncaught (in promise): cordova_not_available

image

kindly post code and not images so as to improve the search capability of your post. Its availability in results may help someone in the future facing the same issue.

2 Likes

How to write? Please…

The resolution to your error is right there in the console… and its also mentioned in the post by Simon
@saimon , thanks for the youtube tutes they’ve proven to be very helpful.

1 Like

I don’ understand. I practice writing.

Kindly take sometime and go through the messages sent to you by discobot they take you through all the basics to enable you to use this forum effectively

Can you write code for using the camera for me to see? For example

Kindly test in real device

Still if you are getting same error then
Delete platforms,
Delete plugins folder

ionic cordova platform add android@latest && ionic cordova build android

Can i test in browser?

Read the comment and the post

Don’t just copy paste … go through it and understand the process, do some research on cordova plugins, how they help to access native api plus what you can do on browser / emulator or real device.

2 Likes

Hey there! Are you trying to test the plugin on a desktop browser like chrome or firefox? If so I dont believe it will work for you…the plugin needs a “cordova” environment/platform to work properly… you then have a couple of options… test in a emulator or test in a real device… if you are using capacitor for plugin handling just execute “ng build” first and after it “ionic capacitor run android”… if you want to do the same thing on a desktop computer or laptop… then you can use navigator.getUserMedia which is pretty simple to use to get video, capture image from camera…blah blah blah… if you need any example let me know…

OK, I want to know example.

Hi sorry for not posting before. I have been a little bit busy. Ok so some notes before you use this code:

  1. this code is using angular. I have not tested it in react but probably the same maybe some minor changes.

  2. I added a function for you to test:

  • save image to desktop/mobile: (mobile when using the browser. also have not test but i believe you should have no problem with major mobile browsers…)
  • send image to api: this is a example of a typical post to an api. please modify to how your api handle file uploading because I cannot write exact code due to I dont know which api you are using.
  1. Please add the HttClientModule to app.module.ts.(I added the code here but if you dont want to copy that part just add this to the imports in app.module.ts All the code is explained step by step. Let me know if you need anything else.

PS: this also works with native app (Android only for the moment because getUserMedia cannot be accesed in IOS outside the safari browser. :frowning_face: due to apple restrictions) but you need to make some tweaks to angular and add some additional modules but it definitely works ( I am currently implementing something with ionic+angular+tensorflowjs to predict objects in live video + web workers for smooth rendering).

HOME.PAGE.HTML:

<ion-header [translucent]="true">
  <ion-toolbar>
    <ion-title>
      Blank
    </ion-title>
  </ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
  <ion-header collapse="condense">
    <ion-toolbar>
      <ion-title size="large">Desktop Camera Test</ion-title>
    </ion-toolbar>
  </ion-header>
  <ion-grid>
    <ion-row class="ion-text-center">
      <ion-col size="6" offset="3">
           <ion-text color="primary" style="font-size: 20px;">Status: {{status}}</ion-text>
      </ion-col>
    </ion-row>
    <ion-row class="ion-text-center">
      <ion-col size="6" offset="3">
        <ion-card>
          <ion-card-title>
          Api Endpoint Url
          </ion-card-title>
          <ion-card-subtitle>
          Please add your api url or use the default
          </ion-card-subtitle>
          <ion-card-content>
            <ion-item>
              <ion-label>URL</ion-label>
              <ion-input [(ngModel)]="defaultApiUrl"></ion-input>
            </ion-item>
          </ion-card-content>
        </ion-card>
      </ion-col>
    </ion-row>
    <ion-row class="ion-text-center">
      <ion-col size="6" offset="3">
        <ion-col size="2" offset="1">
          <ion-button color="primary" (click)="saveToDesktop($event)" #desktopButton>Take picture and
            save to
            desktop</ion-button>
        </ion-col>
         <ion-col size="2" offset="1">
          <ion-button color="primary" (click)="sendToApi()">Take picture and send to api</ion-button>
        </ion-col>
      </ion-col>
    </ion-row>
    <ion-row class="ion-text-center">
      <ion-col>
        <video #videoPreview width="{{videoElementWidth}}" height="{{videoElementHeight}}"></video>
      </ion-col>
    </ion-row>
  </ion-grid>
</ion-content>

HOME.PAGE.TS

import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage implements AfterViewInit{
  // Just to display current status
  status = 'Initializing...';

  // We need to have a reference to the video tag in order to display the media stream on it
  @ViewChild('videoPreview', {static: false }) videoElement: ElementRef;

  // Since our reference is of type ElementRef, we can optionally create a variable to hold a HtmlVideoElement.
  // this is optional you could access directly later in code but will lack of auto-completion. For explanation we will put it here. 
  videoNativeElement: HTMLVideoElement;

  // video display resolution. Note this is only for displaying purposes, how "big or small" you want to display the
  // preview but this is not the resolution of the camera. As you will see bellow in the constraint in the video
  // property you can set width and height but those parameters are for searching a "video source/stream" with that
  // dimensions.
// Try to be equal or below your camera resolution. You can go up but then your image will start losing definition.
  videoElementWidth = 800;
  videoElementHeight = 600;

  // Enter your api url here
  defaultApiUrl = 'http://www.myapicustomserver.com/api/';

  // What type of image do you wish to download or send?
  imageType = 'image/jpeg';

  // Specify the file name for downloading. Be sure to match the image type.You can also modify this with custom
  // code but for example purpose this is ok.
  fileName = 'myImage.jpeg';

  // MediaStreamConstraints
  // to specify what kinds of tracks should be included in the returned MediaStream, and, optionally,
  // to establish constraints for those tracks' settings.
  // https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints
  // facingMode: 'environment' = The video source is facing away from the user, thereby viewing their environment. This
  // is the back camera on a smartphone. you can also use 'user','left','right'. If you need to access a specific device
  // you should use facingMode: {exact: deviceIdHere} but for this example we will not use it.
  constraints: MediaStreamConstraints = {
    audio: false,
    video: {
      facingMode: 'environment',
    }
  };

  constructor(private http: HttpClient) {}

  // We define video html element in here because the page is completely rendered at this point and we know for sure
  // video element exist.
  ngAfterViewInit() {
        this.videoNativeElement = this.videoElement.nativeElement;
        this.setCameraPreview();
    }

  // If you have any doubt using async await let me know but its pretty simple.Its an alternative for using
  // then(), catch(), finalize()....
  async setCameraPreview() {
    this.status = 'setting video stream';
    try {
      const mediaStream: MediaStream = await navigator.mediaDevices.getUserMedia(this.constraints);
      // if we do not set the videoNativeElement variable we need to access like this:
      // this.videoElement.nativeElement.srcObject
      this.videoNativeElement.srcObject = mediaStream;

      // The loadedmetadata event occurs when metadata for the specified audio/video has been loaded.
      // Metadata for audio/video consists of: duration, dimensions (video only) and text tracks.
      // https://www.w3schools.com/tags/av_event_loadedmetadata.asp
      // using a arrow function here
      this.videoNativeElement.onloadeddata = (e) => {
        // now we can star playing the camera;
        this.videoNativeElement.play();
      };
      this.status = 'stream ready';
    } catch (e) {
      this.status = 'Error: ' + e;
    }
  }

  saveToDesktop(e: MouseEvent) {
    this.status = 'taking picture';
    // prevent button default behaviour
    e.preventDefault();
    // first we get a url of the current frame generated by our canvas
    const url = this.takeSnapshot();
    // now we create a anchor element, set its href and simulate a click to download 
    const link = document.createElement('a');
    link.download = 'myImage.jpeg';
    link.href = url;
    link.click();
    this.status = 'Picture captured. ready to get another one.';
  }

  takeSnapshot(): string {
    // we will create a canvas element temporarily to draw the current video frame in it.
    const canvas = document.createElement('canvas');
    // we set the canvas width and height the same as video element width and height.
    canvas.width = this.videoNativeElement.videoWidth;
    canvas.height = this.videoNativeElement.videoHeight;
    // now we get a context to draw in it
    const ctx = canvas.getContext('2d');
    // now we draw the video element and we want to start in the top left corner of the canvas so we start in dx = 0
    // and dy = 0 . Also the dimensions to draw will be our element width and height. d stands for destionation. Our
    // canvas is our destination, and our source is of course the video element. Note: the width and height used in
    // here are the ones from the mediaStream(resolution of the camera) and not out display width and height. if you
    // want to resize the image we should do a little bit more before generating the url but for now we will leave
    // it like this.
    ctx.drawImage(this.videoNativeElement, 0, 0);
    return canvas.toDataURL(this.imageType);

  }

  sendToApi() {
    // Note this function will depend totally of how your api handle file uploading. please modify to your need but
    // this is a example implementation because I dont know how your api process file uploading. Do not forget to
    // add HttClientModule in app.module.ts
    // we take the snapshot. remember this is a bas64 image url
    const url = this.takeSnapshot();
    // we now create a form data to send the file to our api. this totally depends on how your api handle file
    // upload. it can be through a json variable, form-data..... please check that and modify this function
    // according to your api., because I do not know your api endpoint at this moment.
    const formData = new FormData();
    // now we append our image to the form-data. this.fileName used to define our file name that will be uploade. you
    // can change it to whatever you want: i.e: myCustomFile_31_8_20....
    formData.append( this.fileName, url);
    // Now our custom headers for the post method we will use.
    let customHeaders = new HttpHeaders();
    customHeaders = customHeaders.set('Accept', 'application/json').set('Content-Type', 'multipart/form-data');
    // generally when uploading file you need a authorization token, which may be a token generated for the user to
    // access the server... but this totally depends on your api so will comment it for now.
    // .set('Authorization' , 'Bearer ' + 'YOUR_TOKEN_HERE');
    // now we send the data to our api and process it there
    this.http.post(this.defaultApiUrl, formData,{headers: customHeaders}).subscribe(response => {
      // for now we will console log the response from the server. in here you can do whatever you wish.
      console.log(response);
    });
  }
}

APP.MODULE.TS:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';

import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import {HttpClientModule} from '@angular/common/http';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule, HttpClientModule],
  providers: [
    StatusBar,
    SplashScreen,
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

@Pirstscart did this help? any questions?

I test on emulator but It talk me about ‘Class not found’