2013-07-23 4 views
14

나는 튜토리얼을 기반으로 카메라 응용 프로그램을 만들었습니다. 미리보기 클래스는 api-Demos "CameraPreview"에서 사용합니다. here (미리보기는 항상 90 ° 회전 됨)에서 수정 사항을 추가했습니다. 그래서 미리보기 크기를 어떻게 설정합니까?안드로이드 카메라 미리보기 잘못된 가로 세로 비율

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 
    // Now that the size is known, set up the camera parameters and begin 
    // the preview. 
    Camera.Parameters parameters = mCamera.getParameters(); 
    Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); 

    if (display.getRotation() == Surface.ROTATION_0) { 
     parameters.setPreviewSize(mPreviewSize.height, mPreviewSize.width); 
     mCamera.setDisplayOrientation(90); 
    } 

    if (display.getRotation() == Surface.ROTATION_90) { 
     parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); 
    } 

    if (display.getRotation() == Surface.ROTATION_180) { 
     parameters.setPreviewSize(mPreviewSize.height, mPreviewSize.width); 
    } 

    if (display.getRotation() == Surface.ROTATION_270) { 
     parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); 
     mCamera.setDisplayOrientation(180); 
    } 
    parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); 

    requestLayout(); 

    mCamera.setParameters(parameters); 
    mCamera.startPreview(); 
} 

그러나 미리보기가 잘못된 종횡비로 표시됩니다. 이 때문에 위 또는 아마 때문에 내가 사용하는 레이아웃의 코드의인가?

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent" 
android:layout_height="match_parent" > 

<Button 
    android:id="@+id/button_capture" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_alignParentBottom="true" 
    android:text="@string/capture" /> 

<FrameLayout 
    android:id="@+id/camera_preview" 
    android:layout_width="100dp" 
    android:layout_height="match_parent"/> 

어떻게 올바른 가로 세로 비율을 얻는 방법? 미리 감사드립니다.

P. 나는 대답을 읽었다 : Android camera preview look strange 그러나 이것은 나를 위해 일하지 않는다.

+0

어쩌면 당신이 종료 할 수 문제? – Poutrathor

+0

왜? 무엇이 바뀌 었습니까? – dermoritz

+1

처음에는 믿을 필요가 없습니다. 둘째, 다른 솔루션을 시도 할 시간이 없습니다 (질문 게시 후 1 년 간 게시 됨). 다른 답변을 시도하자마자 나는 피드백을 줄 것입니다. 그때까지 모두 괜찮습니다 ... – dermoritz

답변

21

이 기능을 추가하는 미리보기 크기를 변경해보십시오 :

private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) { 
    final double ASPECT_TOLERANCE = 0.05; 
    double targetRatio = (double) w/h; 

    if (sizes==null) return null; 

    Camera.Size optimalSize = null; 

    double minDiff = Double.MAX_VALUE; 

    int targetHeight = h; 

    // Find size 
    for (Camera.Size size : sizes) { 
     double ratio = (double) size.width/size.height; 
     if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; 
     if (Math.abs(size.height - targetHeight) < 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) < minDiff) { 
       optimalSize = size; 
       minDiff = Math.abs(size.height - targetHeight); 
      } 
     } 
    } 
    return optimalSize; 
} 

을 그리고 이러한 최적화 된 값의 크기를 설정 :

List<Camera.Size> sizes = parameters.getSupportedPreviewSizes(); 
Camera.Size optimalSize = getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels); 

parameters.setPreviewSize(optimalSize.width, optimalSize.height); 

나는이 작품 :

안부 희망

Henric

+0

나는 내 질문에이 코드를 사용하고 있습니다 (Api-Demos "CameraPreview"에서 제공). 문제는 레이아웃에 의존하고 미리보기를 추가하는 방법은 무엇입니까? – dermoritz

+0

이 답변은 매우 유용하며 받아 들여야합니다. – zionpi

+0

@dermoritz 레이아웃 문제가 아닙니다! 'CameraPreivew.java' 클래스의'mCamera.startPreview()'위의 한 줄에'mCamera' 객체의 매개 변수 하나를 설정해야합니다. 나를 위해 일합니다. 이 대답을 받아 들여야합니다! – 000000000000000000000

3

다음 코드는 카메라 미리보기의 가로 세로 비율에 맞게 카메라 미리보기 컨테이너의 너비/높이를 수정합니다.

Camera.Size size = camera.getParameters().getPreviewSize(); 

    //landscape 
    float ratio = (float)size.width/size.height; 

    //portrait 
    //float ratio = (float)size.height/size.width; 

    preview = (FrameLayout) findViewById(R.id.camera_preview); 

    int new_width=0, new_height=0; 
    if(preview.getWidth()/preview.getHeight()<ratio){ 
     new_width = Math.round(preview.getHeight()*ratio); 
     new_height = cameraPreview.getHeight(); 
    }else{ 
     new_width = preview.getWidth(); 
     new_height = Math.round(preview.getWidth()/ratio); 
    } 
    preview.setLayoutParams(new FrameLayout.LayoutParams(new_width, new_height)); 
1

위의 솔루션을 사용하여 private size getOptimalPreviewSize (List sizes, int w, int h) 메서드를 사용합니다. 정상적으로 작동했습니다. 세로 방향의 가로 세로 비율에 문제가있었습니다. 여기에서 사용하는 솔루션입니다. 안드로이드의 설명서와 함께 혼합 :

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 
      // 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.getSurface() == null){ 
       // preview surface does not exist 
       return; 
      } 


      // stop preview before making changes 
      try { 
       mCamera.stopPreview(); 
      } catch (Exception e){ 
       // ignore: tried to stop a non-existent preview 
      } 

      // set preview size and make any resize, rotate or 
      // reformatting changes here 
      Camera.Parameters params = mCamera.getParameters(); 
      params.set("orientation", "portrait"); 
      Size optimalSize=getOptimalPreviewSize(params.getSupportedPreviewSizes(), getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels); 
      params.setPreviewSize(optimalSize.width, optimalSize.height); 
      mCamera.setParameters(params); 
      // start preview with new settings 
      try { 

       mCamera.setPreviewDisplay(mHolder); 
       mCamera.startPreview(); 

      } catch (Exception e){ 
       Log.d(TAG, "Error starting camera preview: " + e.getMessage()); 
      } 
     } 
    } 
1

Henric의 대답은 나를 위해 작동하지 않았다, 그래서 목표도 현재 폭과 높이도 활동을 주어진 모든 카메라의 최적의 미리보기 크기를 결정하는 또 다른 방법을 만들었습니다 동향 : 안드로이드의 Size이 API 후에 사용할 수 있기 때문에 이것은 사용자 지정 크기의 객체를 사용

public static Size getOptimalPreviewSize(List<Camera.Size> cameraPreviewSizes, int targetWidth, int targetHeight, boolean isActivityPortrait) { 
    if (CommonUtils.isEmpty(cameraPreviewSizes)) { 
     return null; 
    } 

    int optimalHeight = Integer.MIN_VALUE; 
    int optimalWidth = Integer.MIN_VALUE; 

    for (Camera.Size cameraPreviewSize : cameraPreviewSizes) { 
     boolean isCameraPreviewHeightBigger = cameraPreviewSize.height > cameraPreviewSize.width; 
     int actualCameraWidth = cameraPreviewSize.width; 
     int actualCameraHeight = cameraPreviewSize.height; 

     if (isActivityPortrait) { 
      if (!isCameraPreviewHeightBigger) { 
       int temp = cameraPreviewSize.width; 
       actualCameraWidth = cameraPreviewSize.height; 
       actualCameraHeight = temp; 
      } 
     } else { 
      if (isCameraPreviewHeightBigger) { 
       int temp = cameraPreviewSize.width; 
       actualCameraWidth = cameraPreviewSize.height; 
       actualCameraHeight = temp; 
      } 
     } 

     if (actualCameraWidth > targetWidth || actualCameraHeight > targetHeight) { 
      // finds only smaller preview sizes than target size 
      continue; 
     } 

     if (actualCameraWidth > optimalWidth && actualCameraHeight > optimalHeight) { 
      // finds only better sizes 
      optimalWidth = actualCameraWidth; 
      optimalHeight = actualCameraHeight; 
     } 
    } 

    Size optimalSize = null; 

    if (optimalHeight != Integer.MIN_VALUE && optimalWidth != Integer.MIN_VALUE) { 
     optimalSize = new Size(optimalWidth, optimalHeight); 
    } 

    return optimalSize; 
} 

는 21

public class Size { 

    private int width; 
    private int height; 

    public Size(int width, int height) { 
     this.width = width; 
     this.height = height; 
    } 

    public int getHeight() { 
     return height; 
    } 

    public int getWidth() { 
     return width; 
    } 

} 

당신은 방지 할 수 있습니다 글로벌 레이아웃 변경 사항을 수신하여 뷰의 너비와 높이를 채운 다음 새 치수를 설정할 수 있습니다. 또한 프로그래밍 방식으로 활동 방향을 결정하는 방법을 보여줍니다.

cameraPreviewLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 
      @Override 
      public void onGlobalLayout() { 
       // gets called after layout has been done but before display. 
       cameraPreviewLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this); 

       boolean isActivityPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; 
       Size optimalCameraPreviewSize = CustomUtils.getOptimalPreviewSize(cameraPreview.getCameraSizes(), cameraPreviewLayout.getWidth(), cameraPreviewLayout.getHeight(), isActivityPortrait); 
       if (optimalCameraPreviewSize != null) { 
        LinearLayout.LayoutParams cameraPreviewLayoutParams = new LinearLayout.LayoutParams(optimalCameraPreviewSize.getWidth(), optimalCameraPreviewSize.getHeight()); 
        cameraPreviewLayout.setLayoutParams(cameraPreviewLayoutParams); 
       } 
      } 
     }); 
2

문제는 실제로 레이아웃 것입니다. Preview 클래스에 onLayout가 오버라이드됩니다. 그 작업의 아이디어는 최적의 발견에 따라 SurfaceView 크기를 설정하는 것입니다 Size.

if (mPreviewSize != null) { 
    previewWidth = mPreviewSize.height; 
    previewHeight = mPreviewSize.width; 
    } 

대신 트릭 때문에 90도 회전을 완료 폭과 높이를 교환하는 것입니다

if (mPreviewSize != null) { 
    previewWidth = mPreviewSize.width; 
    previewHeight = mPreviewSize.height; 
    } 

의 : 당신이 스스로 그것을 할 필요가 있도록하지만, 계정으로 회전을지지 않습니다 달성

mCamera.setDisplayOrientation(90); 
당신은 또한 당신이

에서 설정 한 방향에 따라 자식 미리보기 크기 설정을 분기 고려해 볼 수 있습니다

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 
     //... 
    } 

(내 코드는 항상 90도 회전, 180은 임의로 회전 할 필요가 없으며 회전을 설정하지 않으면 너비와 높이를 바꿀 필요가 없음)

언급 할 가치가 또 다른 한가지는 - 경우에 getOptimalPreviewSize을 계산할 때 당신이 회전을 가지고 있고 당신은 또한 onMeasure에서 교환 (Preview) 폭과 높이 부모를 통과해야 아이의 폭과 높이를 바꿀 때

if (mSupportedPreviewSizes != null) { 
    //noinspection SuspiciousNameCombination 
    final int previewWidth = height; 
    //noinspection SuspiciousNameCombination 
    final int previewHeight = width; 
    mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, previewWidth, previewHeight); 
} 
관련 문제