2013-07-23 7 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.S.私は答えをから読んだ:Android camera preview look strange しかし、これは私のために働いていない。

+0

多分あなたはこれを閉じることができ問題 ? – Poutrathor

+0

なぜですか?何が変わったの? – dermoritz

+1

最初に信じる必要はありません.2番目の解決策を試す時間がありません。質問を投稿してから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); 

私は、この作品:)

よろしくお願いいたします

ヘンリック

+0

私はこのコードを使用しています(Api-Demos「CameraPreview」からです)。問題は私のレイアウトに依存していると私はどのようにプレビューを追加すると思いますか? – dermoritz

+0

この回答は非常に有用で、受け入れられるべきです。 – zionpi

+0

@dermoritzレイアウトに問題はありません! 'CameraPreivew.java'クラスの' mCamera.startPreview() 'の上に' mCamera'オブジェクトの1行をパラメータとして設定する必要があります。私のために働く。この回答は受け入れられるべきです! – 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の答えは私のために動作しませんでしたので、私はターゲットビュー現在の幅と高さとも活動を与えられた任意のカメラに最適なプレビューサイズを決定する別の方法を作成しましたオリエンテーション:AndroidのSizeあなたが抑止できるAPI 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; 
    } 

} 

後に利用可能であるため、

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; 
} 

これは、カスタムサイズのオブジェクトを使用していますグローバルレイアウトの変更をリスニングしてビューの幅と高さを確認し、次に新しい寸法を設定することができます。これはまた、プログラムの活動方向をプログラムで決定する方法を示しています:

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; 
    } 

代わりの

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

トリックがあるため90度回転で行われ、幅と高さを交換することです

mCamera.setDisplayOrientation(90); 

によって達成また、あなたが

に設定された向きに応じて子プレビューサイズの設定をフォーク検討するかもしれません
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 
     //... 
    } 

(私のコードでは常に90度回転、180回転では回転を設定しないときは幅と高さを入れ替える必要はありません)

言及する価値もう一つ - ケースのためgetOptimalPreviewSizeを計算するときに回転を持っていて、子の幅と高さを交換するときにも、親を渡す必要があります(PreviewonMeasureに交換された幅と高さ:

if (mSupportedPreviewSizes != null) { 
    //noinspection SuspiciousNameCombination 
    final int previewWidth = height; 
    //noinspection SuspiciousNameCombination 
    final int previewHeight = width; 
    mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, previewWidth, previewHeight); 
} 
関連する問題