15

縦向きモードでカメラのプレビューが正しく機能するようにしようとしています。このモードでは、アクティビティ自体が通常どおり向きを変更できます (つまり、横向きにロックされません)。

ただし、 を使用するsetDisplayOrientation()と、プレビューの動作が著しく損なわれます。

これは、Google 独自の ApiDemos で実証できます。CameraPreview最初の画像は、サンプル プロジェクトのandroid-17版に基づいていApiDemosます。ここで行った唯一の変更はandroid:orientation="landscape"、マニフェストのこのアクティビティのエントリから削除することでした。次の画像は、Android 4.2 を実行している Nexus 4 のディスプレイに表示されるスクリーンショットです。カメラは 8.5 インチの正方形の紙に向けられています。

Nexus 4 ApiDemos プレビュー、ポートレート モード

そのプレビューから明らかでないのは、90 度回転していることです。画像の右端に見える靴下を履いた足は、実際には正方形の下にありました.

これに対する解決策は、少なくともランドスケープ モードでは、 を使用することsetDisplayOrientation()です。しかし、 のPreview内部クラスCameraPreviewを havemCamera.setDisplayOrientation(90);に変更すると、次のようになります。

Nexus 4 ApiDemos プレビュー、ポートレート モード、setDisplayOrientation(90) を使用

特に、正方形はもはや正方形ではありません。

こちらはSurfaceView以前と同じサイズを使用。以外の他のコードでこのシナリオを再現しましたが、そのコードでApiDemosと同じ動作が得TextureViewられます。

getSupportedPreviewSizes()問題は に基づいて異なる値を返す可能性があるのではないかと簡単に考えましたsetDisplayOrientation()が、簡単なテストではそうではないことが示唆されています。

setDisplayOrientation()プレビューにプッシュされた画像の縦横比を壊さずにポートレート モードで作業する方法を知っている人はいますか?

ありがとう!

4

3 に答える 3

15

わかりました、私はこれを理解したと思います。ことわざのパズルにはいくつかのピースがありました。これを解決するのに役立つ洞察を提供してくれた @kcoppock に感謝します。

まず、選択するプレビュー サイズを決定する際に、向きを考慮する必要があります。たとえば、そのアプリのバージョンの向きが横向きにロックされているという理由だけで、の は向きを認識しませgetOptimalPreviewSize()CameraPreviewApiDemos向きをフロートさせたい場合は、ターゲットの縦横比を逆にして一致させる必要があります。だから、どこgetOptimalPreviewSize()にある:

double targetRatio=(double)width / height;

次も必要です。

if (displayOrientation == 90 || displayOrientation == 270) {
  targetRatio=(double)height / width;
}

wheredisplayOrientationは 0 から 360 の値で、約 100 行の非常に醜いコードから判断しています。そのため、これらすべてを再利用可能なコンポーネントにまとめて、まもなく公開します。そのコードは、setDisplayOrientation()JavaDocsとこの StackOverflow answerに基づいています。

(ところで、2013 年 7 月 1 日以降にこれを読んでいて、そのコンポーネントへのこの回答にリンクが表示されない場合は、忘れていたので、コメントを投稿して思い出させてください)

SurfaceView次に、使用している/の縦横比を制御するときに、そのディスプレイの向きを考慮する必要がありますTextureView。からのCameraPreviewアクティビティには、縦横比を処理するApiDemos独自のPreview ViewGroupものがあり、縦向きで使用するには縦横比を逆にする必要があります。

    if (displayOrientation == 90
        || displayOrientation == 270) {
      previewWidth=mPreviewSize.height;
      previewHeight=mPreviewSize.width;
    }
    else {
      previewWidth=mPreviewSize.width;
      previewHeight=mPreviewSize.height;
    }

ここdisplayOrientationで、同じ値です(それぞれ縦向き90270逆向きの縦向きです。逆向きの縦向きまたは逆向きの横向きを機能させることを試みていないことに注意してください。したがって、さらに調整が必要になる場合があります)。

3 つ目は、私が腹立たしく思っていることですがsetPictureSize()Camera.Parameters. そうしないと、画像の縦横比がプレビュー フレームに適用されて、問題が発生するかのようになります。

そのため、次のようなコードを使用していました。

Camera.Parameters parameters=camera.getParameters();
Camera.Size pictureSize=getHost().getPictureSize(parameters);

parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
parameters.setPictureSize(pictureSize.width, pictureSize.height);
parameters.setPictureFormat(ImageFormat.JPEG);

camera.setParameters(parameters);
camera.startPreview();

それは間違っています。本当に必要なものは次のとおりです。

Camera.Parameters parameters=camera.getParameters();
Camera.Size pictureSize=getHost().getPictureSize(parameters);

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

camera.setParameters(parameters);
camera.startPreview();

parameters=camera.getParameters();
parameters.setPictureSize(pictureSize.width, pictureSize.height);
parameters.setPictureFormat(ImageFormat.JPEG);
camera.setParameters(parameters);

その変更がなければ、横向きであっても縦横比が引き伸ばされます。彼らは写真を撮っていなかったので、これは問題ではありませんCameraPreviewでした。ApiDemossetPictureSize()

しかし、これまでのところ、Nexus 4 では縦向きと横向きの正方形の縦横比があり、向きはフローティング (つまり、横向きに固定されていません) です。

他のデバイスで必要な他のハッキングに遭遇した場合は、この質問を修正することを忘れないようにします。また、リリースされたときにCameraView/コンポーネントにリンクするようにします。CameraFragment


更新 #1

もちろん、これほど単純なことはあり得ません。:-)

アスペクト比を台無しにする問題の修正がsetPictureSize()機能します... 写真を撮るまで。その時点で、プレビューが間違った縦横比に切り替わります。

1 つの可能性は、画像をプレビューと同じ (または非常に近い) 縦横比を持つものに制限することです。ユーザーはカメラが提供する画像サイズを取得できるはずなので、その答えは好きではありません。

次の方法で、損傷の範囲を制限できます。

  • Camera.Parameters撮影直前の画像サイズ等のみ更新
  • 撮影Camera.Parameters後、撮影前に戻す

これは、写真が撮られている間、間違った縦横比を示します。これに対する長期的な解決策は、私が思うに、写真を撮っている間、一時的にカメラのプレビューを静止画像 (最後のプレビュー フレーム) に置き換えることです。私は最終的にこれを試してみます。


更新 #2 :私の CWAC-Camera ライブラリの v0.0.1が利用可能になり、前述のコードが組み込まれました。

于 2013-06-16T12:31:00.760 に答える
1

わかりました、私はこの f* * * 問題についてこの 2 週間本当に頭がおかしくなりました。わかりました、知っておくべきことがいくつかあります:

  • アクションバーまたはソフトボタンが表示されている場合、一部のデバイスで可能です.

@CommonsWare による変更は完璧ですが、API レベル 8 のサンプル(以下のリンク) から CameraPreview に直接適用することはできないため、差分は次のとおりです。

縦向きの正しい縦横比の場合:
メソッドは同じで、diff を適用するだけです。

public void setCamera(Camera camera, boolean portrait) {
    mCamera = camera;
    this.portrait = portrait;
    if (mCamera != null) {
        mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
        requestLayout();
    }
}

public void switchCamera(Camera camera, boolean portrait) throws IOException {
   setCamera(camera, portrait);
   camera.setPreviewDisplay(mHolder);       
   Camera.Parameters parameters = camera.getParameters();
   parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
   requestLayout();

   camera.setParameters(parameters);
}

の:

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {…}

変化する:

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

に:

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

の:

private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {…}

変化する:

double targetRatio = (double) w / h;

に:

double targetRatio = 1;
if (portrait) {
    targetRatio= (double) w / h;
}

最後に、次のようなポートレート モードでカメラを起動します。

try {
     mCamera = openFrontFacingCameraGingerbread();
     if (portraitMode) {
       mCamera.setDisplayOrientation(90);
     }
     preview.setCamera(mCamera, portraitMode);
} catch (Exception e) {
     e.printStackTrace();
     handleCameraUnavailable();
}

ううううう!私にとっては、最終的にプレビューの問題も、画像の保存の問題もありません。アクティビティの場所がロックされているため、正しい向きで画像を保存するために OrientationChangedListener を介してディスプレイの向きを取得します。

次のようなものを使用:
http://www.androidzeitgeist.com/2013/01/fixing-rotation-camera-picture.html

しかし、それらは正しくプレビューされ、保存されます。

API レベル 8の元のコードがあります:
https://android.googlesource.com/platform/development/+/master/samples/ApiDemos/src/com/example/android/ 変更が適用されたapis/graphics/CameraPreview.java

于 2014-03-05T15:09:28.867 に答える
-1

setDisplayorientation()コードのカメラの向きを変更してください。getDisplayOrientation()

if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) 
{   
  camera.setDisplayOrientation(0);

} 
于 2015-04-08T05:40:25.203 に答える