Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xamarin.Forms Take photo with camera shows wrong orientation and crashes on back button

I am using the Xamarin.Forms Camera sample from here - https://github.com/XForms/Xamarin-Forms-Labs-Samples/tree/master/XF.Labs.CameraSample I am able to select or take a photo.

private async Task SelectPicture()
{
    mediaPicker = DependencyService.Get<IMediaPicker>();
    imageSource = null;
        var mediaFile = await mediaPicker.SelectPhotoAsync(new CameraMediaStorageOptions
            {
                DefaultCamera = CameraDevice.Front,
                MaxPixelDimension = 400
            });
        imageSource = ImageSource.FromStream(() => mediaFile.Source);
        img.Source  = imageSource;

}


private async Task TakePicture()
{
    mediaPicker = DependencyService.Get<IMediaPicker>();
    imageSource = null;
        var mediaFile = await mediaPicker.TakePhotoAsync(new CameraMediaStorageOptions
            {
                DefaultCamera = CameraDevice.Front,
                MaxPixelDimension = 400
            });
        imageSource = ImageSource.FromStream(() => mediaFile.Source);
        img.Source  = imageSource;

}

the code for the image is simply

    img = new Image
    {
        BackgroundColor = Color.White,
        Aspect = Aspect.AspectFit
    };    

There are a couple of issues:

First one. You can take a photo or select a stored one and it will then show it on the page. If you select a photo it displays it correctly, either portrait or landscape. When you take a photo, it only displays in landscape mode, so if the image was taken in portrait, the image shows on the side. This isn't catastrophic, but it would be better to show the image how it was taken.

The second issue is a bit more drastic, if you press the device's back button when you are either in the camera or the image gallery then the screen goes blank and then you get a message stating the app has stopped responding.

I have only tried this on Android so far. Does anyone have any ideas on how I can solve the above problems?

EDIT: I have managed to fix the crashing on back button, but the image still displays on its side for Android, but displays correctly for iOS

like image 226
user1667474 Avatar asked Oct 10 '14 10:10

user1667474


2 Answers

I would venture to guess there are a couple of issues here. One the Xamarin.Forms.Labs dependency injection handler on Android is 1) not checking for needed rotation, 2) is not checking for either external storage or is not handling onActivityCancelled.

The easy solution to your problem would be to use the Xamarin.Mobile Xamarin.Mobile I cannot 100% confirm it will handle everything but if it does this would be a quick and easy solution.

The more difficult option that will give you more control would be to roll your own platform specific implementation. I am not going to go into how DI works either you know or can see the Accessing Native Features

Here is an example of Android take picture with code for figuring out if the storage is external and whether or not rotation is needed.

    protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
    {


        base.OnActivityResult(requestCode, resultCode, data);
        //FinishActivity(requestCode);
        try
        {

        if (resultCode == Result.Ok)
        {
            switch (requestCode)
            {
                case TAKE_PHOTO:
                    {
                        Java.IO.File photo = null;

                        if (isMounted)
                        {

                        photo = new Java.IO.File(Android.OS.Environment.ExternalStorageDirectory.ToString(), SharedLibrary.strPhotoLocation);

                        }
                        else
                        {
                        photo = new Java.IO.File(CacheDir, SharedLibrary.strPhotoLocation);
                        }


                        BitmapFactory.Options options = new BitmapFactory.Options();
                        options.InJustDecodeBounds = true;
                        options.InSampleSize = 4;
                        options.InPurgeable = true;
                        options.InInputShareable = true;                          

                        try
                        {
                            //Cleanup code... removed this in favor of using options.InJustDecodeBounds to get info about the bitmap
                            //instead of creating it twice in memory

                            //Bitmap imageBitmap = BitmapFactory.DecodeFile(photo.AbsolutePath, options);


                            //int w = imageBitmap.Width;
                            //int h = imageBitmap.Height;

                            BitmapFactory.DecodeFile(photo.AbsolutePath, options);
                            int w = options.OutWidth;
                            int h = options.OutHeight;

                            Matrix matrix = new Matrix();
                            matrix.SetRotate(getNeededRotation(photo.AbsolutePath));

                            options.InJustDecodeBounds = false;

                            //Bitmap imageBitmap = Bitmap.CreateBitmap(BitmapFactory.DecodeFile(photo.AbsolutePath, options), 0, 0, w, h, matrix, false);                                                       
                            Bitmap imageBitmap = Bitmap.CreateScaledBitmap(BitmapFactory.DecodeFile(photo.AbsolutePath, options), w, h, false);
                            //...

Get Mounted

     private System.Boolean isMounted
    {
        get
        {
            return       (System.Boolean)Android.OS.Environment.ExternalStorageState.Equals(Android.OS.Environment.MediaMounted);
        }
    }                               

GetRotationNeeded

    private int getNeededRotation(string filepath)
    {
        ExifInterface exif = new ExifInterface(filepath);
        int orientation = exif.GetAttributeInt(ExifInterface.TagOrientation, -1);
        int rotate = 0;
        switch (orientation)
        {
            case 6:
                {
                    rotate = 90;
                    break;
                }
            case 3:
                {
                    rotate = 180;
                    break;
                }
            case 8:
                {
                    rotate = 270;
                    break;
                }
            default:
                {
                    rotate = 0;
                    break;
                }


        }
        exif.Dispose();
        return rotate;
    }
like image 101
ClintL Avatar answered Oct 03 '22 02:10

ClintL


you can check orientation by using 'mediaFile.Exif.Orientation' to check whether it's portrait or Landscape.(' TopLeft'--> Portrait.) And then set photo orientation before saving using,

 mediaFile.Exif.Orientation = ExifLib.ExifOrientation.TopLeft;
like image 23
Asanka Indrajith Avatar answered Oct 03 '22 03:10

Asanka Indrajith