1

I'm trying to implement my own camera view like the Camera from "SnapChat". Coming from Xamarin.Forms I'm having a really hard time to understand the problem that I have. Is there any way to keep the full screen and remove the Stretch from the camera view.

Coming from Xamarin.Forms you can easily change the Aspect of the Image in the XAML, I couldn't find any similarly Property in Xamarin.Android. Is there some kind of Property?

Currently testing on Samsung S8+.

The camera view works like expected (Taking Pictures), but the View is Stretched image you can see here enter image description here

this is my View code

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TextureView
        android:id="@+id/textureView"
        android:layout_marginTop="-95dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <Button
        android:id="@+id/toggleFlashButton"
        android:layout_width="37dp"
        android:layout_height="37dp"
        android:layout_gravity="top|left"
        android:layout_marginLeft="25dp"
        android:layout_marginTop="25dp"
        android:background="@drawable/NoFlashButton" />
    <Button
        android:id="@+id/switchCameraButton"
        android:layout_width="35dp"
        android:layout_height="26dp"
        android:layout_gravity="top|right"
        android:layout_marginRight="25dp"
        android:layout_marginTop="25dp"
        android:background="@drawable/ToggleCameraButton" />
    <Button
        android:id="@+id/takePhotoButton"
        android:layout_width="65dp"
        android:layout_height="65dp"
        android:layout_marginBottom="15dp"
        android:layout_gravity="center|bottom"
        android:background="@drawable/TakePhotoButton" />
</FrameLayout>

and this is the code behind

 public class CameraPage : PageRenderer, TextureView.ISurfaceTextureListener {

        #region Fields

        private Activity activity;
        private Camera camera;
        private CameraFacing cameraType;

        private bool flashOn;

        private byte[] imageBytes;
        private SurfaceTexture surfaceTexture;
        private Button switchCameraButton;
        private Button takePhotoButton;
        private TextureView textureView;
        private Button toggleFlashButton;
        private View view;
        #endregion

        #region Functions

        public void OnSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
            try {
                camera = Camera.Open((int)cameraType);

                textureView.LayoutParameters = new FrameLayout.LayoutParams(width, height, GravityFlags.FillVertical);
                surfaceTexture = surface;
                camera.SetPreviewTexture(surface);
                PrepareAndStartCamera();
            }
            catch (Exception ex) {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.StackTrace);
            }
        }

        public bool OnSurfaceTextureDestroyed(SurfaceTexture surface) {
            try {
                camera.StopPreview();
                camera.Release();
                return true;
            }
            catch (Exception ex) {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.StackTrace);
            }
            return true;
        }

        public void OnSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
            PrepareAndStartCamera();
        }

        public void OnSurfaceTextureUpdated(SurfaceTexture surface) {

        }

        protected override void OnElementChanged(ElementChangedEventArgs<Page> e) {
            base.OnElementChanged(e);

            if (e.OldElement != null || Element == null)
                return;

            try {
                activity = Context as Activity;
                view = activity.LayoutInflater.Inflate(Resource.Layout.CameraLayout, this, false);
                cameraType = CameraFacing.Back;

                textureView = view.FindViewById<TextureView>(Resource.Id.textureView);
                textureView.SurfaceTextureListener = this;

                takePhotoButton = view.FindViewById<Button>(Resource.Id.takePhotoButton);
                takePhotoButton.Click += TakePhotoButtonTapped;

                switchCameraButton = view.FindViewById<Button>(Resource.Id.switchCameraButton);
                switchCameraButton.Click += SwitchCameraButtonTapped;

                toggleFlashButton = view.FindViewById<Button>(Resource.Id.toggleFlashButton);
                toggleFlashButton.Click += ToggleFlashButtonTapped;

                AddView(view);
            }
            catch (Exception ex) {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.StackTrace);
            }
        }



        protected override void OnLayout(bool changed, int l, int t, int r, int b) {
            try {
                base.OnLayout(changed, l, t, r, b);

                var msw = MeasureSpec.MakeMeasureSpec(r - l, MeasureSpecMode.AtMost);
                var msh = MeasureSpec.MakeMeasureSpec(b - t, MeasureSpecMode.AtMost);

                view.Measure(msw, msh);
                view.Layout(0, 0, r - l, b - t);
            }
            catch (Exception ex) {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.StackTrace);
            }
        }

        private void PrepareAndStartCamera() {
            try {
                camera.StopPreview();

                var display = activity.WindowManager.DefaultDisplay;

                if (display.Rotation == SurfaceOrientation.Rotation0) camera.SetDisplayOrientation(90);

                if (display.Rotation == SurfaceOrientation.Rotation270) camera.SetDisplayOrientation(180);

                camera.StartPreview();
            }
            catch (Exception ex) {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.StackTrace);
            }
        }

        private void SwitchCameraButtonTapped(object sender, EventArgs e) {
            try {
                if (cameraType == CameraFacing.Front) {
                    cameraType = CameraFacing.Back;

                    camera.StopPreview();
                    camera.Release();
                    camera = Camera.Open((int)cameraType);
                    camera.SetPreviewTexture(surfaceTexture);
                    PrepareAndStartCamera();
                }
                else {
                    cameraType = CameraFacing.Front;

                    camera.StopPreview();
                    camera.Release();
                    camera = Camera.Open((int)cameraType);
                    camera.SetPreviewTexture(surfaceTexture);
                    PrepareAndStartCamera();
                }
            }
            catch (Exception ex) {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.StackTrace);
            }
        }

        private void ToggleFlashButtonTapped(object sender, EventArgs e) {
            try {
                flashOn = !flashOn;
                if (flashOn) {
                    if (cameraType == CameraFacing.Back) {
                        toggleFlashButton.SetBackgroundResource(Resource.Drawable.FlashButton);
                        cameraType = CameraFacing.Back;

                        camera.StopPreview();
                        camera.Release();
                        camera = Camera.Open((int)cameraType);
                        var parameters = camera.GetParameters();
                        parameters.FlashMode = Camera.Parameters.FlashModeTorch;
                        camera.SetParameters(parameters);
                        camera.SetPreviewTexture(surfaceTexture);
                        PrepareAndStartCamera();
                    }
                }
                else {
                    toggleFlashButton.SetBackgroundResource(Resource.Drawable.NoFlashButton);
                    camera.StopPreview();
                    camera.Release();

                    camera = Camera.Open((int)cameraType);
                    var parameters = camera.GetParameters();
                    parameters.FlashMode = Camera.Parameters.FlashModeOff;
                    camera.SetParameters(parameters);
                    camera.SetPreviewTexture(surfaceTexture);
                    PrepareAndStartCamera();
                }
            }
            catch (Exception ex) {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.StackTrace);
            }
        }

        private async void TakePhotoButtonTapped(object sender, EventArgs e) {
            try {
                camera.StopPreview();
                DialogService.ShowLoading("Capturing...");

                var image = textureView.Bitmap;
                using (var imageStream = new MemoryStream()) {
                    await image.CompressAsync(Bitmap.CompressFormat.Png, 75, imageStream);
                    image.Recycle();
                    imageBytes = imageStream.ToArray();
                }


                camera.StartPreview();
                await App.NavigationController.PushAsync(new ImagePreviewView(imageBytes));
                DialogService.HideLoading();
            }
            catch (Exception ex) {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                System.Diagnostics.Debug.WriteLine(ex.StackTrace);
            }
        } 
        #endregion
    }
iNCEPTiON_
  • 611
  • 2
  • 10
  • 27
  • 2
    1) Cameras from different OEMs have different aspect ratios. 2) I do not see where you are getting camera's preview sizes which would be needed to transform the output correctly, there are lots are examples floating around: i.e. https://stackoverflow.com/a/17878832/4984832 – SushiHangover Aug 18 '17 at 10:20
  • I've tested the App on different Devices and the Problems persists on a variety of devices. That's my Problem that I can't find a function or a Property where I can set the Preview Size. – iNCEPTiON_ Aug 18 '17 at 10:24
  • Get the preview size and transform it to the TextureView, read through the existing answers (there are lots ;-) : https://stackoverflow.com/search?q=android+camera+preview+aspect+ratio+textureview – SushiHangover Aug 18 '17 at 10:26
  • Thats what I'm doing the last 2 days :) without any success :) but thanks for the links. – iNCEPTiON_ Aug 18 '17 at 10:28
  • From your code I do not see you get the camera's preview sizes, choosing one, calc'ing the aspect ratio and then transforming to match your TextureView, the answers in those links show you what you need to do.... – SushiHangover Aug 18 '17 at 10:30
  • Managed to get the Optimal Preview Sizes but I can't seem to get it work regardless what I do... so I guess I have to give up ... – iNCEPTiON_ Aug 19 '17 at 13:47

1 Answers1

1

try to get the aspect ratio in onMeasure:

protected void onMeasure(int widthSpec, int heightSpec) {//}

Check the links , Camera Preview Stretched, Camera Preview

try this original here

protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
        {
            // We purposely disregard child measurements because act as a
            // wrapper to a SurfaceView that centers the camera preview instead
            // of stretching it.
            int width = ResolveSize(SuggestedMinimumWidth, widthMeasureSpec);
            int height = ResolveSize(SuggestedMinimumHeight, heightMeasureSpec);
            SetMeasuredDimension(width, height);

            if (_mSupportedPreviewSizes != null)
            {
                _mPreviewSize = GetOptimalPreviewSize(_mSupportedPreviewSizes, width, height);
            }
        }

Check this link :

Camera Preview Stretched on few Devices

Hope this may help you.

Janmejoy
  • 2,721
  • 1
  • 20
  • 38
  • Thank you for your Answer. Based on your Links I've updated my Code but I still can't get it to work :( would you mind taking a look at my Code? https://pastebin.com/p2TY717Y – iNCEPTiON_ Aug 21 '17 at 13:29
  • @iNCEPTiON_try with changing the ASPECT_TOLERANCE with preview sizes.link here https://stackoverflow.com/questions/17804309/android-camera-preview-wrong-aspect-ratio – Janmejoy Aug 21 '17 at 14:20
  • Thanks, Janmejoy. unfortunately, i get the same result. – iNCEPTiON_ Aug 21 '17 at 14:37
  • @iNCEPTiON_check the link https://stackoverflow.com/questions/30049293/camera-preview-stretched-on-few-android-devices – Janmejoy Aug 22 '17 at 06:43
  • Thanks for your help the link you gave me fixed my issue! – iNCEPTiON_ Aug 22 '17 at 08:16