feat(image-source): add saveToFileAsync, toBase64StringAsync & resizeAsync (#9404)

This commit is contained in:
Osei Fortune
2021-08-11 10:28:06 -07:00
committed by Nathan Walker
parent 3aff057b99
commit b2f792324d
9 changed files with 371 additions and 3 deletions

View File

@ -316,6 +316,29 @@ export class ImageSource implements ImageSourceDefinition {
return res;
}
public saveToFileAsync(path: string, format: 'png' | 'jpeg' | 'jpg', quality = 100): Promise<boolean> {
return new Promise((resolve, reject) => {
org.nativescript.widgets.Utils.saveToFileAsync(
this.android,
path,
format,
quality,
new org.nativescript.widgets.Utils.AsyncImageCallback({
onSuccess(param0: boolean) {
resolve(param0);
},
onError(param0: java.lang.Exception) {
if (param0) {
reject(param0.getMessage());
} else {
reject();
}
},
})
);
});
}
public toBase64String(format: 'png' | 'jpeg' | 'jpg', quality = 100): string {
if (!this.android) {
return null;
@ -334,12 +357,56 @@ export class ImageSource implements ImageSourceDefinition {
return outputStream.toString();
}
public toBase64StringAsync(format: 'png' | 'jpeg' | 'jpg', quality = 100): Promise<string> {
return new Promise((resolve, reject) => {
org.nativescript.widgets.Utils.toBase64StringAsync(
this.android,
format,
quality,
new org.nativescript.widgets.Utils.AsyncImageCallback({
onSuccess(param0: string) {
resolve(param0);
},
onError(param0: java.lang.Exception) {
if (param0) {
reject(param0.getMessage());
} else {
reject();
}
},
})
);
});
}
public resize(maxSize: number, options?: any): ImageSource {
const dim = getScaledDimensions(this.android.getWidth(), this.android.getHeight(), maxSize);
const bm: android.graphics.Bitmap = android.graphics.Bitmap.createScaledBitmap(this.android, dim.width, dim.height, options && options.filter);
return new ImageSource(bm);
}
public resizeAsync(maxSize: number, options?: any): Promise<ImageSource> {
return new Promise((resolve, reject) => {
org.nativescript.widgets.Utils.resizeAsync(
this.android,
maxSize,
JSON.stringify(options || {}),
new org.nativescript.widgets.Utils.AsyncImageCallback({
onSuccess(param0: any) {
resolve(new ImageSource(param0));
},
onError(param0: java.lang.Exception) {
if (param0) {
reject(param0.getMessage());
} else {
reject();
}
},
})
);
});
}
}
function getTargetFormat(format: 'png' | 'jpeg' | 'jpg'): android.graphics.Bitmap.CompressFormat {

View File

@ -198,6 +198,14 @@ export class ImageSource {
*/
saveToFile(path: string, format: 'png' | 'jpeg' | 'jpg', quality?: number): boolean;
/**
* Saves this instance to the specified file, using the provided image format and quality asynchronously.
* @param path The path of the file on the file system to save to.
* @param format The format (encoding) of the image.
* @param quality Optional parameter, specifying the quality of the encoding. Defaults to the maximum available quality. Quality varies on a scale of 0 to 100.
*/
saveToFileAsync(path: string, format: 'png' | 'jpeg' | 'jpg', quality?: number): Promise<boolean>;
/**
* Converts the image to base64 encoded string, using the provided image format and quality.
* @param format The format (encoding) of the image.
@ -205,6 +213,13 @@ export class ImageSource {
*/
toBase64String(format: 'png' | 'jpeg' | 'jpg', quality?: number): string;
/**
* Converts the image to base64 encoded string, using the provided image format and quality asynchronously.
* @param format The format (encoding) of the image.
* @param quality Optional parameter, specifying the quality of the encoding. Defaults to the maximum available quality. Quality varies on a scale of 0 to 100.
*/
toBase64StringAsync(format: 'png' | 'jpeg' | 'jpg', quality?: number): Promise<string>;
/**
* Returns a new ImageSource that is a resized version of this image with the same aspect ratio, but the max dimension set to the provided maxSize.
* @param maxSize The maximum pixel dimension of the resulting image.
@ -217,6 +232,19 @@ export class ImageSource {
* bilinear filtering is typically minimal and the improved image quality is significant.
*/
resize(maxSize: number, options?: any): ImageSource;
/**
* Returns a new ImageSource that is a resized version of this image with the same aspect ratio, but the max dimension set to the provided maxSize asynchronously.
* @param maxSize The maximum pixel dimension of the resulting image.
* @param options Optional parameter, Only used for android, options.filter is a boolean which
* determines whether or not bilinear filtering should be used when scaling the bitmap.
* If this is true then bilinear filtering will be used when scaling which has
* better image quality at the cost of worse performance. If this is false then
* nearest-neighbor scaling is used instead which will have worse image quality
* but is faster. Recommended default is to set filter to 'true' as the cost of
* bilinear filtering is typically minimal and the improved image quality is significant.
*/
resizeAsync(maxSize: number, options?: any): Promise<ImageSource>;
}
/**

View File

@ -317,6 +317,33 @@ export class ImageSource implements ImageSourceDefinition {
return false;
}
public saveToFileAsync(path: string, format: 'png' | 'jpeg' | 'jpg', quality?: number): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
if (!this.ios) {
reject(false);
}
let isSuccess = false;
try {
if (quality) {
quality = (quality - 0) / (100 - 0); // Normalize quality on a scale of 0 to 1
}
const main_queue = dispatch_get_current_queue();
const background_queue = dispatch_get_global_queue(qos_class_t.QOS_CLASS_DEFAULT, 0);
dispatch_async(background_queue, () => {
const data = getImageData(this.ios, format, quality);
if (data) {
isSuccess = NSFileManager.defaultManager.createFileAtPathContentsAttributes(path, data, null);
}
dispatch_async(main_queue, () => {
resolve(isSuccess);
});
});
} catch (ex) {
reject(ex);
}
});
}
public toBase64String(format: 'png' | 'jpeg' | 'jpg', quality?: number): string {
let res = null;
if (!this.ios) {
@ -335,6 +362,33 @@ export class ImageSource implements ImageSourceDefinition {
return res;
}
public toBase64StringAsync(format: 'png' | 'jpeg' | 'jpg', quality?: number): Promise<string> {
return new Promise<string>((resolve, reject) => {
if (!this.ios) {
reject(null);
}
let result = null;
try {
if (quality) {
quality = (quality - 0) / (100 - 0); // Normalize quality on a scale of 0 to 1
}
const main_queue = dispatch_get_current_queue();
const background_queue = dispatch_get_global_queue(qos_class_t.QOS_CLASS_DEFAULT, 0);
dispatch_async(background_queue, () => {
const data = getImageData(this.ios, format, quality);
if (data) {
result = data.base64Encoding();
}
dispatch_async(main_queue, () => {
resolve(result);
});
});
} catch (ex) {
reject(ex);
}
});
}
public resize(maxSize: number, options?: any): ImageSource {
const size: CGSize = this.ios.size;
const dim = getScaledDimensions(size.width, size.height, maxSize);
@ -349,6 +403,31 @@ export class ImageSource implements ImageSourceDefinition {
return new ImageSource(resizedImage);
}
public resizeAsync(maxSize: number, options?: any): Promise<ImageSource> {
return new Promise((resolve, reject) => {
if (!this.ios) {
reject(null);
}
const main_queue = dispatch_get_current_queue();
const background_queue = dispatch_get_global_queue(qos_class_t.QOS_CLASS_DEFAULT, 0);
dispatch_async(background_queue, () => {
const size: CGSize = this.ios.size;
const dim = getScaledDimensions(size.width, size.height, maxSize);
const newSize: CGSize = CGSizeMake(dim.width, dim.height);
UIGraphicsBeginImageContextWithOptions(newSize, options?.opaque ?? false, this.ios.scale);
this.ios.drawInRect(CGRectMake(0, 0, newSize.width, newSize.height));
const resizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
dispatch_async(main_queue, () => {
resolve(new ImageSource(resizedImage));
});
});
});
}
}
function getFileName(path: string): string {