Save Captured Images in a NativeScript Angular Application to Couchbase
NativeScript devs using Angular can send image captures to a database, Couchbase Lite here. If database saves are the direction you want to go, here's how to do it.
i get a particular set of questions quite a bit when it comes to mobile applications, the first being how to save captured images, and the second being how to sync them between devices or a remote database. since i’m a huge fan of nativescript for android and ios development, i thought it would be great to share one of many possible examples of solving this problem.
we’re going to see how to capture images in a nativescript application using angular and save those captured images to couchbase lite, an embedded device-level database.
going forward, it is important to note that there are many ways to save images or any other file data within a mobile application. for example, you could save them in a database or you can save them on the file system. we’re going to be saving them directly into the database in this example, but do your research on what strategy will work best for you.
in the animated image above, we are presented with the ability to capture images. things are a little different in a simulator, but on a device, the camera will open. after capturing an image it will be presented on the screen and saved into couchbase lite as a base64 formatted string.
the requirements
there aren’t many requirements when it comes to being successful with this guide. at a minimum you’ll need the following:
- nativescript cli
- android sdk for android and xcode for ios
to be able to build for android you’ll need the android sdk and to be able to build for ios you’ll need xcode, which is only available on macos computers. for this particular guide, no remote instance of couchbase server is necessary.
creating a fresh nativescript with angular project
with the prerequisites installed and ready to go, we need to create a fresh project somewhere on our computer.
from the nativescript cli, execute the following:
tns create photo-project --ng
the above command will create a new angular project, hence the
--ng
flag.
before we start developing, we will need to install the couchbase plugin for nativescript. this can be done by executing the following:
tns plugin add nativescript-couchbase
while we can technically start developing the application, there is one more order of business to take care of. on ios it is a requirement to explain each of the permissions being used. being able to take photos or use the gallery is a permission request, so we have to explain.
open the project’s app/app_resources/ios/info.plist file and include the following:
<key>nsphotolibraryusagedescription</key>
<string>photo library access warning</string>
the above will prevent any errors during compile time or run time. now we can safely start developing our android and ios mobile application.
developing the core application logic and user interface
before we start adding our own code, let’s strip out a bunch of the boilerplate template code that ships when creating a new nativescript with an angular project.
this is going to be a single page application, so we need to remove any of the pre-existing navigation routes. start by opening the project’s app/app.routing.ts file and make it look like the following:
import { ngmodule } from "@angular/core";
import { nativescriptroutermodule } from "nativescript-angular/router";
import { routes } from "@angular/router";
const routes: routes = [];
@ngmodule({
imports: [nativescriptroutermodule.forroot(routes)],
exports: [nativescriptroutermodule]
})
export class approutingmodule { }
the only thing we did was remove the routes from the
routes
array. technically, we can remove this file, but it is easier just to strip out what we’re not going to use.
now open the project’s app/app.module.ts file and make the typescript look like the following:
import { ngmodule, no_errors_schema } from "@angular/core";
import { nativescriptmodule } from "nativescript-angular/nativescript.module";
import { approutingmodule } from "./app.routing";
import { appcomponent } from "./app.component";
@ngmodule({
bootstrap: [
appcomponent
],
imports: [
nativescriptmodule,
approutingmodule
],
declarations: [
appcomponent
],
providers: [],
schemas: [
no_errors_schema
]
})
export class appmodule { }
notice in the above we’ve removed any reference to the mvc files that were previously routes. this includes html, typescript, and the angular service that was provided.
when it comes to adding new content, we’re going to focus on the typescript logic first, then move into the html ui. open the project’s app/app.component.ts file and include the following:
import { component, oninit } from "@angular/core";
import { couchbase } from "nativescript-couchbase";
import * as camera from "camera";
import * as imagesource from "image-source";
@component({
selector: "ns-app",
templateurl: "app.component.html",
})
export class appcomponent implements oninit {
public database: any;
public images: array<any>;
public constructor() {
this.database = new couchbase("image-database");
this.database.createview("images", "1", function(document, emitter) {
if(document.type && document.type == "image") {
emitter.emit(document._id, document);
}
});
this.images = [];
}
public ngoninit() {
let rows = this.database.executequery("images");
for(let i = 0; i < rows.length; i++) {
this.images.push(imagesource.frombase64(rows[i].image));
}
}
public capture() {
camera.takepicture({ width: 300, height: 300, keepaspectratio: true, savetogallery: false }).then(picture => {
let base64 = picture.tobase64string("png", 70);
this.database.createdocument({
"type": "image",
"image": base64,
"timestamp": (new date()).gettime()
});
this.images.push(picture);
}, error => {
console.dump(error);
});
}
}
a lot is happening in the above code so we’re going to break it down.
we had previously downloaded the couchbase plugin for nativescript, but now we need to import it along with other things:
import { couchbase } from "nativescript-couchbase";
import * as camera from "camera";
import * as imagesource from "image-source";
the camera functionality is already included with nativescript, we just need to import it. when it comes to manipulating the camera data, the
imagesource
is what we’ll use.
within the
appcomponent
class we have two variables:
private database: any;
public images: array<any>;
the
database
will hold our open couchbase lite instance and the
images
will hold all saved images that will be presented on the screen.
within the
constructor
method we open our database, create a view that we can later query, and initialize the array that will store our images.
public constructor() {
this.database = new couchbase("image-database");
this.database.createview("images", "1", function(document, emitter) {
if(document.type && document.type == "image") {
emitter.emit(document._id, document);
}
});
this.images = [];
}
the view that we’re creating will return all nosql documents that have a property called
type
that is set to
image
which represents to us that it is one of the possible images for displaying on the screen.
because data should never be loaded in the
constructor
method, we take things to the
ngoninit
method:
public ngoninit() {
let rows = this.database.executequery("images");
for(let i = 0; i < rows.length; i++) {
this.images.push(imagesource.frombase64(rows[i].image));
}
}
the
ngoninit
method triggers after the
constructor
method and it will query the view that had been previously created. each document saved will have a property called
image
that contains base64 image data. this model is based on our design.
after obtaining the base64 data it is converted into an
imagesource
and added to our array to be displayed on the screen.
public capture() {
camera.takepicture({
width: 300,
height: 300,
keepaspectratio: true,
savetogallery: false
}).then(picture => {
let base64 = picture.tobase64string("png", 70);
this.database.createdocument({
"type": "image",
"image": base64,
"timestamp": (new date()).gettime()
});
this.images.push(picture);
}, error => {
console.dump(error);
});
}
the above
capture
method is called via a button press in our html. it will launch the camera with a few settings defined.
upon a successful capture, the picture will be converted to base64 and a nosql document will be created along with various information sitting next to the base64 data.
not so bad right?
now we want to take a look at the html markup that goes with this logic. open the project’s app/app.component.html file and include the following:
<actionbar title="{n} couchbase photos">
<actionitem text="capture" ios.position="right" (tap)="capture()"></actionitem>
</actionbar>
<stacklayout>
<image *ngfor="let image of images" [src]="image"></image>
</stacklayout>
in the above html we have an actionbar with a button that will trigger the camera. within the core content of the page we have a loop that will go through each image in the array and display it on the screen.
conclusion
you just saw how to create a basic image capturing application with nativescript and angular that saves image data directly into couchbase lite nosql documents as base64 encoded strings. next time around we’re going to see how to synchronize this image data between devices and a remote database instance.
Comments