title: How to change display orientation without messing up preview sizes - android
body: <p>I'm setting up an android app and I want to take pictures of loyalty cards. I want to set the orientation of the camera view to portrait mode and resize the preview. Now I'm able to resize my preview correctly but when i change the orientation (mCamera.setDisplayOrientation(90)) I mess everything up and the preview is stretched horizontally.</p>
  
  <p>My XML:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;android.support.constraint.ConstraintLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".activities.CardCaptureActivity"
  android:background="@color/blue"&gt;
  
  &lt;android.support.v7.widget.CardView
      android:layout_width="0dp"
      android:layout_height="0dp"
      android:layout_marginStart="20dp"
      android:layout_marginTop="8dp"
      android:layout_marginEnd="20dp"
      android:layout_marginBottom="8dp"
      android:elevation="5dp"
      app:cardCornerRadius="15dp"
      app:layout_constraintBottom_toTopOf="@+id/button_capture"
      app:layout_constraintDimensionRatio="H,1.618:1"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      app:layout_constraintVertical_chainStyle="spread"&gt;
  
      &lt;FrameLayout
          android:id="@+id/camera_preview"
          android:layout_width="match_parent"
          android:layout_height="match_parent"/&gt;
  
  &lt;/android.support.v7.widget.CardView&gt;
  
  &lt;Button
      android:id="@+id/button_capture"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_gravity="center"
      android:layout_marginStart="8dp"
      android:layout_marginEnd="8dp"
      android:layout_marginBottom="8dp"
      android:text="Capture"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent" /&gt;
  
  &lt;/android.support.constraint.ConstraintLayout&gt;
  </code></pre>
  
  <p>CardCaptureActivity:</p>
  
  <pre><code>class CardCaptureActivity : AppCompatActivity() {
  
  private var mCamera: Camera? = null
  private var mPreview: CardCameraPreview? = null
  private var captureButton: Button? = null
  
  companion object {
      var data: ByteArray? = null
  }
  
  private val mPicture = Camera.PictureCallback { bytes, camera -&gt;
      CardCaptureActivity.data = bytes
      setResult(CommonStatusCodes.SUCCESS)
      finish()
  }
  
  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_card_capture)
  
      captureButton = findViewById(R.id.button_capture)
      captureButton?.setOnClickListener {
          // get an image from the camera
          mCamera?.takePicture(null, null, mPicture)
      }
  
      mCamera = getCameraInstance()
  
      mPreview = mCamera?.let {
          CardCameraPreview(this, it, findViewById(R.id.camera_preview))
      }
      mPreview?.also {
          val preview: FrameLayout = findViewById(R.id.camera_preview)
          preview.addView(it)
      }
  }
  
  override fun finish() {
      mCamera?.stopPreview()
      mCamera?.release()
      mCamera = null
      super.finish()
  }
  
  override fun onDestroy() {
      mCamera?.stopPreview()
      mCamera?.release()
      mCamera = null
      super.onDestroy()
  }
  
  override fun onStop() {
      mCamera?.stopPreview()
      super.onStop()
  }
  
  /** Check if this device has a camera */
  private fun checkCameraHardware(context: Context): Boolean {
      return context.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)
  }
  
  /** A safe way to get an instance of the Camera object. */
  fun getCameraInstance(): Camera? {
      return try {
          Camera.open() // attempt to get a Camera instance
      } catch (e: Exception) {
          // Camera is not available (in use or does not exist)
          null // returns null if camera is unavailable
      }
  }
  }
  </code></pre>
  
  <p>CardCameraPreview:</p>
  
  <pre><code>class CardCameraPreview(context: Context, private val mCamera: Camera, private val frameLayout: FrameLayout) : SurfaceView(context), SurfaceHolder.Callback{
  
  private val TAG = "CardCameraPreview"
  
  private val mHolder: SurfaceHolder = holder.apply {
      // Install a SurfaceHolder.Callback so we get notified when the
      // underlying surface is created and destroyed.
      addCallback(this@CardCameraPreview)
      // deprecated setting, but required on Android versions prior to 3.0
      setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS)
  }
  
  override fun surfaceCreated(p0: SurfaceHolder?) {
      // The Surface has been created, now tell the camera where to draw the preview.
      mCamera.apply {
          try {
  
              parameters?.also {params -&gt;
                  params.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE
                  parameters = params
              }
  
              setPreviewDisplay(holder)
              startPreview()
          } catch (e: IOException) {
              Log.d(TAG, "Error setting camera preview: ${e.message}")
          }
      }
  }
  
  override fun surfaceDestroyed(holder: SurfaceHolder) {
      // empty. Take care of releasing the Camera preview in your activity.
  }
  
  override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) {
      // If your preview can change or rotate, take care of those events here.
      // Make sure to stop the preview before resizing or reformatting it.
      if (mHolder.surface == null) {
          // preview surface does not exist
          return
      }
  
      // stop preview before making changes
      try {
          mCamera.stopPreview()
      } catch (e: Exception) {
          // ignore: tried to stop a non-existent preview
      }
  
      // set preview size and make any resize, rotate or
      // reformatting changes here
      //mCamera.setDisplayOrientation(90)
  
      val params = mCamera.parameters
      val newSize = getOptimalPreviewSize(params.supportedPreviewSizes, frameLayout.width, frameLayout.height)
      if(newSize != null) {
          params.setPreviewSize(newSize.width, newSize.height)
      }
  
      params.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE
      mCamera.setDisplayOrientation(90)
      mCamera.parameters = params
  
      // start preview with new settings
      mCamera.apply {
          try {
              setPreviewDisplay(mHolder)
              startPreview()
          } catch (e: Exception) {
              Log.d(TAG, "Error starting camera preview: ${e.message}")
          }
      }
  }
  
  private fun getOptimalPreviewSize(sizes: List&lt;Camera.Size&gt;?, width: Int, height: Int): Camera.Size?{
      if(sizes == null)
          return null
  
      val ratio = height.toDouble()/width
      var optimalSize: Camera.Size? = null
      var actualDiff = Double.MAX_VALUE
  
      sizes.forEach { size -&gt;
          val actualRatio = size.height.toDouble() / size.width
  
          if(ratio - actualRatio &lt; actualDiff &amp;&amp; ratio - actualRatio &gt;= 0){
              actualDiff = ratio - actualRatio
              optimalSize = size
          }
          else if(actualRatio - ratio &lt; actualDiff &amp;&amp; actualRatio - ratio &gt;= 0){
              actualDiff = actualRatio - ratio
              optimalSize = size
          }
      }
      return optimalSize
  }
  }
  </code></pre>
  
  <p>The actual result of my code is that the orientation of the preview is correct (potrait) but the preview is stretched horizontally (Image 2). If I delete the line "mCamera.setDisplayOrientation(90)" the preview has the perfect size (nothing stretched or anything like that) but the preview has the wrong orientation (Image 1).
  The expected result is a preview in portrait mode and the preview isn't stretched. </p>
  
  <p>If you are looking at my xml you will see that the preview is  a pretty small rectangle with rounded corners and not the whole screen. That's what I want.</p>
  
  <p><a href="https://i.stack.imgur.com/zwVCz.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/zwVCz.png" alt="result without setting display orientation"></a>
  <a href="https://i.stack.imgur.com/oMkLf.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/oMkLf.png" alt="result with setting display orientation"></a></p>