Skip to content

iOS unable to get requested image resolution, always getting smaller #26

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

Closed
Daxito opened this issue Jan 23, 2017 · 17 comments
Closed

iOS unable to get requested image resolution, always getting smaller #26

Daxito opened this issue Jan 23, 2017 · 17 comments

Comments

@Daxito
Copy link

Daxito commented Jan 23, 2017

I am not sure what I am doing wrong or maybe this is a bug.
I want to take a picture 2048x1536 but I keep getting an image 320x480.
Please see the attached demo that shows the issue.
I am using an iPhone 4.

CameraTest.zip

@tsonevn tsonevn self-assigned this Jan 30, 2017
@tsonevn
Copy link
Contributor

tsonevn commented Jan 30, 2017

Hi @Daxito,
Thank you for the sample project.

I reviewed your case and found that the image, which has been made has been saved to the gallery and returned in the app with the correct size.

However, the problem comes from the ImageSource, which has been returned from fromAsset method, which will always be with the minimal possible size of the UIImage.

We will research this behavior and will provide further info about the problem and what is causing it.

Regards,
@tsonevn

@tsonevn tsonevn added the bug label Jan 30, 2017
@Daxito
Copy link
Author

Daxito commented Jan 30, 2017

Thank you @tsonevn !

@tsonevn
Copy link
Contributor

tsonevn commented Jan 31, 2017

Hi @Daxito
In my further research, I found that you could use PHImageManager in iOS to get the UIImage with the correct width and height. I am attaching sample code, where have been used PHImageManager and its requestImageForAsset method.

TypeScript

import { Page } from "ui/page";
import { View } from 'ui/core/view';
import { takePicture, requestPermissions } from "nativescript-camera";
import * as appModule from "application";
import * as imageSourceModule from "image-source";
import {Image} from "ui/image"
import {ImageAsset, ImageAssetOptions} from "image-asset"
import {isIOS} from "platform"

declare var UIImage:any;
declare var PHImageManager:any;
declare var PHImageRequestOptions:any;
declare var targetSize:any;
declare var CGSize:any;
declare var PHImageManager:any;
declare var contentMode:any;
declare var PHImageContentModeAspectFill:any;
declare var PHImageRequestOptionsResizeMode, PHImageRequestOptionsDeliveryModeHighQualityFormat;
declare var Environment:any;

declare var java:any;
declare var android:any;

import * as trace from "trace";
trace.addCategories(trace.categories.Debug);
trace.enable();


export function navigatingTo(args: EventData) {
    var page = <Page>args.object;
    let picturePath = null;

    page.bindingContext = fromObject({cameraImage: picturePath, saveToGallery: true});
}

export function onRequestPermissionsTap(args: EventData) {
    requestPermissions();
}

export function onTakePictureTap(args: EventData) {
    let page = <Page>(<View>args.object).page;
    let saveToGallery = page.bindingContext.get("saveToGallery");
    takePicture({width: 2048, height: 1536, keepAspectRatio: false, saveToGallery: saveToGallery}).
        then((imageAsset) => {

            if(isIOS){
                try {

                let manager = PHImageManager.defaultManager()
                let options = new PHImageRequestOptions();
                options.resizeMode = PHImageRequestOptionsResizeMode.Exact;
                options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
                var img;
 
                manager.requestImageForAssetTargetSizeContentModeOptionsResultHandler(imageAsset.ios, { width: 2048, height: 1536 }, PHImageContentModeAspectFill, options, function(result, info) {
                    console.log("Result: " + result + ", info: " + info);
                    img=result;
                });
                
                console.log(img)

                } catch(e) {
                    console.log("err: " + e);
                    console.log("stack: " + e.stack);
                }
            }
   
        }, 
        (err) => {
            console.log("Error -> " + err.message);
        });
}

Regards,
@tsonevn

@Daxito
Copy link
Author

Daxito commented Jan 31, 2017

@tsonevn Thank you for sharing! I'm taking a look at it right now.

@Daxito
Copy link
Author

Daxito commented Jan 31, 2017

FYI: seems like Android has the same issue ;-), It makes sense if you said it might be a problem with the Image Source

@tsonevn
Copy link
Contributor

tsonevn commented Jan 31, 2017

Hi @Daxito,

I was able to reproduce this behavior also on Android. I am still searching for a workaround and will provide further info with possible solution Android.

@tsonevn
Copy link
Contributor

tsonevn commented Feb 1, 2017

Hi @Daxito,

To be able to create image with custom size on Android, you could create Bitmap with appropriate width and height. I am attaching sample with the workaround for this case:

import { EventData, Observable, fromObject } from "data/observable";
import { Page } from "ui/page";
import { View } from 'ui/core/view';
import { takePicture, requestPermissions } from "nativescript-camera";
import * as appModule from "application";
import * as imageSourceModule from "image-source";
import { Image } from "ui/image"
import { ImageAsset, ImageAssetOptions } from "image-asset"
import { isIOS, isAndroid } from "platform"
var application = require("application")

declare var java: any;
declare var android: any;

import * as trace from "trace";
trace.addCategories(trace.categories.Debug);
trace.enable();


export function navigatingTo(args: EventData) {
    var page = <Page>args.object;
    let picturePath = null;

    page.bindingContext = fromObject({ cameraImage: picturePath, saveToGallery: true });
}

export function onRequestPermissionsTap(args: EventData) {
    requestPermissions();
}

export function onTakePictureTap(args: EventData) {
    let page = <Page>(<View>args.object).page;
    let saveToGallery = page.bindingContext.get("saveToGallery");
    takePicture({ width: 2048, height: 1536, keepAspectRatio: false, saveToGallery: saveToGallery }).
        then((imageAsset) => {
            console.log("image asset android")
            console.log(imageAsset.android);

            if (isAndroid) {


                var downsampleOptions = new android.graphics.BitmapFactory.Options();
                downsampleOptions.inSampleSize = getSampleSize(imageAsset.android, { maxWidth: 2048, maxHeight: 1536 });
                var bitmap = android.graphics.BitmapFactory.decodeFile(imageAsset.android, downsampleOptions);
                console.log("bitmap");
                console.log(bitmap);
                console.log("bitmap getWidth");
                console.log(bitmap.getWidth());
                console.log("bitmap getHeight");
                console.log(bitmap.getHeight());
                page.bindingContext.set("cameraImage", bitmap);
            }
            
            
        },
        (err) => {
            console.log("Error -> " + err.message);
        });
}


function getSampleSize(uri, options?: { maxWidth: number, maxHeight: number }): number {
    var scale = 1;
    if (isAndroid) {
        var boundsOptions = new android.graphics.BitmapFactory.Options();
        boundsOptions.inJustDecodeBounds = true;
        android.graphics.BitmapFactory.decodeFile(uri, boundsOptions);

        // Find the correct scale value. It should be the power of 2.
        var outWidth = boundsOptions.outWidth;
        var outHeight = boundsOptions.outHeight;

        if (options) {

            var targetSize = options.maxWidth < options.maxHeight ? options.maxWidth : options.maxHeight;
            while (!(matchesSize(targetSize, outWidth) ||
                matchesSize(targetSize, outHeight))) {
                outWidth /= 2;
                outHeight /= 2;
                scale *= 2;
            }
        }
    }
    return scale;
}


function matchesSize(targetSize: number, actualSize: number): boolean {
    return targetSize && actualSize / 2 < targetSize;
}

Regards,
@tsonevn

@Daxito
Copy link
Author

Daxito commented Feb 1, 2017

Thank you @tsonevn ! I already implemented the workaround for iOS!

Thanks

@ghost
Copy link

ghost commented Sep 16, 2017

@tsonevn any idea how I can convert the final bitmap/asset object to base64 in both cases?

@nmongiya
Copy link

nmongiya commented Oct 5, 2017

In my case, It is taking larger pictures than the size I provided. (In case of both android and ios.)

@DimitarTachev
Copy link

DimitarTachev commented Dec 6, 2017

The above-mentioned issues were caused by the image processing logic in the NativeScript core modules.

@Daxito, you are always getting 320x480 because the logic was restricting the image size to the screen size of the current device.

@nmongiya, you are getting bigger images on Android because the images were read up to 2x the requested size.

All of the image processing issues are now resolved but still now available publicly. You could track the status of these pull requests:

nativescript-core-modules PR
nativescript-core-modules-widgets PR

We can't do anything more inside the camera plugin but will keep this issue opened till the core modules fixes become released.

@p-3
Copy link

p-3 commented Jan 25, 2018

Any status on this when this will be merged in to comming NativeScript core?

@vakrilov
Copy link
Contributor

@p-3 You can expect these PRs to be merged in the next 2 weeks.
(We are in the process of reviewing and merging several PR and these are still waiting on the queue)

@zbranzov
Copy link
Contributor

I'm closing this issue as the PRs fixing it are already merged in the core modules and available in the tns-core-modules@next version. Stay tuned for the official release.

@vicmasa
Copy link

vicmasa commented Jul 9, 2019

I'm closing this issue as the PRs fixing it are already merged in the core modules and available in the tns-core-modules@next version. Stay tuned for the official release.

Hello everyone, I am currently capturing images with the camera, both on Android and IOS, it is not possible to change the size of the image. I await your suggestions. regards

Captura de pantalla 2019-07-09 a la(s) 11 14 17

{ "nativescript": { "id": "org.invianinternational.ViiAMonitoring", "tns-ios": { "version": "5.3.1" }, "tns-android": { "version": "5.3.1" } }, "description": "NativeScript Application", "license": "SEE LICENSE IN <your-license-filename>", "repository": "<fill-your-repository-here>", "scripts": { "lint": "eslint \"app/**/*.js\"" }, "dependencies": { "nativescript-camera": "^4.5.0", "nativescript-carousel": "^4.1.0", "nativescript-feedback": "^1.3.9", "nativescript-imagepicker": "^6.2.0", "nativescript-parallax": "^1.4.0", "nativescript-plugin-firebase": "^9.0.1", "nativescript-social-share": "^1.5.2", "nativescript-sqlite": "^2.3.3", "nativescript-theme-core": "~1.0.4", "nativescript-ui-gauge": "^4.0.0", "nativescript-ui-sidedrawer": "~6.0.0", "rxjs": "~6.3.0", "tns-core-modules": "~5.3.0" }, "devDependencies": { "eslint": "~5.8.0", "nativescript-dev-sass": "~1.7.0", "nativescript-dev-webpack": "~0.21.0" }, "gitHead": "803cec054c44c99eaa59cdc267993e6346f6cb3a", "readme": "NativeScript Application" }

@vytautas-pranskunas-
Copy link

Seems like this issue was fixed few years ago but i still cannot get image smaller.
mu options are:
options: { width: 720, height: 1280, keepAspectRatio: false, saveToGallery: true }

but I am getting this sizeimage: 1890x3360

@vytautas-pranskunas-
Copy link

It looks like it is fixed just device shows size not correct.
I checked that using util: utilsModule.layout.toDeviceIndependentPixels(imageAsset.options.width)
by followinf this issue: #101
and this link: https://docs.nativescript.org/core-concepts/utils#utils

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants