Skip to content

fix(android): Setting String Value to Width And Height #10668

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/core/image-asset/image-asset-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export function getRequestedImageSize(src: { width: number; height: number }, op
}

return {
width: reqWidth,
height: reqHeight,
width: Number(reqWidth),
height: Number(reqHeight),
};
}
55 changes: 53 additions & 2 deletions packages/core/image-asset/index.android.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,58 @@ export class ImageAsset extends ImageAssetBase {
this._android = value;
}

public getImageAsync(callback: (image, error) => void) {
/**
* Validates and adjusts image dimensions to prevent bitmap size exceeding Android's 32-bit limit.
* Android has a limitation where bitmap size (width * height) cannot exceed 2^31-1.
* This method ensures the dimensions are within safe bounds while maintaining aspect ratio.
*
* @param {number|string} width - The desired width of the image
* @param {number|string} height - The desired height of the image
* @returns {{ width: number; height: number }} Object containing validated dimensions
*
* @example
* // Returns safe dimensions that won't exceed Android's bitmap size limit
* const safe = validateDimensions("4000", "3000");
*/
private _validateDimensions(width: number | string, height: number | string): { width: number; height: number } {
const parseSize = (size: number | string): number => {
return typeof size === 'string' ? parseInt(size, 10) : size;
};

let w = parseSize(width);
let h = parseSize(height);

// Check for 32-bit limitation (2^31 - 1, leaving some headroom)
const MAX_DIMENSION = Math.floor(Math.sqrt(Math.pow(2, 31) - 1));

// Check if each dimension exceeds MAX_DIMENSION
w = Math.min(w, MAX_DIMENSION);
h = Math.min(h, MAX_DIMENSION);

// Check the total pixel count
if (w * h > Math.pow(2, 31) - 1) {
const scale = Math.sqrt((Math.pow(2, 31) - 1) / (w * h));
w = Math.floor(w * scale);
h = Math.floor(h * scale);
}

return { width: w, height: h };
}

/**
* Asynchronously loads an image with the specified dimensions.
* Handles string/number dimension types and applies size validation for Android bitmap limitations.
*
* @param {Function} callback - Callback function that receives (image, error)
* @param {{ width?: number; height?: number }} [options] - Optional dimensions for the image
*/
public getImageAsync(callback: (image, error) => void, options?: { width?: number; height?: number }) {
if (options?.width || options?.height) {
const validDimensions = this._validateDimensions(options.width || this.options.width || 0, options.height || this.options.height || 0);
options.width = validDimensions.width;
options.height = validDimensions.height;
}

org.nativescript.widgets.Utils.loadImageAsync(
ad.getApplicationContext(),
this.android,
Expand All @@ -39,7 +90,7 @@ export class ImageAsset extends ImageAssetBase {
onError(ex) {
callback(null, ex);
},
})
}),
);
}
}
4 changes: 2 additions & 2 deletions packages/core/image-asset/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ export class ImageAsset extends Observable {
}

export interface ImageAssetOptions {
width?: number;
height?: number;
width?: number | string;
height?: number | string;
keepAspectRatio?: boolean;
autoScaleFactor?: boolean;
}
26 changes: 25 additions & 1 deletion packages/core/image-asset/index.ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,23 @@ export class ImageAsset extends ImageAssetBase {
this._ios = value;
}

public getImageAsync(callback: (image, error) => void) {
/**
* Asynchronously loads an image and optionally resizes it.
* Handles both string and number type dimensions by converting strings to numbers.
*
* @param {Function} callback - Callback function that receives (image, error)
* @param {{ width?: number|string; height?: number|string }} [options] - Optional dimensions for the image
*/
public getImageAsync(callback: (image, error) => void, options?: { width?: number | string; height?: number | string }) {
if (options) {
if (typeof options.width === 'string') {
options.width = parseInt(options.width, 10);
}
if (typeof options.height === 'string') {
options.height = parseInt(options.height, 10);
}
}

if (!this.ios && !this.nativeImage) {
callback(null, 'Asset cannot be found.');
}
Expand Down Expand Up @@ -60,6 +76,14 @@ export class ImageAsset extends ImageAssetBase {
});
}

/**
* Scales the image to the requested size while respecting device scale factor settings.
*
* @param {UIImage} image - The source UIImage to scale
* @param {{ width: number; height: number }} requestedSize - Target dimensions
* @returns {UIImage} Scaled image
* @private
*/
private scaleImage(image: UIImage, requestedSize: { width: number; height: number }): UIImage {
return NativeScriptUtils.scaleImageWidthHeightScaleFactor(image, requestedSize.width, requestedSize.height, this.options?.autoScaleFactor === false ? 1.0 : 0.0);
}
Expand Down