Skip to content

Commit 6081343

Browse files
crowmagnumbNathanWalker
authored andcommitted
feat(ImageSource): resize method (#8678)
1 parent f4313e3 commit 6081343

6 files changed

Lines changed: 86 additions & 0 deletions

File tree

api-reports/NativeScript.api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,6 +1198,8 @@ export class ImageSource {
11981198
// @deprecated (undocumented)
11991199
loadFromResource(name: string): boolean;
12001200

1201+
resize(maxSize: number, options?: any): ImageSource;
1202+
12011203
rotationAngle: number;
12021204

12031205
saveToFile(path: string, format: "png" | "jpeg" | "jpg", quality?: number): boolean;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
export function getScaledDimensions(
2+
width: number,
3+
height: number,
4+
maxSize: number
5+
) {
6+
if (height >= width) {
7+
if (height <= maxSize) {
8+
// if image already smaller than the required height
9+
return { width, height };
10+
}
11+
12+
return {
13+
width: Math.round((maxSize * width) / height),
14+
height: maxSize
15+
};
16+
}
17+
18+
if (width <= maxSize) {
19+
// if image already smaller than the required width
20+
return { width, height };
21+
}
22+
23+
return {
24+
width: maxSize,
25+
height: Math.round((maxSize * height) / width)
26+
};
27+
}

nativescript-core/image-source/image-source.android.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import { getNativeApplication } from "../application";
1010
import { Font } from "../ui/styling/font";
1111
import { Color } from "../color";
1212

13+
import { getScaledDimensions } from "./image-source-common";
14+
1315
export { isFileOrResourcePath };
1416

1517
let http: typeof httpModule;
@@ -337,6 +339,18 @@ export class ImageSource implements ImageSourceDefinition {
337339

338340
return outputStream.toString();
339341
}
342+
343+
public resize(maxSize: number, options?: any): ImageSource {
344+
const dim = getScaledDimensions(this.android.getWidth(), this.android.getHeight(), maxSize);
345+
const bm: android.graphics.Bitmap = android.graphics.Bitmap.createScaledBitmap(
346+
this.android,
347+
dim.width,
348+
dim.height,
349+
options && options.filter
350+
);
351+
352+
return new ImageSource(bm);
353+
}
340354
}
341355

342356
function getTargetFormat(format: "png" | "jpeg" | "jpg"): android.graphics.Bitmap.CompressFormat {

nativescript-core/image-source/image-source.d.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,19 @@ export class ImageSource {
209209
* @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.
210210
*/
211211
toBase64String(format: "png" | "jpeg" | "jpg", quality?: number): string;
212+
213+
/**
214+
* 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.
215+
* @param maxSize The maximum pixel dimension of the resulting image.
216+
* @param options Optional parameter, Only used for android, options.filter is a boolean which
217+
* determines whether or not bilinear filtering should be used when scaling the bitmap.
218+
* If this is true then bilinear filtering will be used when scaling which has
219+
* better image quality at the cost of worse performance. If this is false then
220+
* nearest-neighbor scaling is used instead which will have worse image quality
221+
* but is faster. Recommended default is to set filter to 'true' as the cost of
222+
* bilinear filtering is typically minimal and the improved image quality is significant.
223+
*/
224+
resize(maxSize: number, options?: any): ImageSource;
212225
}
213226

214227
/**

nativescript-core/image-source/image-source.ios.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import { Color } from "../color";
99
import { path as fsPath, knownFolders } from "../file-system";
1010
import { isFileOrResourcePath, RESOURCE_PREFIX, layout } from "../utils/utils";
1111

12+
import { getScaledDimensions } from "./image-source-common";
13+
1214
export { isFileOrResourcePath };
1315

1416
let http: typeof httpModule;
@@ -336,6 +338,24 @@ export class ImageSource implements ImageSourceDefinition {
336338
return res;
337339

338340
}
341+
342+
public resize(maxSize: number, options?: any): ImageSource {
343+
const size: CGSize = this.ios.size;
344+
const dim = getScaledDimensions(
345+
size.width,
346+
size.height,
347+
maxSize
348+
);
349+
350+
const newSize: CGSize = CGSizeMake(dim.width, dim.height);
351+
UIGraphicsBeginImageContextWithOptions(newSize, true, this.ios.scale);
352+
this.ios.drawInRect(CGRectMake(0, 0, newSize.width, newSize.height));
353+
354+
const resizedImage = UIGraphicsGetImageFromCurrentImageContext();
355+
UIGraphicsEndImageContext();
356+
357+
return new ImageSource(resizedImage);
358+
}
339359
}
340360

341361
function getFileName(path: string): string {

tests/app/image-source/image-source-tests.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,3 +295,13 @@ export function testLoadFromFontIconCode() {
295295
TKUnit.assert(img.width !== null, "img.width");
296296
TKUnit.assert(img.height !== null, "img.width");
297297
}
298+
299+
export function testResize() {
300+
const img = ImageSource.fromFileSync(imagePath);
301+
302+
const newSize = Math.floor(Math.max(img.width, img.height) / 2);
303+
304+
const resized = img.resize(newSize);
305+
306+
TKUnit.assert(resized.width === newSize || resized.height === newSize, "Image not resized correctly");
307+
}

0 commit comments

Comments
 (0)