title: Camera Size and 4:3 aspect ratio is not matching
body: <p>I am using the Surface View of Camera to show camera and take a photo
  i need the camera preview to be of specific ration 4:3, instagram is a square and mine is a rectangle.</p>
  
  <p>If you look at the instagram app the camera preview is not stretching or compressed, but in mine its compressed.</p>
  
  <p>This is my Camera Preview Class :</p>
  
  <pre><code>class CustomCam extends SurfaceView implements SurfaceHolder.Callback {
  
      private final String TAG = "PIC-FRAME";
      private static final double ASPECT_RATIO = 4.0 / 3.0;
      private static final int PICTURE_SIZE_MAX_WIDTH = 1280;
      private static final int PREVIEW_SIZE_MAX_WIDTH = 640;
  
      private SurfaceHolder mHolder;
      private Camera mCamera;
      private Display display;
      public List&lt;Camera.Size&gt; mSupportedPreviewSizes;
      private Camera.Size mPreviewSize;
  
      public CustomCam(Activity context, Camera camera) {
          super(context);
          mCamera = camera;
          display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
  
          mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
          for (Camera.Size str : mSupportedPreviewSizes)
              Log.e(TAG, str.width + "/" + str.height);
          // Install a SurfaceHolder.Callback so we get notified when the
          // underlying surface is created and destroyed.
          mHolder = getHolder();
          mHolder.addCallback(this);
          // deprecated setting, but required on Android versions prior to 3.0
          mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  
          setKeepScreenOn(true);
      }
  
      public void surfaceDestroyed(SurfaceHolder holder) {
          // empty. Take care of releasing the Camera preview in your activity.
          this.getHolder().removeCallback(this);
      }
  
      @Override
      public void surfaceCreated(SurfaceHolder holder) {
  
      }
  
      private Camera.Size getBestPreviewSize(int width, int height) {
          Camera.Size result = null;
          Camera.Parameters p = mCamera.getParameters();
          for (Camera.Size size : p.getSupportedPreviewSizes()) {
              if (size.width &lt;= width &amp;&amp; size.height &lt;= height) {
                  if (result == null) {
                      result = size;
                  } else {
                      int resultArea = result.width * result.height;
                      int newArea = size.width * size.height;
  
                      if (newArea &gt; resultArea) {
                          result = size;
                      }
                  }
              }
          }
          return result;
  
      }
  
      @Override
      public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
          //This line helped me set the preview Display Orientation to Portrait
          //Only works API Level 8 and higher unfortunately.
  
          try {
              Camera.Parameters parameters = mCamera.getParameters();
  //        Camera.Size size = getBestPreviewSize(width, height);
  //            Camera.Size size = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
  //            parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
  //            initialCameraPictureSize(parameters);
  //            parameters.setPreviewSize(size.width, size.height);
  
              Camera.Size bestPreviewSize = determineBestPreviewSize(parameters);
              Camera.Size bestPictureSize = determineBestPictureSize(parameters);
  
              parameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height);
              parameters.setPictureSize(bestPictureSize.width, bestPictureSize.height);
  
              parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
              mCamera.setDisplayOrientation(90);
              mCamera.getParameters().setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
              mCamera.setPreviewDisplay(mHolder);
              mCamera.setParameters(parameters);
              mCamera.startPreview();
  
          } catch (IOException e) {
              e.printStackTrace();
          }
  
      }
  
      public static void initialCameraPictureSize(Camera.Parameters parameters) {
  
          List list = parameters.getSupportedPictureSizes();
          if (list != null) {
              Camera.Size size = null;
              Iterator iterator = list.iterator();
              do {
                  if (!iterator.hasNext())
                      break;
                  Camera.Size size1 = (Camera.Size) iterator.next();
                  if (Math.abs(3F * ((float) size1.width / 4F) - (float) size1.height) &lt; 0.1F * (float) size1.width &amp;&amp; (size == null || size1.height &gt; size.height &amp;&amp; size1.width &lt; 3000))
                      size = size1;
              } while (true);
              if (size != null)
                  parameters.setPictureSize(size.width, size.height);
              else
                  Log.e("CameraSettings", "No supported picture size found");
          }
      }
  
      private Camera.Size getOptimalPreviewSize(List&lt;Camera.Size&gt; sizes, int w, int h) {
          final double ASPECT_TOLERANCE = 0.1;
          double targetRatio = (double) h / w;
  
          if (sizes == null) return null;
  
          Camera.Size optimalSize = null;
          double minDiff = Double.MAX_VALUE;
  
          int targetHeight = h;
  
          for (Camera.Size size : sizes) {
              double ratio = (double) size.width / size.height;
              if (Math.abs(ratio - targetRatio) &gt; ASPECT_TOLERANCE) continue;
              if (Math.abs(size.height - targetHeight) &lt; minDiff) {
                  optimalSize = size;
                  minDiff = Math.abs(size.height - targetHeight);
              }
          }
  
          if (optimalSize == null) {
              minDiff = Double.MAX_VALUE;
              for (Camera.Size size : sizes) {
                  if (Math.abs(size.height - targetHeight) &lt; minDiff) {
                      optimalSize = size;
                      minDiff = Math.abs(size.height - targetHeight);
                  }
              }
          }
          return optimalSize;
      }
  
      /**
       * Measure the view and its content to determine the measured width and the
       * measured height.
       */
      @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
          int height = MeasureSpec.getSize(heightMeasureSpec);
          int width = MeasureSpec.getSize(widthMeasureSpec);
  
          if (width &gt; height * ASPECT_RATIO) {
              width = (int) (height * ASPECT_RATIO + 0.5);
          } else {
              height = (int) (width / ASPECT_RATIO + 0.5);
          }
  
          setMeasuredDimension(width, height);
      }
  
      protected Camera.Size determineBestSize(List&lt;Camera.Size&gt; sizes, int widthThreshold) {
          Camera.Size bestSize = null;
  
          for (Camera.Size currentSize : sizes) {
              boolean isDesiredRatio = (currentSize.width / 4) == (currentSize.height / 3);
              boolean isBetterSize = (bestSize == null || currentSize.width &gt; bestSize.width);
              boolean isInBounds = currentSize.width &lt;= PICTURE_SIZE_MAX_WIDTH;
  
              if (isDesiredRatio &amp;&amp; isInBounds &amp;&amp; isBetterSize) {
                  bestSize = currentSize;
              }
          }
  
          if (bestSize == null) {
              return sizes.get(0);
          }
  
          return bestSize;
      }
  
      private Camera.Size determineBestPreviewSize(Camera.Parameters parameters) {
          List&lt;Camera.Size&gt; sizes = parameters.getSupportedPreviewSizes();
  
          return determineBestSize(sizes, PREVIEW_SIZE_MAX_WIDTH);
      }
  
      private Camera.Size determineBestPictureSize(Camera.Parameters parameters) {
          List&lt;Camera.Size&gt; sizes = parameters.getSupportedPictureSizes();
  
          return determineBestSize(sizes, PICTURE_SIZE_MAX_WIDTH);
      }
  }
  </code></pre>
  
  <p>My Custom Frame layout :</p>
  
  <pre><code>CustomFrameLayout extends FrameLayout {
  
      private static final float RATIO = 4f / 3f;
  
      public CustomFrameLayout(Context context) {
          super(context);
      }
  
      public CustomFrameLayout(Context context, AttributeSet attrs) {
          super(context, attrs);
      }
  
      public CustomFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
          super(context, attrs, defStyleAttr);
      }
  
      @TargetApi(Build.VERSION_CODES.LOLLIPOP)
      public CustomFrameLayout(Context context, AttributeSet attrs, int defStyleAttr,
                              int defStyleRes) {
          super(context, attrs, defStyleAttr, defStyleRes);
      }
  
      @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
          super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  
          int width = getMeasuredWidth();
          int height = getMeasuredHeight();
          int widthWithoutPadding = width - getPaddingLeft() - getPaddingRight();
          int heigthWithoutPadding = height - getPaddingTop() - getPaddingBottom();
  
          int maxWidth = (int) (heigthWithoutPadding * RATIO);
          int maxHeight = (int) (widthWithoutPadding / RATIO);
  
          if (widthWithoutPadding &gt; maxWidth) {
              width = maxWidth + getPaddingLeft() + getPaddingRight();
          } else {
              height = maxHeight + getPaddingTop() + getPaddingBottom();
          }
  
          setMeasuredDimension(width, height);
      }
  </code></pre>
  
  <p>But the cam preview is compressed inside the frame layout how can i solve this ?issue ? </p>
  
  <p><strong>Update</strong></p>
  
  <p>Ok after some research got to know that its because of onMeasure 
  ASPECT_RATIO = 4:3</p>
  
  <pre><code>@Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
          int height = MeasureSpec.getSize(heightMeasureSpec);
          int width = MeasureSpec.getSize(widthMeasureSpec);
  
          if (width &gt; height * ASPECT_RATIO) {
              width = (int) (height * ASPECT_RATIO + 0.5);
          } else {
              height = (int) (width / ASPECT_RATIO + 0.5);
          }
  
          setMeasuredDimension(width, height);
      }
  </code></pre>
  
  <p><strong>Solution</strong></p>
  
  <p>So i was thinking of a solution, might be (just like Instagram does) to make your camera at full size and then hide some areas of the layout just to make it look like its 4:3 ratio.Then by using some crop mechanism have to cut the image to make the image look like 4:3.</p>
  
  <p>Say i always show preview from top with 4:3 ratio and rest of the below part is hidden, so now as soon as i take photo i want to crop the image from top to 4:3 ratio and save it.</p>
  
  <p>How can i achieve this, is this a feasible solution ?</p>