Put picture on camera while taking a photo

Hello there! I am quite new to ionic and its native tools. I am wondering if there is a possibility to make an app where you first choose a picture, and then you get it as an overlay when taking a photo.

I am going to make an app where housebuilders can use a picture of a house as an overlay, and then take a picture of an spot where they would like to have the house. To see if they like it or not.
I need some guidance, dont know where and how to start.
Thanks in advance, i appreciate it!

Interesting problem.

I don’t know of a solution, but googled a bit: https://github.com/chrisweb/cordova_prototype - This project says that you can add ā€œstickersā€ to images. Check if this is on the live picture or on taken pictures.

1 Like

Viewing the picture as an overlay while still being able to use the camera is the hardest part here. Take a look at this tutorial:

2 Likes

It looked a bit outdated, but i will check it out! Thank you :slight_smile:

Im working on something related, so i actually went through it today.
CameraPreview has been updated and needed some changes, but nothing major.
The background hiding was poorly handled when you need a multipage app, but i solved it quite simply with ionViewWillLoad and ionViewWillLeave.

Tell me if you want the code

Some of the CLI commands have change a tiny little bit, too. But that shouldn’t be blocking you as the CLI will tell you about it.

Oh wow. Yeah, if you are okay with that I would like to see the code!
I like to see how other people make their apps. It gives me some inspiration!

Cheers!

I am trying this plugin right now, and it works like a charm. Although, when I store a picture with the takePicture method, it won’t take a picture of the overlay as well.
So I was thinking about using the screenshot plugin to ā€œtake a pictureā€, but the screen is now black.
Any tips perhaps?

You could takePicture and then place the the ā€œoverlayā€ at the same position manually.

1 Like

Sorry I couldnt get back to you, had a busy weekend. Glad it worked out!

Here is the code for only making the other pages of the app transparent when using the capture image app. I think it might come in handy.

scanpage.ts:

ionViewWillLoad(){
    document.getElementsByTagName('html')[0].style.visibility = 'hidden';
  }
  ionViewWillLeave(){
    document.getElementsByTagName('html')[0].style.visibility = 'visible';
  }

scanpage.scss:

.camera-content {
    background-color: transparent !important;
    visibility: visible;
  }
.card-title {
    position: absolute;
    top: 0%;
    width: 100%;
    height: 100%;
  }

i have been using canvas to rotate images, im guessing you can use it to draw one image on top of another as well, but im not too familiar with those kind of problems. Its also a bit slow (only tested on mobile).
This is the code for rotating an image 90 degrees and returning it as base64 encoded jpg string:

public rotateImgToBase64(img:string, clockwise:boolean):Promise<string>{
    return new Promise((resolve)=>{
      var canvas = document.createElement('canvas');
      var ctx = canvas.getContext("2d");

      var image = new Image();
      image.src = img
      image.onload = ()=> {
        canvas.width=image.height
        canvas.height=image.width

        if(clockwise){
          ctx.rotate(90 * Math.PI / 180);
          ctx.translate(0,-canvas.width);
        }else{
          ctx.rotate(-90 * Math.PI / 180);
          ctx.translate(-canvas.height, 0);
        }
        ctx.drawImage(image, 0, 0)

        resolve(canvas.toDataURL('image/jpeg', 100))
      };
    })
  }
2 Likes

I’m trying to get a similar app running and I’m having problems I can’t seem to solve. I’m hoping you guys can help me out.

My app consists of 2 pages with the sidemenu starter template. It’s very similar to the Ionic Go tutorial Josh posted.

Here’s my ionic info output

global packages:

    @ionic/cli-utils : 1.5.0
    Cordova CLI      : 7.0.1
    Ionic CLI        : 3.5.0

local packages:

    @ionic/app-scripts              : 2.0.1
    @ionic/cli-plugin-cordova       : 1.4.1
    @ionic/cli-plugin-ionic-angular : 1.3.2
    Cordova Platforms               : android 6.2.3 browser 4.1.0 ios 4.4.0
    Ionic Framework                 : ionic-angular 3.5.0

System:
    Node       : v6.9.2
    OS         : Windows 8.1
    Xcode      : not installed
    ios-deploy : not installed
    ios-sim    : not installed
    npm        : 3.10.9

My package.json:

{
    "name": "CameraTest",
    "version": "0.0.1",
    "author": "Ionic Framework",
    "homepage": "http://ionicframework.com/",
    "private": true,
    "scripts": {
        "clean": "ionic-app-scripts clean",
        "build": "ionic-app-scripts build",
        "lint": "ionic-app-scripts lint",
        "ionic:build": "ionic-app-scripts build",
        "ionic:serve": "ionic-app-scripts serve"
    },
    "dependencies": {
        "@angular/common": "4.1.3",
        "@angular/compiler": "4.1.3",
        "@angular/compiler-cli": "4.1.3",
        "@angular/core": "4.1.3",
        "@angular/forms": "4.1.3",
        "@angular/http": "4.1.3",
        "@angular/platform-browser": "4.1.3",
        "@angular/platform-browser-dynamic": "4.1.3",
        "@ionic-native/camera-preview": "^4.0.0",
        "@ionic-native/core": "3.12.1",
        "@ionic-native/splash-screen": "3.12.1",
        "@ionic-native/status-bar": "3.12.1",
        "@ionic/storage": "2.0.1",
        "cordova-android": "^6.2.3",
        "cordova-browser": "^4.1.0",
        "cordova-ios": "^4.4.0",
        "cordova-plugin-camera-preview": "^0.9.0",
        "cordova-plugin-console": "^1.0.5",
        "cordova-plugin-device": "^1.1.4",
        "cordova-plugin-splashscreen": "^4.0.3",
        "cordova-plugin-statusbar": "^2.2.2",
        "cordova-plugin-whitelist": "^1.3.1",
        "ionic-angular": "3.5.0",
        "ionic-plugin-keyboard": "^2.2.1",
        "ionicons": "3.0.0",
        "rxjs": "5.4.0",
        "sw-toolbox": "3.6.0",
        "zone.js": "0.8.12"
    },
    "devDependencies": {
        "@ionic/app-scripts": "2.0.1",
        "@ionic/cli-plugin-cordova": "1.4.1",
        "@ionic/cli-plugin-ionic-angular": "1.3.2",
        "typescript": "2.3.4"
    },
    "description": "An Ionic project",
    "cordova": {
        "plugins": {
            "cordova-plugin-camera-preview": {},
            "cordova-plugin-console": {},
            "cordova-plugin-device": {},
            "cordova-plugin-splashscreen": {},
            "cordova-plugin-statusbar": {},
            "cordova-plugin-whitelist": {},
            "ionic-plugin-keyboard": {}
        },
        "platforms": [
            "android",
            "browser",
            "ios"
        ]
    }
}

I’ve added this to my config.xml, as suggested in the Ionic Native docs for iOS 10+:

<config-file parent="NSCameraUsageDescription" platform="ios" target="*-Info.plist">
    <string>Allow the app to use your camera</string>
</config-file>

My HomePage has nothing special. My PreviewPage ts file:

import { HomePage } from './../home/home';
import { CameraPreview, CameraPreviewOptions } from '@ionic-native/camera-preview';

import { Component, OnInit } from '@angular/core';
import { NavController } from 'ionic-angular';

@Component({
  selector: 'page-preview',
  templateUrl: 'preview.html',
})
export class PreviewPage implements OnInit {

  constructor(public navCtrl: NavController, private cameraPreview: CameraPreview) {
    
  }

  ngOnInit(): void {

    const cameraPreviewOpts: CameraPreviewOptions = {
        x: 0,
        y: 0,
        width: window.screen.width,
        height: window.screen.height,
        camera: this.cameraPreview.CAMERA_DIRECTION.BACK,
        tapPhoto: false,
        previewDrag: false,
        toBack: true,
        alpha: 1
      };

      this.cameraPreview.startCamera(cameraPreviewOpts).then(
        (res) => {
          console.log("startCamera success", res);
        },
        (err) => {
          console.log("startCamera error", err)
      });

  }

  exit(){
    console.log("go home");
    this.navCtrl.setRoot(HomePage);
  }

  switchCamera(){
    this.cameraPreview.switchCamera();
  }

  ionViewWillLoad(){
    document.getElementsByTagName('html')[0].style.visibility = 'hidden';
  }

  ionViewWillLeave(){
    document.getElementsByTagName('html')[0].style.visibility = 'visible';
  }

}

I’ve imported CameraPreview to my app.module.ts:

import { CameraPreview } from '@ionic-native/camera-preview';
...
providers: [
    StatusBar,
    SplashScreen,
    CameraPreview,
  {provide: ErrorHandler, useClass: IonicErrorHandler}
  ]

So now when I test in the browser on my PC, there’s no camera so I don’t expect to see that but all the elements in the DOM have transparent backgrounds, plus @Gunnarkd’s suggestion to use the ionViewWillLoad/ionViewWillLeave sets the visibility on the html element.

I upload my app with ionic upload and test the app in the Ionic View app… and no camera preview. :frowning:

Does the CameraPreview just not work in Ionic View?

Any help would be appreciated! :slight_smile:

1 Like

Exactly, not one of the supported plugins: Ionic Docs - Ionic Documentation You will have to build the ap yourself.

1 Like

@Gunnarkd just wondering how many second between actually taking picture and seeing the preview image in your app?
I’m using the plugin and feels like it is slow 3-4 second? between taking a picture and seeing the preview with what i got.

Cheers
thanks in advance

A bit under a second on my Huawei mate S (midrange+ 2 years old). Maybe 1-2 seconds on the iphone 5 im using for testing.
Im saving the picture right away, and then using the Uri link to show the picture.

Code for saving the base64img:

File is just { File } from ā€˜@ionic-native/file’;
pictureDir is this.file.dataDirectory with a image folder I created.

b64toBlob(b64Data, contentType) {

    const bytes: string = atob(b64Data);
    const byteNumbers = new Array(bytes.length);
    for (let i = 0; i < bytes.length; i++) {
      byteNumbers[i] = bytes.charCodeAt(i);
    }
    const byteArray = new Uint8Array(byteNumbers);
    const blob: Blob = new Blob([byteArray], { type: contentType });

    return blob;
  }

public saveBase64Raw(base64raw:string, name:string):Promise<string>{
    return new Promise((resolve, reject)=>{

      let blob=this.b64toBlob(base64raw, 'image/jpeg')

      this.file.writeFile(this.pictureDir, name, blob)
      .then(()=>{
        resolve(this.pictureDir+name);
      })
      .catch((err)=>{
        console.log('error writing blob')
        reject(err)
      })

    })
  }
1 Like

@Gunnarkd can you do ionic info just wondering which versions are you using for some reason im getting 4-5 sec between taking pic and displaying, i used ine of the newest fork supposedly super fast. but for some reason its slow

1-2 seconds thats fast!!

global packages:

@ionic/cli-utils : 1.5.0
Cordova CLI      : 6.5.0 
Ionic CLI        : 3.5.0

local packages:

@ionic/app-scripts              : 1.3.8
@ionic/cli-plugin-cordova       : 1.4.1
@ionic/cli-plugin-ionic-angular : 1.3.2
Cordova Platforms               : android 6.1.2 ios 4.3.1
Ionic Framework                 : ionic-angular 3.4.2

System:

Node       : v6.9.4
OS         : macOS Sierra
Xcode      : Xcode 8.3.3 Build version 8E3004b 
ios-deploy : 1.9.1 
ios-sim    : 5.0.13 
npm        : 3.10.10

hi,i am working on something related project and all exams outdated Could you share your code with me? @Gunnarkd

My scanpage is opened in a ModalController, so im dismissing it after the picture is taken, but you can also cancel the image capture

code for opening the scanpage:

let modal = this.modalCtrl.create(NewScanPage);
modal.onDidDismiss(data =>{
   if(data.save) {
           //USE data.base64 HERE FOR WHAT YOU WANT
   }
   else {
     console.log("Cancel ScanModal");
   }
})
modal.present()

new-scan.html:

<ion-content class="camera-content">

    <ion-fab right top small>
        <button (click)="dismiss(false, '')" ion-fab color="light"><ion-icon name="exit"></ion-icon></button>
    </ion-fab>

    <ion-fab center bottom small>
        <button *ngIf="!capturingImage" (click)="takePicture()" ion-fab color="light"><ion-icon name="camera"></ion-icon></button>
    </ion-fab>

</ion-content>

new-scan.scss:

page-new-scan {
  .camera-content {
    background-color: transparent !important;
    visibility: visible;
  }
  .card-title {
    position: absolute;
    top: 0%;
    width: 100%;
    height: 100%;
  }
}

new-scan.ts:

import { Component } from '@angular/core';
import { NavController, NavParams, ViewController, LoadingController } from 'ionic-angular';

import { CameraPreview, CameraPreviewPictureOptions, CameraPreviewOptions, CameraPreviewDimensions } from '@ionic-native/camera-preview';

@Component({
  selector: 'page-new-scan',
  templateUrl: 'new-scan.html',
})
export class NewScanPage {


  capturingImage:boolean=false

  constructor(private cameraPreview: CameraPreview, public loadingCtrl:LoadingController, public viewCtrl: ViewController, public navCtrl: NavController, public navParams: NavParams) {


    const cameraPreviewOpts: CameraPreviewOptions = {
      x: 0,
      y: 0,
      width: window.screen.width,
      height: window.screen.height,
      camera: 'rear',
      tapPhoto: false,
      previewDrag: true,
      toBack: true,
      alpha: 1
    };

    this.cameraPreview.startCamera(cameraPreviewOpts)
    .then((data)=>{
      console.log(data)

      this.cameraPreview.setFocusMode('auto')
      .then((data)=>{
        console.log(data)
      })
      .catch((err)=>{
        console.log(JSON.stringify(err))
      })
    })
    .catch((err)=>{
      console.log(JSON.stringify(err))
    })

  }

  takePicture(){
    if(!this.capturingImage){
      this.capturingImage=true;
      const pictureOpts: CameraPreviewPictureOptions = {
        width: window.screen.width,
        height: window.screen.height,
        quality: 100
      }

      this.cameraPreview.takePicture(pictureOpts)
      .then((base64Raw)=>{
        this.cameraPreview.stopCamera()
        this.dismiss(true, base64Raw)

        this.capturingImage=false

      })
      .catch((err)=>{
        console.log('new-scan: error taking picture')
        this.capturingImage=false
      })
    }

  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad NewScanPage');
  }
  ionViewWillLoad(){
    document.getElementsByTagName('html')[0].style.visibility = 'hidden';
  }
  ionViewWillLeave(){
    document.getElementsByTagName('html')[0].style.visibility = 'visible';
  }

  dismiss(save: boolean, base64:string) {
    this.viewCtrl.dismiss({'save': save, 'base64':base64});
  }
  changeImgUrl(url: string){
    this.overlay_url = url;
  }

}

tell me if you have any issues

1 Like

Hi @Gunnarkd
Thank u so much for ur attention and ur project is very usefull for me. Its working on android, but its not working on ios. When i try to open new-scan page in my project, the app suddenly close itself. I dont know its a cordova issue or not. What do u think about this ? U have an idea ?