2
votes

I'm writing a Xamarin forms android application where I'm taking images from gallery. I want to upload those images to server, So I need byte[] from it. I'm scaling and compressing those images and then taking byte[] from it. My problem is when I compress the image, the image is changing it's orientation from portrait to landscape. I've tried by using 'ExifInterface' class and changing the image orientation but it's not working. Below is the my complete code :-

protected override async void OnActivityResult (int requestCode, Result resultCode, Intent data)
    {
        if (resultCode == Result.Canceled)
            return;

        try {
            var mediafile = await data.GetMediaFileExtraAsync (Forms.Context);

            byte[] data1 = ReadFully (mediafile.GetStream ());

            byte[] resizedImage = ResizeImageAndroid (data1, 60, 60, mediafile);
            var imageStream = new ByteArrayContent (resizedImage);
            imageStream.Headers.ContentDisposition = new ContentDispositionHeaderValue ("attachment") {
                FileName = Guid.NewGuid () + ".Png"
            };

            var multi = new MultipartContent ();
            multi.Add (imageStream);
            HealthcareProfessionalDataClass lDataClass = HealthcareProfessionalDataClass.Instance;
            lDataClass.Thumbnail = multi;
            App.mByteArrayOfImage = data1;

            System.Diagnostics.Debug.WriteLine (mediafile.Path);

            MessagingCenter.Send<IPictureTaker,string> (this, "picturetaken", mediafile.Path);
        } catch (Java.Lang.Exception e) {
            e.PrintStackTrace ();
        }
    }

public static byte[] ReadFully (System.IO.Stream input)
    {
        using (var ms = new MemoryStream ()) {
            input.CopyTo (ms);
            return ms.ToArray ();
        }
    }

public static byte[] ResizeImageAndroid (byte[] imageData, float width, float height, MediaFile file)
    {
        try {
            // Load the bitmap

            var options = new BitmapFactory.Options ();
            options.InJustDecodeBounds = true;

            // Calculate inSampleSize
            options.InSampleSize = calculateInSampleSize (options, (int)width, (int)height);
            // Decode bitmap with inSampleSize set
            options.InJustDecodeBounds = false;

            Bitmap originalImage = BitmapFactory.DecodeByteArray (imageData, 0, imageData.Length, options);
            Bitmap resizedImage = Bitmap.CreateScaledBitmap (originalImage, (int)width, (int)height, false);


            using (var ms = new MemoryStream ()) {

                resizedImage.Compress (Bitmap.CompressFormat.Png, 0, ms);
                resizedImage = changeOrientation (file, resizedImage);

                return ms.ToArray ();
            }
        } catch (Java.Lang.Exception e) {
            e.PrintStackTrace ();
            return null;
        }
    }

public static int calculateInSampleSize (BitmapFactory.Options options, int reqWidth, int reqHeight)
    {
        // Raw height and width of image
        int height = options.OutHeight;
        int width = options.OutWidth;
        int inSampleSize = 4;

        if (height > reqHeight || width > reqWidth) {

            int halfHeight = height / 2;
            int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                   && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }

static Bitmap changeOrientation (MediaFile mediafile, Bitmap bitmap)
    {
        var exifInterface = new ExifInterface (mediafile.Path);
        int orientation = exifInterface.GetAttributeInt (ExifInterface.TagOrientation, 0);
        var matrix = new Matrix ();
        switch (orientation) {
        case 2:
            matrix.SetScale (-1, 1);
            break;
        case 3:
            matrix.SetRotate (180);
            break;
        case 4:
            matrix.SetRotate (180);
            matrix.PostScale (-1, 1);
            break;
        case 5:
            matrix.SetRotate (90);
            matrix.PostScale (-1, 1);
            break;
        case 6:
            matrix.SetRotate (90);
            break;
        case 7:
            matrix.SetRotate (-90);
            matrix.PostScale (-1, 1);
            break;
        case 8:
            matrix.SetRotate (-90);
            break;
        default:
            return bitmap;
        }

        try {
            Bitmap oriented = Bitmap.CreateBitmap (bitmap, 0, 0, bitmap.Width, bitmap.Height, matrix, true);
            bitmap.Recycle ();
            return oriented;
        } catch (OutOfMemoryError e) {
            e.PrintStackTrace ();
            return bitmap;
        } catch (System.Exception e) {
            System.Diagnostics.Debug.WriteLine (e.Message);
            return bitmap;
        }
    }

If someone have a solution to my problem please let me know.

1

1 Answers

1
votes

I am not sure if I miss read it but it feels the matrix is not being assigned to any image? So any change you make to the matrix you will never see.

The way I went around implementing this was:

    Matrix mtx = new Matrix();
    ExifInterface exif = new ExifInterface(fileName);
    string orientation = exif.GetAttribute(ExifInterface.TagOrientation);

    switch (orientation)
    {
        case "6": // portrait
            mtx.PreRotate(90);
            resizedBitmap = Bitmap.CreateBitmap(resizedBitmap, 0, 0, resizedBitmap.Width, resizedBitmap.Height, mtx, false);
            mtx.Dispose();
            mtx = null;
            break;
        case "1": // landscape
            break;
        case "8": // Selfie ORIENTATION_ROTATE_270 - might need to flip horizontally too...
            mtx.PreRotate(270);
            resizedBitmap = Bitmap.CreateBitmap(resizedBitmap, 0, 0, resizedBitmap.Width, resizedBitmap.Height, mtx, false);
            mtx.Dispose();
            mtx = null;
            break;
    }

This was the matrix .preRotate is assigned to the Bitmap.CreateBitmap(), then you return this resized bitmap. I hope this helps :)