Merge branch 'master'

This commit is contained in:
Vasil Trifonov
2020-01-17 15:12:28 +02:00
parent 432a029499
commit b76893801d
3131 changed files with 418263 additions and 185769 deletions

View File

@@ -0,0 +1,65 @@
import { ImageAsset as ImageAssetDefinition, ImageAssetOptions } from ".";
import { Observable } from "../data/observable";
import { screen as platformScreen } from "../platform";
export class ImageAssetBase extends Observable implements ImageAssetDefinition {
private _options: ImageAssetOptions;
private _nativeImage: any;
ios: PHAsset;
android: string;
constructor() {
super();
this._options = { keepAspectRatio: true, autoScaleFactor: true };
}
get options(): ImageAssetOptions {
return this._options;
}
set options(value: ImageAssetOptions) {
this._options = 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 = Math.min(widthCoef, heightCoef);
return {
width: Math.floor(sourceWidth / aspectCoef),
height: Math.floor(sourceHeight / aspectCoef)
};
}
export function getRequestedImageSize(src: { width: number, height: number }, options: ImageAssetOptions): { width: number, height: number } {
const screen = platformScreen.mainScreen;
let reqWidth = options.width || Math.min(src.width, screen.widthPixels);
let reqHeight = options.height || Math.min(src.height, screen.heightPixels);
if (options && options.keepAspectRatio) {
let safeAspectSize = getAspectSafeDimensions(src.width, src.height, reqWidth, reqHeight);
reqWidth = safeAspectSize.width;
reqHeight = safeAspectSize.height;
}
return {
width: reqWidth,
height: reqHeight
};
}

View File

@@ -0,0 +1,90 @@
import { ImageAssetBase, getRequestedImageSize } from "./image-asset-common";
import { path as fsPath, knownFolders } from "../file-system";
export * from "./image-asset-common";
export class ImageAsset extends ImageAssetBase {
private _android: string; //file name of the image
constructor(asset: string) {
super();
let fileName = typeof asset === "string" ? asset.trim() : "";
if (fileName.indexOf("~/") === 0) {
fileName = fsPath.join(knownFolders.currentApp().path, fileName.replace("~/", ""));
}
this.android = fileName;
}
get android(): string {
return this._android;
}
set android(value: string) {
this._android = value;
}
public getImageAsync(callback: (image, error) => void) {
let bitmapOptions = new android.graphics.BitmapFactory.Options();
bitmapOptions.inJustDecodeBounds = true;
// read only the file size
let bitmap = android.graphics.BitmapFactory.decodeFile(this.android, bitmapOptions);
let sourceSize = {
width: bitmapOptions.outWidth,
height: bitmapOptions.outHeight
};
let requestedSize = getRequestedImageSize(sourceSize, this.options);
let sampleSize = org.nativescript.widgets.image.Fetcher.calculateInSampleSize(bitmapOptions.outWidth, bitmapOptions.outHeight, requestedSize.width, requestedSize.height);
let finalBitmapOptions = new android.graphics.BitmapFactory.Options();
finalBitmapOptions.inSampleSize = sampleSize;
try {
let error = null;
// read as minimum bitmap as possible (slightly bigger than the requested size)
bitmap = android.graphics.BitmapFactory.decodeFile(this.android, finalBitmapOptions);
if (bitmap) {
if (requestedSize.width !== bitmap.getWidth() || requestedSize.height !== bitmap.getHeight()) {
// scale to exact size
bitmap = android.graphics.Bitmap.createScaledBitmap(bitmap, requestedSize.width, requestedSize.height, true);
}
const rotationAngle = calculateAngleFromFile(this.android);
if (rotationAngle !== 0) {
const matrix = new android.graphics.Matrix();
matrix.postRotate(rotationAngle);
bitmap = android.graphics.Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
}
if (!bitmap) {
error = "Asset '" + this.android + "' cannot be found.";
}
callback(bitmap, error);
}
catch (ex) {
callback(null, ex);
}
}
}
function calculateAngleFromFile(filename: string) {
let rotationAngle = 0;
const ei = new android.media.ExifInterface(filename);
const orientation = ei.getAttributeInt(android.media.ExifInterface.TAG_ORIENTATION, android.media.ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case android.media.ExifInterface.ORIENTATION_ROTATE_90:
rotationAngle = 90;
break;
case android.media.ExifInterface.ORIENTATION_ROTATE_180:
rotationAngle = 180;
break;
case android.media.ExifInterface.ORIENTATION_ROTATE_270:
rotationAngle = 270;
break;
}
return rotationAngle;
}

View File

@@ -0,0 +1,21 @@
/**
* @module "image-asset"
*/ /** */
import { Observable } from "../data/observable";
export class ImageAsset extends Observable {
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;
autoScaleFactor?: boolean;
}

View File

@@ -0,0 +1,79 @@
import { ImageAssetBase, getRequestedImageSize } from "./image-asset-common";
import { path as fsPath, knownFolders } from "../file-system";
export * from "./image-asset-common";
export class ImageAsset extends ImageAssetBase {
private _ios: PHAsset;
constructor(asset: string | PHAsset | UIImage) {
super();
if (typeof asset === "string") {
if (asset.indexOf("~/") === 0) {
asset = fsPath.join(knownFolders.currentApp().path, asset.replace("~/", ""));
}
this.nativeImage = UIImage.imageWithContentsOfFile(asset);
}
else if (asset instanceof UIImage) {
this.nativeImage = asset;
}
else {
this.ios = asset;
}
}
get ios(): PHAsset {
return this._ios;
}
set ios(value: PHAsset) {
this._ios = value;
}
public getImageAsync(callback: (image, error) => void) {
if (!this.ios && !this.nativeImage) {
callback(null, "Asset cannot be found.");
}
let srcWidth = this.nativeImage ? this.nativeImage.size.width : this.ios.pixelWidth;
let srcHeight = this.nativeImage ? this.nativeImage.size.height : this.ios.pixelHeight;
let requestedSize = getRequestedImageSize({ width: srcWidth, height: srcHeight }, this.options);
if (this.nativeImage) {
let newSize = CGSizeMake(requestedSize.width, requestedSize.height);
let resizedImage = this.scaleImage(this.nativeImage, newSize);
callback(resizedImage, null);
return;
}
let imageRequestOptions = PHImageRequestOptions.alloc().init();
imageRequestOptions.deliveryMode = PHImageRequestOptionsDeliveryMode.HighQualityFormat;
imageRequestOptions.networkAccessAllowed = true;
PHImageManager.defaultManager().requestImageForAssetTargetSizeContentModeOptionsResultHandler(this.ios, requestedSize, PHImageContentMode.AspectFit, imageRequestOptions,
(image, imageResultInfo) => {
if (image) {
let resultImage = this.scaleImage(image, requestedSize);
callback(resultImage, null);
}
else {
callback(null, imageResultInfo.valueForKey(PHImageErrorKey));
}
}
);
}
private scaleImage(image: UIImage, requestedSize: { width: number, height: number }): UIImage {
// scaleFactor = 0 takes the scale factor of the devices's main screen.
const scaleFactor = this.options && this.options.autoScaleFactor === false ? 1.0 : 0.0;
UIGraphicsBeginImageContextWithOptions(requestedSize, false, scaleFactor);
image.drawInRect(CGRectMake(0, 0, requestedSize.width, requestedSize.height));
let resultImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return resultImage;
}
}

View File

@@ -0,0 +1,6 @@
{
"name": "image-asset",
"main": "image-asset",
"types": "image-asset.d.ts",
"nativescript": {}
}