Tuesday 8 September 2015

Adding image rotate with the nativescript camera functionality

You may be aware that you can take photos just using nativescript.

One thing I found on my Galaxy Note 4 though is that the images will always appear in landscape mode regardless of how you took them.

So I thought I would post some code to show you how they can be rotated.

First here is how it looks in the app.





And here is the XML and code.

<Page xmlns="http://www.nativescript.org/tns.xsd" shownModally="onShownModally" loaded="onLoaded" backgroundColor="transparent"  xmlns:imageButton="helpers/buttonhelper">
  <GridLayout columns="*" rows="auto,*" width="300" height="550" cssClass="popup">
    <Label text="Take Photo" row="0" col="0" cssClass="popuptitle"/>
    <StackLayout  row="1" col="0" cssClass="popupouter">
      <GridLayout columns="*" rows="*,auto,auto" cssClass="popupinner" horizontalAlignment="center" verticalAlignment="center">
        <Image imageSource="{{photo}}" row="0" col="0"/>
        <StackLayout orientation="horizontal" horizontalAlignment="center" row="1" col="0">
          <imageButton:ImageButton textPadded="" tap="{{rotateLeft}}" icon="rotateleft"/>
          <imageButton:ImageButton textPadded="" tap="{{takePhoto}}" icon="camera"/>
          <imageButton:ImageButton textPadded="" tap="{{rotateRight}}" icon="rotateright"/>
        </StackLayout>
        <StackLayout orientation="horizontal" horizontalAlignment="center" row="2" col="0">
          <imageButton:ImageButton textPadded="{{languageData.OK}}" tap="{{ok}}" icon="tick"/>
          <imageButton:ImageButton textPadded="{{languageData.Cancel}}"  tap="{{cancel}}" icon="cross"/>
        </StackLayout>
      </GridLayout>
    </StackLayout>
  </GridLayout>
</Page>
/* tslint:disable:use-strict triple-equals max-line-length one-line */

import observableHelper = require("../../helpers/observablehelper");
import pages = require("ui/page");
import camera = require("camera");
import imageSource = require("image-source");
import fs = require("file-system");
import enums = require("ui/enums");

export interface ICallbackResult { photo: imageSource.ImageSource }
export interface ICallback { (result: ICallbackResult, success: boolean): void };

export function display(page: pages.Page, action: ICallback) {
    page.showModal("./dialogs/photo/photo-page", page, action);
}

enum fields { photo };

export class PhotoModel extends observableHelper.PopupModel<ICallbackResult, fields> {
    constructor() {
        super(fields);
        this.setValue(fields.photo, null);
    }

    public returnTrue() {
        this.returnValue = { photo: this.getValue(fields.photo) };
        this.returnResult(this.returnValue, true);
    }

    public rotateRight() {
        var picture = <imageSource.ImageSource>this.getValue(fields.photo);
        if (picture != null) {
            var newImage = new imageSource.ImageSource();

            if (picture.ios) {
                var cgImage = new CIImage(picture.ios);
                newImage.ios = picture.ios.initWithCGImageScaleOrientation(cgImage, 1, UIImageOrientation.UIImageOrientationRight);
            }

            if (picture.android) {
                var matrix = new android.graphics.Matrix();
                matrix.postRotate(90);
                newImage.android = android.graphics.Bitmap.createBitmap(picture.android, 0, 0, picture.android.getWidth(), picture.android.getHeight(), matrix, true);
            }
            this.setValue(fields.photo, newImage);
        }
    }

    public rotateLeft() {
        var picture = <imageSource.ImageSource>this.getValue(fields.photo);
        if (picture != null) {
            var newImage = new imageSource.ImageSource();

            if (picture.ios) {
                var cgImage = new CIImage(picture.ios);
                newImage.ios = picture.ios.initWithCGImageScaleOrientation(cgImage, 1, UIImageOrientation.UIImageOrientationLeft);
            }

            if (picture.android) {
                var matrix = new android.graphics.Matrix();
                matrix.postRotate(-90);
                newImage.android = android.graphics.Bitmap.createBitmap(picture.android, 0, 0, picture.android.getWidth(), picture.android.getHeight(), matrix, true);
            }
            this.setValue(fields.photo, newImage);
        }
    }

    public takePhoto() {
        camera.takePicture({ width: 200, height: 200, keepAspectRatio: true }).then((picture) => {
            this.setValue(fields.photo, picture);
        });
    }
}

export var viewModel = new PhotoModel();
As can be seen then code is quite small. I have put in a request on github to get image rotation in the core code.

I haven't tested the functionality in IOS yet, but from reading it should work.

3 comments:

  1. Good job.. i am still stuck on creating framework stuff for my apps

    ReplyDelete
  2. Nice blog Peter, we are currently evaluating Nativescript for our existing apps done with Kendo UI Mobile.
    Just one question: on www.physiotherapyexercises.com you guys have statistics about app downloads (?) per platform. Are they generated automatically or are you doing them manually?
    Thanks,
    Roman

    ReplyDelete
    Replies
    1. I have a program that reads the android/ios text files that are generated from their reporting options. Once a month I download them and copy them to a directory on the server and it just updates statistics from there.

      Delete