mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 19:26:42 +08:00
Merge pull request #2822 from NativeScript/nnikolov/CameraRefactoring
Refactored image loading from camera.
This commit is contained in:
@ -61,6 +61,6 @@ export function setPicture(args: observable.EventData) {
|
||||
var img = parent.getViewById<image.Image>("cameraImage");
|
||||
|
||||
camera.takePicture().then(r=> {
|
||||
img.imageSource = r;
|
||||
img.src = r;
|
||||
}).catch(e => dialogs.alert("ERROR: " + e));
|
||||
}
|
@ -81,21 +81,6 @@ export var takePicture = function (options?): Promise<any> {
|
||||
scaledSizeImage = bitmap;
|
||||
}
|
||||
|
||||
let ei = new android.media.ExifInterface(picturePath);
|
||||
let orientation = ei.getAttributeInt(android.media.ExifInterface.TAG_ORIENTATION, android.media.ExifInterface.ORIENTATION_NORMAL);
|
||||
|
||||
switch (orientation) {
|
||||
case android.media.ExifInterface.ORIENTATION_ROTATE_90:
|
||||
scaledSizeImage = rotateBitmap(scaledSizeImage, 90);
|
||||
break;
|
||||
case android.media.ExifInterface.ORIENTATION_ROTATE_180:
|
||||
scaledSizeImage = rotateBitmap(scaledSizeImage, 180);
|
||||
break;
|
||||
case android.media.ExifInterface.ORIENTATION_ROTATE_270:
|
||||
scaledSizeImage = rotateBitmap(scaledSizeImage, 270);
|
||||
break;
|
||||
}
|
||||
|
||||
resolve(imageSource.fromNativeSource(scaledSizeImage));
|
||||
}
|
||||
};
|
||||
@ -144,9 +129,3 @@ var createDateTimeStamp = function () {
|
||||
date.getSeconds().toString();
|
||||
return result;
|
||||
}
|
||||
|
||||
var rotateBitmap = function (source, angle) {
|
||||
let matrix = new android.graphics.Matrix();
|
||||
matrix.postRotate(angle);
|
||||
return android.graphics.Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
|
||||
}
|
||||
|
78
tns-core-modules/image-asset/image-asset-common.ts
Normal file
78
tns-core-modules/image-asset/image-asset-common.ts
Normal file
@ -0,0 +1,78 @@
|
||||
import definition = require("image-asset");
|
||||
import platform = require("platform");
|
||||
|
||||
export class ImageAsset implements definition.ImageAsset {
|
||||
private _options: definition.ImageAssetOptions;
|
||||
private _ios: PHAsset;
|
||||
private _nativeImage: any;
|
||||
private _android: string; //file name of the image
|
||||
|
||||
get options(): definition.ImageAssetOptions {
|
||||
return this._options;
|
||||
}
|
||||
|
||||
set options(value: definition.ImageAssetOptions) {
|
||||
this._options = value;
|
||||
}
|
||||
|
||||
get ios(): PHAsset {
|
||||
return this._ios;
|
||||
}
|
||||
|
||||
set ios(value: PHAsset) {
|
||||
this._ios = value;
|
||||
}
|
||||
|
||||
get android(): string {
|
||||
return this._android;
|
||||
}
|
||||
|
||||
set android(value: string) {
|
||||
this._android = value;
|
||||
}
|
||||
|
||||
get nativeImage(): any {
|
||||
return this._nativeImage;
|
||||
}
|
||||
|
||||
set nativeImage(value: any) {
|
||||
this._nativeImage = value;
|
||||
}
|
||||
|
||||
public getImageAsync(callback: (image: any, error: Error) => void) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
export function getAspectSafeDimensions(sourceWidth, sourceHeight, reqWidth, reqHeight) {
|
||||
let widthCoef = sourceWidth / reqWidth;
|
||||
let heightCoef = sourceHeight / reqHeight;
|
||||
|
||||
let aspectCoef = widthCoef > heightCoef ? widthCoef : heightCoef;
|
||||
|
||||
return {
|
||||
width: Math.floor(sourceWidth / aspectCoef),
|
||||
height: Math.floor(sourceHeight / aspectCoef)
|
||||
};
|
||||
}
|
||||
|
||||
export function getRequestedImageSize(src: {width: number, height: number}): {width: number, height: number} {
|
||||
let reqWidth = platform.screen.mainScreen.widthDIPs;
|
||||
let reqHeight = platform.screen.mainScreen.heightDIPs
|
||||
if (this.options && this.options.width) {
|
||||
reqWidth = (this.options.width > 0 && this.options.width < reqWidth) ? this.options.width : reqWidth;
|
||||
}
|
||||
if (this.options && this.options.height) {
|
||||
reqWidth = (this.options.height > 0 && this.options.height < reqHeight) ? this.options.height : reqHeight;
|
||||
}
|
||||
|
||||
if (this.options && this.options.keepAspectRatio) {
|
||||
let safeAspectSize = getAspectSafeDimensions(src.width, src.height, reqWidth, reqHeight);
|
||||
reqWidth = safeAspectSize.width;
|
||||
reqHeight = safeAspectSize.height;
|
||||
}
|
||||
return {
|
||||
width: reqWidth,
|
||||
height:reqHeight
|
||||
};
|
||||
}
|
50
tns-core-modules/image-asset/image-asset.android.ts
Normal file
50
tns-core-modules/image-asset/image-asset.android.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import * as platform from "platform";
|
||||
import common = require("./image-asset-common");
|
||||
|
||||
global.moduleMerge(common, exports);
|
||||
|
||||
export class ImageAsset extends common.ImageAsset {
|
||||
constructor(asset: string) {
|
||||
super();
|
||||
this.android = asset;
|
||||
}
|
||||
|
||||
public getImageAsync(callback: (image, error) => void) {
|
||||
let bitmapOptions = new android.graphics.BitmapFactory.Options();
|
||||
bitmapOptions.inJustDecodeBounds = true;
|
||||
let bitmap = android.graphics.BitmapFactory.decodeFile(this.android, bitmapOptions);
|
||||
let sourceSize = {
|
||||
width: bitmapOptions.outWidth,
|
||||
height: bitmapOptions.outHeight
|
||||
};
|
||||
let requestedSize = common.getRequestedImageSize(sourceSize);
|
||||
|
||||
let sampleSize = calculateInSampleSize(bitmapOptions.outWidth, bitmapOptions.outHeight, requestedSize.width, requestedSize.height);
|
||||
|
||||
let finalBitmapOptions = new android.graphics.BitmapFactory.Options();
|
||||
finalBitmapOptions.inSampleSize = sampleSize;
|
||||
try {
|
||||
bitmap = android.graphics.BitmapFactory.decodeFile(this.android, finalBitmapOptions);
|
||||
callback(bitmap, null);
|
||||
}
|
||||
catch (ex) {
|
||||
callback(null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var calculateInSampleSize = function (imageWidth, imageHeight, reqWidth, reqHeight) {
|
||||
let sampleSize = 1;
|
||||
let displayWidth = platform.screen.mainScreen.widthDIPs;
|
||||
let displayHeigth = platform.screen.mainScreen.heightDIPs;
|
||||
reqWidth = (reqWidth > 0 && reqWidth < displayWidth) ? reqWidth : displayWidth;
|
||||
reqHeight = (reqHeight > 0 && reqHeight < displayHeigth) ? reqHeight : displayHeigth;
|
||||
if (imageWidth > reqWidth && imageHeight > reqHeight) {
|
||||
let halfWidth = imageWidth / 2;
|
||||
let halfHeight = imageHeight / 2;
|
||||
while ((halfWidth / sampleSize) > reqWidth && (halfHeight / sampleSize) > reqHeight) {
|
||||
sampleSize *= 2;
|
||||
}
|
||||
}
|
||||
return sampleSize;
|
||||
}
|
16
tns-core-modules/image-asset/image-asset.d.ts
vendored
Normal file
16
tns-core-modules/image-asset/image-asset.d.ts
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
declare module "image-asset" {
|
||||
export class ImageAsset {
|
||||
constructor(asset: any);
|
||||
getImageAsync(callback: (image: any, error: any) => void); //UIImage for iOS and android.graphics.Bitmap for Android
|
||||
ios: any; //PHAsset
|
||||
nativeImage: any; //UIImage for iOS and android.graphics.Bitmap for Android
|
||||
android: any;
|
||||
options: ImageAssetOptions;
|
||||
}
|
||||
|
||||
export interface ImageAssetOptions {
|
||||
width?: number;
|
||||
height?: number;
|
||||
keepAspectRatio?: boolean;
|
||||
}
|
||||
}
|
41
tns-core-modules/image-asset/image-asset.ios.ts
Normal file
41
tns-core-modules/image-asset/image-asset.ios.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import common = require("./image-asset-common");
|
||||
|
||||
global.moduleMerge(common, exports);
|
||||
|
||||
export class ImageAsset extends common.ImageAsset {
|
||||
constructor(asset: PHAsset | UIImage) {
|
||||
super();
|
||||
if (asset instanceof UIImage) {
|
||||
this.nativeImage = asset
|
||||
}
|
||||
else {
|
||||
this.ios = asset;
|
||||
}
|
||||
}
|
||||
|
||||
public getImageAsync(callback: (image, error) => void) {
|
||||
let requestedSize = common.getRequestedImageSize({
|
||||
width: this.ios.pixelWidth,
|
||||
height: this.ios.pixelHeight
|
||||
});
|
||||
|
||||
let imageRequestOptions = PHImageRequestOptions.alloc().init();
|
||||
imageRequestOptions.deliveryMode = PHImageRequestOptionsDeliveryMode.HighQualityFormat;
|
||||
|
||||
if (this.nativeImage) {
|
||||
callback(this.nativeImage, null);
|
||||
return;
|
||||
}
|
||||
|
||||
PHImageManager.defaultManager().requestImageForAssetTargetSizeContentModeOptionsResultHandler(this.ios, requestedSize, PHImageContentMode.AspectFit, imageRequestOptions,
|
||||
(image, imageResultInfo) => {
|
||||
if (image) {
|
||||
callback(image, null);
|
||||
}
|
||||
else {
|
||||
callback(null, imageResultInfo.valueForKey(PHImageErrorKey));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
5
tns-core-modules/image-asset/package.json
Normal file
5
tns-core-modules/image-asset/package.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"name" : "image-asset",
|
||||
"main" : "image-asset",
|
||||
"nativescript": {}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import utils = require("utils/utils");
|
||||
import * as httpModule from "http";
|
||||
import * as imageAssetModule from "image-asset";
|
||||
|
||||
var http: typeof httpModule;
|
||||
function ensureHttp() {
|
||||
@ -11,6 +12,11 @@ function ensureHttp() {
|
||||
// This is used for definition purposes only, it does not generate JavaScript for it.
|
||||
import definition = require("image-source");
|
||||
|
||||
export function fromAsset(asset: imageAssetModule.ImageAsset): Promise<definition.ImageSource> {
|
||||
let image = new definition.ImageSource();
|
||||
return image.fromAsset(asset);
|
||||
}
|
||||
|
||||
export function fromResource(name: string): definition.ImageSource {
|
||||
var image = new definition.ImageSource();
|
||||
return image.loadFromResource(name) ? image : null;
|
||||
|
@ -4,6 +4,7 @@ import common = require("./image-source-common");
|
||||
import * as utilsModule from "utils/utils";
|
||||
import * as fileSystemModule from "file-system";
|
||||
import * as enumsModule from "ui/enums";
|
||||
import * as imageAssetModule from "image-asset";
|
||||
|
||||
global.moduleMerge(common, exports);
|
||||
|
||||
@ -32,6 +33,21 @@ export class ImageSource implements definition.ImageSource {
|
||||
public android: android.graphics.Bitmap;
|
||||
public ios: UIImage;
|
||||
|
||||
public fromAsset(asset: imageAssetModule.ImageAsset): Promise<definition.ImageSource> {
|
||||
return new Promise<definition.ImageSource>((resolve, reject) => {
|
||||
asset.getImageAsync((image, err) => {
|
||||
if (image) {
|
||||
this.setRotationAngleFromFile(asset.android);
|
||||
this.setNativeSource(image);
|
||||
resolve(this);
|
||||
}
|
||||
else {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public loadFromResource(name: string): boolean {
|
||||
this.android = null;
|
||||
|
||||
@ -58,6 +74,24 @@ export class ImageSource implements definition.ImageSource {
|
||||
});
|
||||
}
|
||||
|
||||
private setRotationAngleFromFile(filename: string) {
|
||||
this.rotationAngle = 0;
|
||||
let ei = new android.media.ExifInterface(filename);
|
||||
let orientation = ei.getAttributeInt(android.media.ExifInterface.TAG_ORIENTATION, android.media.ExifInterface.ORIENTATION_NORMAL);
|
||||
|
||||
switch (orientation) {
|
||||
case android.media.ExifInterface.ORIENTATION_ROTATE_90:
|
||||
this.rotationAngle = 90;
|
||||
break;
|
||||
case android.media.ExifInterface.ORIENTATION_ROTATE_180:
|
||||
this.rotationAngle = 180;
|
||||
break;
|
||||
case android.media.ExifInterface.ORIENTATION_ROTATE_270:
|
||||
this.rotationAngle = 270;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public loadFromFile(path: string): boolean {
|
||||
ensureFS();
|
||||
|
||||
@ -66,7 +100,9 @@ export class ImageSource implements definition.ImageSource {
|
||||
fileName = fs.path.join(fs.knownFolders.currentApp().path, fileName.replace("~/", ""));
|
||||
}
|
||||
|
||||
this.setRotationAngleFromFile(fileName);
|
||||
this.android = android.graphics.BitmapFactory.decodeFile(fileName, null);
|
||||
|
||||
return this.android != null;
|
||||
}
|
||||
|
||||
@ -154,6 +190,15 @@ export class ImageSource implements definition.ImageSource {
|
||||
|
||||
return NaN;
|
||||
}
|
||||
|
||||
private _rotationAngle: number;
|
||||
get rotationAngle(): number {
|
||||
return this._rotationAngle;
|
||||
}
|
||||
|
||||
set rotationAngle(value: number) {
|
||||
this._rotationAngle = value;
|
||||
}
|
||||
}
|
||||
|
||||
function getTargetFormat(format: string): android.graphics.Bitmap.CompressFormat {
|
||||
|
15
tns-core-modules/image-source/image-source.d.ts
vendored
15
tns-core-modules/image-source/image-source.d.ts
vendored
@ -2,7 +2,7 @@
|
||||
* Contains the ImageSource class, which encapsulates the common abstraction behind a platform specific object (typically a Bitmap) that is used as a source for images.
|
||||
*/
|
||||
declare module "image-source" {
|
||||
|
||||
import * as imageAssetModule from "image-asset";
|
||||
/**
|
||||
* Encapsulates the common abstraction behind a platform specific object (typically a Bitmap) that is used as a source for images.
|
||||
*/
|
||||
@ -17,6 +17,11 @@ declare module "image-source" {
|
||||
*/
|
||||
width: number;
|
||||
|
||||
/**
|
||||
* Gets or sets the rotation angle that should be applied to image. (Used in android)
|
||||
*/
|
||||
rotationAngle: number;
|
||||
|
||||
/**
|
||||
* The iOS-specific [UIImage](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIImage_Class/) instance. Will be undefined when running on Android.
|
||||
*/
|
||||
@ -27,6 +32,12 @@ declare module "image-source" {
|
||||
*/
|
||||
android: any /* android.graphics.Bitmap */;
|
||||
|
||||
/**
|
||||
* Loads this instance from the specified asset asynchronously.
|
||||
* @param asset The ImageAsset instance used to create ImageSource.
|
||||
*/
|
||||
fromAsset(asset: imageAssetModule.ImageAsset): Promise<ImageSource>;
|
||||
|
||||
/**
|
||||
* Loads this instance from the specified resource name.
|
||||
* @param name The name of the resource (without its extension).
|
||||
@ -98,6 +109,8 @@ declare module "image-source" {
|
||||
toBase64String(format: string, quality?: number): string;
|
||||
}
|
||||
|
||||
export function fromAsset(asset: imageAssetModule.ImageAsset): Promise<ImageSource>;
|
||||
|
||||
/**
|
||||
* Creates a new ImageSource instance and loads it from the specified resource name.
|
||||
* @param name The name of the resource (without its extension).
|
||||
|
@ -3,6 +3,7 @@ import types = require("utils/types");
|
||||
import fs = require("file-system");
|
||||
import common = require("./image-source-common");
|
||||
import enums = require("ui/enums");
|
||||
import * as imageAssetModule from "image-asset";
|
||||
|
||||
global.moduleMerge(common, exports);
|
||||
|
||||
@ -10,6 +11,19 @@ export class ImageSource implements definition.ImageSource {
|
||||
public android: android.graphics.Bitmap;
|
||||
public ios: UIImage;
|
||||
|
||||
public fromAsset(asset: imageAssetModule.ImageAsset) {
|
||||
return new Promise<definition.ImageSource>((resolve, reject) => {
|
||||
asset.getImageAsync((image, err) => {
|
||||
if (image) {
|
||||
resolve(common.fromNativeSource(image));
|
||||
}
|
||||
else {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public loadFromResource(name: string): boolean {
|
||||
this.ios = (<any>UIImage).tns_safeImageNamed(name) || (<any>UIImage).tns_safeImageNamed(`${name}.jpg`);
|
||||
return this.ios != null;
|
||||
@ -157,6 +171,10 @@ export class ImageSource implements definition.ImageSource {
|
||||
|
||||
return NaN;
|
||||
}
|
||||
|
||||
get rotationAngle(): number {
|
||||
return NaN;
|
||||
}
|
||||
}
|
||||
|
||||
function getImageData(instance: UIImage, format: string, quality = 1.0): NSData {
|
||||
|
1
tns-core-modules/tns-core-modules.base.d.ts
vendored
1
tns-core-modules/tns-core-modules.base.d.ts
vendored
@ -18,6 +18,7 @@
|
||||
/// <reference path="fps-meter/fps-native.d.ts" />
|
||||
/// <reference path="http/http-request.d.ts" />
|
||||
/// <reference path="http/http.d.ts" />
|
||||
/// <reference path="image-asset/image-asset.d.ts" />
|
||||
/// <reference path="image-source/image-source.d.ts" />
|
||||
/// <reference path="js-libs/easysax/easysax.d.ts" />
|
||||
/// <reference path="js-libs/esprima/esprima.d.ts" />
|
||||
|
@ -2,6 +2,7 @@
|
||||
import view = require("ui/core/view");
|
||||
import proxy = require("ui/core/proxy");
|
||||
import imageSource = require("image-source");
|
||||
import imageAssetModule = require("image-asset");
|
||||
import definition = require("ui/image");
|
||||
import enums = require("ui/enums");
|
||||
import platform = require("platform");
|
||||
@ -158,6 +159,12 @@ export class Image extends view.View implements definition.Image {
|
||||
this.imageSource = value;
|
||||
this._setValue(Image.isLoadingProperty, false);
|
||||
}
|
||||
else if (value instanceof imageAssetModule.ImageAsset) {
|
||||
imageSource.fromAsset(value).then((result) => {
|
||||
this.imageSource = result;
|
||||
this._setValue(Image.isLoadingProperty, false);
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.imageSource = imageSource.fromNativeSource(value);
|
||||
this._setValue(Image.isLoadingProperty, false);
|
||||
|
@ -45,7 +45,7 @@ function onImageSourcePropertyChanged(data: dependencyObservable.PropertyChangeD
|
||||
return;
|
||||
}
|
||||
|
||||
image._setNativeImage(data.newValue ? data.newValue.android : null);
|
||||
image._setNativeImage(data.newValue);
|
||||
}
|
||||
|
||||
// register the setNativeValue callback
|
||||
@ -64,7 +64,11 @@ export class Image extends imageCommon.Image {
|
||||
}
|
||||
|
||||
public _setNativeImage(nativeImage: any) {
|
||||
this.android.setImageBitmap(nativeImage);
|
||||
let rotation = (nativeImage && nativeImage.rotationAngle) ? nativeImage.rotationAngle : 0 ;
|
||||
if (rotation > 0) {
|
||||
this.android.setRotationAngle(rotation);
|
||||
}
|
||||
this.android.setImageBitmap(nativeImage.android);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -280,6 +280,14 @@
|
||||
|
||||
export class ImageView extends android.widget.ImageView {
|
||||
constructor(context: android.content.Context);
|
||||
getCornerRadius(): number;
|
||||
setCornerRadius(radius: number): void;
|
||||
|
||||
getBorderWidth(): number;
|
||||
setBorderWidth(width: number): void;
|
||||
|
||||
getRotationAngle(): number;
|
||||
setRotationAngle(angle: number): void;
|
||||
}
|
||||
|
||||
export class TabLayout extends android.widget.HorizontalScrollView {
|
||||
|
Reference in New Issue
Block a user