【问题标题】:Camera Preview does not appear full screen(displayed in a box)相机预览不会全屏显示(显示在一个框中)
【发布时间】:2014-01-20 05:12:33
【问题描述】:

我想使用自定义相机拍摄小于预览尺寸的照片,我听说保持纵横比非常重要。我在AOSP ICS中使用了PreviewFrameLayout。我发现SurfaceView 仅显示在活动中心的框内,不会填满整个屏幕。

public class PreviewFrameLayout extends RelativeLayout{

static final String TAG="PreviewFrameLayout";
public interface OnSizeChangedListener
{
    public void onSizeChanged(int w,int h);
}

OnSizeChangedListener mListener;

public void setOnSizeChangedListener(OnSizeChangedListener listener)
{
    mListener=listener;
}

private double mAspectRatio=4.0/3.0;

public PreviewFrameLayout(Context c,AttributeSet attrs)
{
    super(c,attrs);
}

public void setAspectRatio(double ratio)
{
    if(ratio<=0.0)
        throw new IllegalArgumentException();
    if(getResources().getConfiguration().orientation==Configuration.ORIENTATION_PORTRAIT)
        ratio=1/ratio;
    if(mAspectRatio!=ratio)
    {
        mAspectRatio=ratio;
        requestLayout();
    }
}

@Override
protected void onMeasure(int widthSpec,int heightSpec)
{
    int previewWidth=MeasureSpec.getSize(widthSpec);
    int previewHeight=MeasureSpec.getSize(heightSpec);

    int hPadding=getPaddingLeft()+getPaddingRight();
    int vPadding=getPaddingTop()+getPaddingBottom();

    previewWidth-=hPadding;
    previewHeight-=vPadding;

    if(previewWidth>previewHeight*mAspectRatio)
        previewWidth=(int) (previewHeight*mAspectRatio+.5);
    else
        previewHeight=(int)(previewWidth/mAspectRatio+.5);
    previewWidth+=hPadding;
    previewHeight+=vPadding;
    Log.d(TAG,"Aspect ratio "+mAspectRatio);
    Log.d(TAG, "Width: "+previewWidth+" Height: "+previewHeight);
    super.onMeasure(MeasureSpec.makeMeasureSpec(previewWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(previewHeight, MeasureSpec.EXACTLY));
}

protected void onSizeChanged(int w,int h,int oldw,int oldh)
{
    if(mListener!=null)
        mListener.onSizeChanged(w, h);
}
}

并像这样设置预览和图片大小:

  private Size getOptimalPreviewSize(List<Size> supportedSizeList,double targetRatio)
{
    final double ASPECT_TOLERANCE=0.05;
    double minDiff=Double.MAX_VALUE;
    Size optimalSize=null;
    Display display=getWindowManager().getDefaultDisplay();
    @SuppressWarnings("deprecation")
    int targetHeight=Math.min(display.getWidth(), display.getHeight());
    if(targetHeight<=0)
    {   
        WindowManager windowManager=(WindowManager)getSystemService(Context.WINDOW_SERVICE);
        targetHeight=windowManager.getDefaultDisplay().getHeight();
    }
    for(Size size:supportedSizeList)
    {
        double ratio=(double)size.width/size.height;
        if(Math.abs(targetRatio-ratio)>ASPECT_TOLERANCE)
            continue;
        if(Math.abs(size.height-targetHeight)<minDiff)
        {
            optimalSize=size;
            minDiff=Math.abs(size.height-targetHeight);
        }
    }

    for(Size size:supportedSizeList)
    {
        if((Math.abs(size.height-targetHeight))<minDiff)
        {   
            optimalSize=size;
            minDiff=Math.abs(size.height-targetHeight);
        }
    }
    return optimalSize;
}

private Size getDesiredPictureSize(List<Size> supportedSizeList)
{
    //Resolution is widthxheight

    Size result=null;
    final int minArea=500*500;  
    final int maxArea=1000*1000;
    for(Size size:supportedSizeList)
    {
        if(size.width*size.height>minArea && size.width*size.height<maxArea)
        {
            if(result==null)
                result=size;
            else
            {
                int resultArea=result.width*result.height;
                int sizeArea=size.width*size.height;
                if(resultArea<sizeArea)
                {   
                    result=size;
                }   
            }
        }
    }
    return result;
 }

并且我这里使用代码来设置图片大小的纵横比:

    mParameters=mCamera.getParameters();
    List<Size> supportedPictureSizes=mParameters.getSupportedPictureSizes();
    List<Size> supportedPreviewSizes=mParameters.getSupportedPreviewSizes();
    mPictureSize=getDesiredPictureSize(supportedPictureSizes);
    double targetRatio=(double)mPictureSize.width/mPictureSize.height;
    mPreviewPanel=findViewById(R.id.frame_layout);
    mPreviewFrameLayout=(PreviewFrameLayout)findViewById(R.id.frame);
    mPreviewFrameLayout.setAspectRatio(targetRatio);

此布局的父级是RelativeLayout:

<com.example.newcameraproject.PreviewFrameLayout android:id="@+id/frame"
        android:layout_centerInParent="true"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    <SurfaceView android:id="@+id/camera_preview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
      </com.example.newcameraproject.PreviewFrameLayout>

这包含在主摄像头布局中,如下所示:

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

 <include layout="@layout/preview_frame"/>

 </LinearLayout>

编辑:

纵向方向:

CameraActivity(6502): Resolution Width: 720 Resolution Height: 1184
CameraActivity(6502): The Picture Width: 1152 The Picture Height: 864
CameraActivity(6502): The Preview Width:960 Preview Height: 720
CameraActivity(6502): Picture Ratio: 1.3333333333333333
CameraActivity(6502): Preview Ratio: 1.3333333333333333
PreviewFrameLayout(6502): Left: 0 Right: 0 Top: 0 Bottom: 0
PreviewFrameLayout(6502): Aspect ratio 0.75
PreviewFrameLayout(6502): Width: 720 Height: 960

纵横比是倒置的,因为它是纵向的。

if(getResources().getConfiguration().orientation==Configuration.ORIENTATION_PORTRAIT)
        ratio=1/ratio;

相机显示为一个比活动略小的框。

横向方向:

  CameraActivity(6502): Resolution Width: 1196 Resolution Height: 720
  CameraActivity(6502): The Picture Width: 1152 The Picture Height: 864
  CameraActivity(6502): The Preview Width:960 Preview Height: 720
  CameraActivity(6502): Picture Ratio: 1.3333333333333333
  CameraActivity(6502): Preview Ratio: 1.3333333333333333
  PreviewFrameLayout(6502): Left: 0 Right: 0 Top: 0 Bottom: 0
  PreviewFrameLayout(6502): Aspect ratio 1.3333333333333333
  PreviewFrameLayout(6502): Width: 787 Height: 590

 mPreviewSize=getOptimalPreviewSize(this,supportedPreviewSizes, targetRatio);
    Log.d(TAG, "The Preview Width:"+mPreviewSize.width+" Preview Height: "+mPreviewSize.height);
    double ratio=(double)mPreviewSize.width/mPreviewSize.height;
    Log.d(TAG,"Picture Ratio: "+targetRatio);
    Log.d(TAG, "Preview Ratio: "+ratio);
    int new_width=0, new_height=0;    
 if(getResources().getConfiguration().orientation==Configuration.ORIENTATION_PORTRAIT)
    {
        if((double)previewFrame.getWidth()/previewFrame.getHeight()<ratio)
        {
            new_width=(int)(Math.round(previewFrame.getHeight()*ratio));
            new_height=getWindowManager().getDefaultDisplay().getHeight();
        }
        else
        {
            new_width=getWindowManager().getDefaultDisplay().getHeight();
            new_height=(int)Math.round((double)new_width/ratio);
        }
    }
    if(getResources().getConfiguration().orientation==Configuration.ORIENTATION_LANDSCAPE)
    {
        if((double)previewFrame.getWidth()/previewFrame.getHeight()<ratio)
        {
            new_width=(int)(Math.round(previewFrame.getHeight()*ratio));
            new_height=getWindowManager().getDefaultDisplay().getHeight();
        }
        else
        {
            new_width=getWindowManager().getDefaultDisplay().getWidth();
            new_height=(int)Math.round((double)new_width/ratio);
        }
    }

编辑:

1.Ensured that getOptimalPreviewSize and other methods works,changed code outside of this post to do so.
2.Even though these methods now work,the preview was not filling the screen,so changed to FrameLayout.The final version(see above) now works for both landscape and portrait.
3.I have noticed that the image in the preview looks stretched when the Camera Activity is rotated to landscape.

在Camera Preview stretched when using FrameLayout添加了一个问题来解决这个问题

编辑2:

Camera PreviewFrameLayout 工作得几乎完美(几乎是全屏)...当我将此代码添加到构造函数时,就在 ShutterButton 上方:

 public PreviewFrameLayout(Context c,AttributeSet attrs)
{
    super(c,attrs);
    setAspectRatio(4.0/3.0);
}

仍然存在屏幕显示方向为90的横向拍照并预览等问题......

我发现尽管使用ExifInterface 和Matrix 在ImagePreviewActivity 中修复此旋转代码,但在横向和纵向模式下,获得的图像都顺时针旋转了 90 度

Exif 方向始终为 0,我上次修复了这个问题(在设置方向时没有使用 Parameters.setRotation 代码的 PreviewFrameLayout...但它似乎在这里不起作用

【问题讨论】:

  • 你的屏幕的自然分辨率是多少,你的代码写了什么来记录PreviewFrameLayout width和height?
  • 宽度:720 高度:540。我的 Galaxy Nexus 屏幕的自然分辨率是 WXGA (1280 x 800)。虽然getSupportedPreviewSize() 似乎也支持更大的分辨率
  • 您能查看getPaddingLeft() 及其兄弟姐妹报告的内容吗?
  • @AlexCohn PreviewFrameLayout:左:0 右:0 上:0 下:0
  • @AlexCohn 我也尝试过使用最大的图片尺寸like this。预览仍然出现在一个框中

标签: java android android-camera surfaceview aspect-ratio


【解决方案1】:

我看不到getOptimalPreviewSize() 的调用位置;此外,没有真正的理由设置预览大小以匹配屏幕;通常,制造商会选择默认的相机预览以在屏幕上看起来不错(这涉及缩放)。

有了所有这些,您发布的代码可以大大简化。如果我理解正确,您在 Activity 中已修复 screenOrientation,并希望用相机预览填充整个屏幕,并保留宽高比以匹配所需的图片大小。

This simple example,展示了如何设置预览表面视图的宽度和高度。如果这对您来说还不够,请随时询问更多详细信息。

【讨论】:

  • 刚刚在调用updateCameraParameters(int updateSet) 方法之前我没有将mUpdateSet 更改为正确的值。预览更大但仍然没有完全填满屏幕。我们可以使用修复你吗上面描述的是 PreviewFrameLayout 的父级,它是一个 RelativeLayout???
  • 方向也没有固定
  • 是的,如果您真的需要,同样的解决方案也适用于 RelativeLayout。但在你的情况下,FrameLayout 上面甚至没有 LinearLayout 就足够了。
  • 如果是横向的,我们是否需要反转宽度和高度?
  • 用不同的纵向和横向代码编辑,这适用于所有情况吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多