我想使用自定义相机拍摄比预览更小的尺寸,我听说保持纵横比非常重要。我PreviewFrameLayout
在AOSP ICS中使用过。我发现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.
添加了一个问题以解决在使用FrameLayout时拉伸的Camera Preview中的问题
当我将以下代码添加到构造函数中时,Camera PreviewFrameLayout几乎可以完美地工作(几乎是全屏显示)……就在ShutterButton的上方:
public PreviewFrameLayout(Context c,AttributeSet attrs)
{
super(c,attrs);
setAspectRatio(4.0/3.0);
}
仍然存在一些问题,例如在屏幕的显示方向为90的风景中拍照并预览...
我发现尽管使用ExifInterface
和Matrix
来固定此旋转代码,但在横向和纵向模式下,获得的图像仍会沿横向和纵向模式顺时针旋转90度ImagePreviewActivity
Exif方向始终为0,我上次修复了此问题(Parameters.setRotation
设置方向时没有使用代码的PreviewFrameLayout ...但此处似乎不起作用
我看不到那里getOptimalPreviewSize()
叫什么。另外,没有真正的理由设置预览大小以匹配屏幕;通常,制造商会选择默认的相机预览以使其在屏幕上看起来不错(这涉及缩放)。
有了这些,您发布的代码就可以大大简化。如果我理解正确,则您的活动中具有固定的screenOrientation,并希望用相机预览填充所有屏幕,并保留宽高比以匹配所需的图片尺寸。
这个简单的示例显示了如何设置预览曲面视图的宽度和高度。如果您还不够,请随时询问更多详细信息。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句