Skip to content

Commit 3f711c9

Browse files
Merge pull request #135 from NativeScript/hristova/make-dimensions-match-orientation-when-keepAspectRatio-true
fix: make dimensions match orientation when keepAspectRatio is true
2 parents 9493d57 + 2dbbcaf commit 3f711c9

File tree

9 files changed

+121
-52
lines changed

9 files changed

+121
-52
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ __Example 2__ shows how to take a picture using the NativeScript camera module.
111111
* __width__: The desired width of the picture (in device independent pixels).
112112
* __height__: The desired height of the picture (in device independent pixels).
113113
* __keepAspectRatio__: A boolean parameter that indicates if the aspect ratio should be kept.
114-
* __saveToGallery__: A boolean parameter that indicates if the taken photo will be saved in "Photos" for Android and in "Camera Roll" in iOS
114+
* __saveToGallery__: A boolean parameter that indicates if the original taken photo will be saved in "Photos" for Android and in "Camera Roll" in iOS
115115
* __cameraFacing__: Start with either the "front" or "rear" (default) camera of the device. The current implementation doesn't work on all Android devices, in which case it falls back to the default behavior.
116116

117117
What does `device independent pixels` mean? The NativeScript layout mechanism uses device-independent pixels when measuring UI controls. This allows you to declare one layout and this layout will look similar to all devices (no matter the device's display resolution). In order to get a proper image quality for high resolution devices (like iPhone retina and Android Full HD), camera will return an image with bigger dimensions. For example, if we request an image that is 100x100, on iPhone 6 the actual image will be 200x200 (since its display density factor is 2 -> 100*2x100*2).

demo-angular/README.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
# Example for using nativescript-camera plugin
22
## This example demonstrates how to use plugin with nativescript-angular and webpack
33

4-
Steps to start example.
4+
If you want to test it out on an emulator or a device you can follow the instructions below:
55

6-
1. npm install
7-
2. Due to a bug with the used version of @angular, a single line from file
8-
node_modules/@angular/compiler/index.js (line 38: export * from './src/template_parser/template_ast';) should be deleted, since its duplicated.
9-
3. tns platform add android - to add platform before starting webpack process
10-
4. npm run start-android
6+
`git clone https://github.com/NativeScript/nativescript-camera.git`
7+
`cd nativescript-camera/demo` or `cd nativescript-camera/demo-angular`
8+
`npm run build.plugin && npm install`
9+
`tns run android` or `tns run ios` depending on the platform you want to test

demo-angular/app/app.component.html

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
1-
<GridLayout rows="auto, *, auto">
2-
<StackLayout orientation="horizontal" row="0" padding="10">
3-
<Label text="saveToGallery"></Label>
4-
<Switch [(ngModel)]="saveToGallery"></Switch>
1+
<GridLayout rows="auto, *, auto, auto">
2+
<StackLayout row="0" orientation="vertical" padding="10">
3+
<StackLayout orientation="horizontal" padding="10">
4+
<Label text="saveToGallery"></Label>
5+
<Switch [(ngModel)]="saveToGallery"></Switch>
6+
</StackLayout>
7+
<StackLayout orientation="horizontal" padding="10">
8+
<Label text="keepAspectRatio"></Label>
9+
<Switch [(ngModel)]="keepAspectRatio"></Switch>
10+
</StackLayout>
11+
<StackLayout orientation="horizontal" padding="10">
12+
<Label text="width"></Label>
13+
<TextField hint="Enter width" keyboardType="number" [(ngModel)]="width" class="input"></TextField>
14+
<Label text="height"></Label>
15+
<TextField hint="Enter height" keyboardType="number" [(ngModel)]="height" class="input"></TextField>
16+
</StackLayout>
517
</StackLayout>
6-
<Image row="1" [src]="cameraImage" stretch="fill" margin="10"></Image>
7-
<Button text="Take Picture" (tap)='onTakePictureTap($event)' row="2" padding="10"></Button>
18+
19+
<Image row="1" [src]="cameraImage" stretch="aspectFit" margin="10"></Image>
20+
<TextView row="2" [(ngModel)]="labelText" editable="false"></TextView>>
21+
<Button row="3" text="Take Picture" (tap)='onTakePictureTap($event)' padding="10"></Button>
822
</GridLayout>

demo-angular/app/app.component.ts

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,38 @@ import { ImageAsset } from 'tns-core-modules/image-asset';
77
templateUrl: './app.component.html'
88
})
99
export class AppComponent {
10-
public saveToGallery: boolean = true;
10+
public saveToGallery: boolean = false;
11+
public keepAspectRatio: boolean = true;
12+
public width: number = 320;
13+
public height: number = 240;
1114
public cameraImage: ImageAsset;
15+
public actualWidth: number;
16+
public actualHeight: number;
17+
public scale: number = 1;
18+
public labelText: string;
1219

1320
onTakePictureTap(args) {
1421
requestPermissions().then(
1522
() => {
16-
takePicture({ width: 300, height: 300, keepAspectRatio: true, saveToGallery: this.saveToGallery })
23+
takePicture({ width: this.width, height: this.height, keepAspectRatio: this.keepAspectRatio, saveToGallery: this.saveToGallery })
1724
.then((imageAsset: any) => {
1825
this.cameraImage = imageAsset;
26+
let that = this;
1927
imageAsset.getImageAsync(function (nativeImage) {
20-
let scale = 1;
21-
let height = 0;
22-
let width = 0;
2328
if (imageAsset.android) {
2429
// get the current density of the screen (dpi) and divide it by the default one to get the scale
25-
scale = nativeImage.getDensity() / android.util.DisplayMetrics.DENSITY_DEFAULT;
26-
height = imageAsset.options.height;
27-
width = imageAsset.options.width;
30+
that.scale = nativeImage.getDensity() / android.util.DisplayMetrics.DENSITY_DEFAULT;
31+
that.actualWidth = nativeImage.getWidth();
32+
that.actualHeight = nativeImage.getHeight();
2833
} else {
29-
scale = nativeImage.scale;
30-
width = nativeImage.size.width * scale;
31-
height = nativeImage.size.height * scale;
34+
that.scale = nativeImage.scale;
35+
that.actualWidth = nativeImage.size.width * that.scale;
36+
that.actualHeight = nativeImage.size.height * that.scale;
3237
}
33-
console.log(`Displayed Size: ${width}x${height} with scale ${scale}`);
34-
console.log(`Image Size: ${width / scale}x${height / scale}`);
38+
that.labelText = `Displayed Size: ${that.actualWidth}x${that.actualHeight} with scale ${that.scale}\n` +
39+
`Image Size: ${Math.round(that.actualWidth / that.scale)}x${Math.round(that.actualHeight / that.scale)}`;
40+
41+
console.log(`${that.labelText}`);
3542
});
3643
}, (error) => {
3744
console.log("Error: " + error);

demo/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Example for using nativescript-camera plugin
2+
3+
If you want to test it out on an emulator or a device you can follow the instructions below:
4+
5+
`git clone https://github.com/NativeScript/nativescript-camera.git`
6+
`cd nativescript-camera/demo` or `cd nativescript-camera/demo-angular`
7+
`npm run build.plugin && npm install`
8+
`tns run android` or `tns run ios` depending on the platform you want to test

demo/app/main-page.ts

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,46 @@ export function navigatingTo(args: EventData) {
1111
let page = <Page>args.object;
1212
let picturePath = null;
1313

14-
page.bindingContext = fromObject({ cameraImage: picturePath, saveToGallery: true });
14+
page.bindingContext = fromObject({
15+
cameraImage: picturePath,
16+
saveToGallery: false,
17+
keepAspectRatio: true,
18+
width: 320,
19+
height: 240
20+
});
1521
}
1622

1723
export function onTakePictureTap(args: EventData) {
1824
let page = <Page>(<View>args.object).page;
1925
let saveToGallery = page.bindingContext.get("saveToGallery");
26+
let keepAspectRatio = page.bindingContext.get("keepAspectRatio");
27+
let width = page.bindingContext.get("width");
28+
let height = page.bindingContext.get("height");
2029
requestPermissions().then(
2130
() => {
22-
takePicture({ width: 300, height: 300, keepAspectRatio: true, saveToGallery: saveToGallery }).
31+
takePicture({ width: width, height: height, keepAspectRatio: keepAspectRatio, saveToGallery: saveToGallery }).
2332
then((imageAsset) => {
2433
page.bindingContext.set("cameraImage", imageAsset);
2534
imageAsset.getImageAsync(function (nativeImage) {
2635
let scale = 1;
27-
let height = 0;
28-
let width = 0;
36+
let actualWidth = 0;
37+
let actualHeight = 0;
2938
if (imageAsset.android) {
3039
// get the current density of the screen (dpi) and divide it by the default one to get the scale
3140
scale = nativeImage.getDensity() / android.util.DisplayMetrics.DENSITY_DEFAULT;
32-
height = imageAsset.options.height;
33-
width = imageAsset.options.width;
41+
actualWidth = nativeImage.getWidth();
42+
actualHeight = nativeImage.getHeight();
3443
} else {
3544
scale = nativeImage.scale;
36-
width = nativeImage.size.width * scale;
37-
height = nativeImage.size.height * scale;
45+
actualWidth = nativeImage.size.width * scale;
46+
actualHeight = nativeImage.size.height * scale;
3847
}
39-
console.log(`Displayed Size: ${width}x${height} with scale ${scale}`);
40-
console.log(`Image Size: ${width / scale}x${height / scale}`);
48+
let labelText = `Displayed Size: ${actualWidth}x${actualHeight} with scale ${scale}\n` +
49+
`Image Size: ${Math.round(actualWidth / scale)}x${Math.round(actualHeight / scale)}`;
50+
page.bindingContext.set("labelText", labelText);
51+
52+
console.log(`${labelText}`);
53+
4154
});
4255
},
4356
(err) => {

demo/app/main-page.xml

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,23 @@
11
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo">
2-
<GridLayout rows="auto, *, auto">
3-
<StackLayout orientation="horizontal" row="0" padding="10">
4-
<Label text="saveToGallery" />
5-
<Switch checked="{{ saveToGallery }}"/>
2+
<GridLayout rows="auto, *, auto, auto">
3+
<StackLayout row="0" orientation="vertical" padding="10">
4+
<StackLayout orientation="horizontal" row="0" padding="10">
5+
<Label text="saveToGallery" />
6+
<Switch checked="{{ saveToGallery }}"/>
7+
</StackLayout>
8+
<StackLayout orientation="horizontal" row="0" padding="10">
9+
<Label text="keepAspectRatio" />
10+
<Switch checked="{{ keepAspectRatio }}"/>
11+
</StackLayout>
12+
<StackLayout orientation="horizontal" padding="10">
13+
<Label text="width"></Label>
14+
<TextField hint="Enter width" keyboardType="number" text="{{ width }}" class="input"></TextField>
15+
<Label text="height"></Label>
16+
<TextField hint="Enter height" keyboardType="number" text="{{ height }}" class="input"></TextField>
17+
</StackLayout>
618
</StackLayout>
7-
<Image row="1" src="{{ cameraImage }}" id="image" stretch="fill" margin="10"/>
8-
<Button text="Take Picture" tap="onTakePictureTap" row="2" padding="10"/>
19+
<Image row="1" src="{{ cameraImage }}" id="image" stretch="aspectFit" margin="10"/>
20+
<TextView row="2" text="{{ labelText }}" editable="false"></TextView>>
21+
<Button row="3" text="Take Picture" tap="onTakePictureTap" padding="10"/>
922
</GridLayout>
1023
</Page>

src/camera.android.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,7 @@ export let takePicture = function (options?): Promise<any> {
6767
tempPictureUri = (<any>android.support.v4.content).FileProvider.getUriForFile(
6868
applicationModule.android.currentContext,
6969
applicationModule.android.nativeApp.getPackageName() + ".provider", nativeFile);
70-
}
71-
else {
70+
} else {
7271
tempPictureUri = android.net.Uri.fromFile(nativeFile);
7372
}
7473

@@ -125,6 +124,18 @@ export let takePicture = function (options?): Promise<any> {
125124
rotateBitmap(picturePath, 270);
126125
}
127126

127+
if (shouldKeepAspectRatio) {
128+
let pictureWidth = exif.getAttributeInt(android.media.ExifInterface.TAG_IMAGE_WIDTH, 0);
129+
let pictureHeight = exif.getAttributeInt(android.media.ExifInterface.TAG_IMAGE_LENGTH, 0);
130+
let isPictureLandscape = pictureWidth > pictureHeight;
131+
let areOptionsLandscape = reqWidth > reqHeight;
132+
if (isPictureLandscape !== areOptionsLandscape) {
133+
let oldReqWidth = reqWidth;
134+
reqWidth = reqHeight;
135+
reqHeight = oldReqWidth;
136+
}
137+
}
138+
128139
let asset = new imageAssetModule.ImageAsset(picturePath);
129140
asset.options = {
130141
width: reqWidth,

src/camera.ios.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ class UIImagePickerControllerDelegateImpl extends NSObject implements UIImagePic
4242
let currentDate: Date = new Date();
4343
let source = info.valueForKey(UIImagePickerControllerOriginalImage);
4444
if (source) {
45-
let image = null;
4645
let imageSource: typeof imageSourceModule = require("image-source");
4746
let imageSourceResult = imageSource.fromNativeSource(source);
4847

@@ -81,10 +80,8 @@ class UIImagePickerControllerDelegateImpl extends NSObject implements UIImagePic
8180
trace.write("An error ocurred while saving image to gallery: " +
8281
err, trace.categories.Error, trace.messageType.error);
8382
}
84-
8583
});
86-
}
87-
else {
84+
} else {
8885
imageAsset = new imageAssetModule.ImageAsset(imageSourceResult.ios);
8986
this.setImageAssetAndCallCallback(imageAsset);
9087
}
@@ -96,6 +93,15 @@ class UIImagePickerControllerDelegateImpl extends NSObject implements UIImagePic
9693
}
9794

9895
private setImageAssetAndCallCallback(imageAsset: imageAssetModule.ImageAsset) {
96+
if (this._keepAspectRatio) {
97+
let isPictureLandscape = imageAsset.nativeImage.size.width > imageAsset.nativeImage.size.height;
98+
let areOptionsLandscape = this._width > this._height;
99+
if (isPictureLandscape !== areOptionsLandscape) {
100+
let oldWidth = this._width;
101+
this._width = this._height;
102+
this._height = oldWidth;
103+
}
104+
}
99105
imageAsset.options = {
100106
width: this._width,
101107
height: this._height,
@@ -139,8 +145,7 @@ export let takePicture = function (options): Promise<any> {
139145
} else if (saveToGallery) {
140146
listener = UIImagePickerControllerDelegateImpl.new().initWithCallbackAndOptions(
141147
resolve, reject, { saveToGallery: saveToGallery, keepAspectRatio: keepAspectRatio });
142-
}
143-
else {
148+
} else {
144149
listener = UIImagePickerControllerDelegateImpl.new().initWithCallback(resolve, reject);
145150
}
146151
imagePickerController.delegate = listener;
@@ -204,8 +209,7 @@ let requestPhotosPermissions = function () {
204209
trace.write("Application can access photo library assets.", trace.categories.Debug);
205210
}
206211
resolve();
207-
}
208-
else {
212+
} else {
209213
reject();
210214
}
211215
});

0 commit comments

Comments
 (0)