ImagePicker set output width and height

Hi,
I’m using ImagePicker to take photos and I ran into one issue: on android the width and height (aprox. 800px by 1100px) of the taken image appears to be the resolution of my phones screen (Moto G4). On iOS I get an image the seems to be more in check with the actuall sensor size (aprox. 3000px by 4000px).
Is there any way to control the output width and height of the taken image.
In my case I would love the image to be relatively small, and since React Native Image Resize is not working on Expo, it would be greate to have some level of control over the images.

Thanks a lot for your help!

1 Like

Hi, unfortunately I don’t think there’s a way to make ImagePicker post-resize the image which was picked right now. That library just wraps the underlying iOS/Android API and returns the result without additional processing.

If you just want to display the image differently in your app you can use properties on the <Image /> component to set its width/height/resize mode.

ping @nikki in case there is some way to postprocess the image that I’m not aware of.

Thanks @ben for your reply!
I was afraid that it wouldn’t work with ImagePicker.
I tried some very hacky way to make it happen in some way by putting the image I took inside an <Image />, hiding that component outside of the viewport and then take a screenshot of the compontent using takeSnapshotAsync:

https://snack.expo.io/S1mlRSrHb

It would be great if you guys could make ReactNativeImageResizer work as an expo component in some of the coming SDKs.

Thanks for your great work.

1 Like

I think https://facebook.github.io/react-native/docs/imageeditor.html should work for this. It can take image size too, the source for that module should detail the option.

Thanks for pointing out the ImageEditor component @nikki, but doesn’t it just cut out a part of an image rather than resizing/scaling it down?
In the docs it says something about cropData as a parameter of cropImage() method, but doesn’t specify what cropData really is. I guess it takes an object, but I don’t know what parameters this object contains. Would be glad if you could help me there.

You can resize the image like this: https://snack.expo.io/SyyDo-rr- notice the resizeMode option.

The only problem is that it will give you a file uri like rct-image-store://6 or you can use ImageStore to get the base64 uri for it. But there isn’t currently a way to save it to disk, but if you’re ok with uploading a base64 encoded image that will work for you.

1 Like

Thank you so much for the greate example @notbrent!
And thanks to the whole Expo team, you made a great tool and give even greater support!

2 Likes

@notbrent i hope it is ok, that i ping you, but your example makes an output of an image with a width of 150x150. :disappointed_relieved:

i just changed

displaySize: { width: 150, height: 150 },

nothing else, but the output-image is 150x150.

But it doesn’t matter how i play with it, contain is not working here, it just takes a square image and cuts everything else off.

It seems like, it is not possible just to resize an image? :neutral_face:

@shuffgy- sorry I don’t understand the question. in the example I shared, it resizes the image to 50x50, not 150x150 :open_mouth:

50x50

400x400

2 Likes

@notbrent that’s because i took your example and just changed that one line i mentioned.

But when i pick an image that has a ratio of 4:3, i dont want an image that is 1:1.

and i have also resizeMode to contain, but i always get an 1:1, that is all covered, not with any border like in your post above.

Now I used the simulator to show you what i mean:
(Android / SDK 18)

What i see now is, that iOS only allows you to crop to square - but i have allowsEditing: false to my ImagePicker anyway.

https://snack.expo.io/ByLIw0sSW - this works on android well

indeed iOS only lets you crop to square, cc @nikki, this would be nice to support on iOS but I’m not sure if the native picker that we lean on supports it

@notbrent I believe this is not for the interactive crop case, it’s for ImageEditor (the user has allowsEditing: false)? Could you clarify, @shuffgy?

@notbrent & @nikki
Thank you for your responses, it helped me to understand cropImage() now. (it took me a moment, sorry :sweat_smile: )

I just wanted to resize an image (no crop), whether it is vertical image or horizontal and the long side of the image has to be like 150px.

That’s why i’m using allowsEditing: false in the imagepicker @nikki

But i made it work! So thanks again for your help. Now I just have to deal with the rct-image-store://0 from iOS. :sweat_smile:

Hi @shuffgy, can you explain how you made it work in your case?

@maximilian-ruppert

here is a snippet of my function that i’m using right now:

The goal was to let the user pic a image of his choice, let the function check if it is vertical or not and resize it the right way (looking for ratio)

watch here for var wantedMaxSize

    _pickImage = async () => {
        let result = await ImagePicker.launchImageLibraryAsync({
            allowsEditing: false
        });

        console.log(result);

        if (!result.cancelled) {

            var wantedMaxSize = 1280;
            var rawheight = result.height;
            var rawwidth = result.width;
            
            var ratio = rawwidth / rawheight;
            // check vertical or horizont
            if(rawheight > rawwidth){
                var wantedwidth = wantedMaxSize*ratio;
                var wantedheight = wantedMaxSize;
            }
            else {
                var wantedwidth = wantedMaxSize;
                var wantedheight = wantedMaxSize/ratio;
            }

            let resizedUri = await new Promise((resolve, reject) => {
                ImageEditor.cropImage(result.uri,
                    {
                        offset: { x: 0, y: 0 },
                        size: { width: result.width, height: result.height },
                        displaySize: { width: wantedwidth, height: wantedheight },
                        resizeMode: 'contain',
                    },
                    (uri) => resolve(uri),
                    () => reject(),
                );
            });
            
            this.setState({ 
                image: resizedUri
            });
        }
    }

For me it is working so I hope that will help you :slight_smile:

1 Like

Thanks for sharing! The code looks very good and I will try it out soon.

1 Like

I thought i might also share my resolution to this issue, Thanks to @shuffgy’s code above, slightly modified to save a base64 string inside of a pouch db without android killing the sync process.

In addition, it also checks for the permission to access the camera roll as well, which is an often missed step.

    _pickImage = async () => {
        //prompt for camera permission
        const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL);
        if (status === 'granted') {
            let result = await ImagePicker.launchImageLibraryAsync({
                mediaTypes: 'Images',
                allowsEditing: false
            });

            // console.log(result);

            if (!result.cancelled) {

                var wantedMaxSize = 1280;
                var rawheight = result.height;
                var rawwidth = result.width;

                var ratio = rawwidth / rawheight;
                // check vertical or horizont
                if(rawheight > rawwidth){
                    var wantedwidth = wantedMaxSize*ratio;
                    var wantedheight = wantedMaxSize;
                }
                else {
                    var wantedwidth = wantedMaxSize;
                    var wantedheight = wantedMaxSize/ratio;
                }

                let resizedBase64 = await new Promise((resolve, reject) => {
                    ImageEditor.cropImage(result.uri,
                    {
                        offset: { x: 0, y: 0 },
                        size: { width: result.width, height: result.height },
                        displaySize: { width: wantedwidth, height: wantedheight },
                        resizeMode: 'contain',
                    },
                    (uri) => {
                        ImageStore.getBase64ForTag(uri,
                        (base64Data) => {
                            resolve('data:image/jpg'+ ';base64,' + base64Data);
                        },
                        (reason) => reject(reason));
                    },
                    () => reject());
                });
               console.log(resizedBase64);
               //store resizedBase64 in db
            }
        }
    }```
2 Likes