我想为相机预览有效地进行简单的数码变焦,所以我想我只需将SurfaceView的大小调整为大于屏幕。其他问题(例如3813049)似乎表明这很容易,所以我创建了下面的示例代码,我希望能让我只看到水平图像的一半(因为SurfaceView的宽度是屏幕的两倍)并且图像只占水平屏幕的一半。但是,运行它(当我的Thunderbolt上使用Android 2.2.1定位到SDK版本4时)可以在水平填充屏幕时水平查看整个图像。 SurfaceView似乎垂直行为(当我使它小于屏幕时),但Android不允许我使SurfaceView大于屏幕。
如何实现数码变焦? (不,我不能使用Camera.Parameters.setZoom;不仅Android 1.6不支持,但不同的相机支持和实现这一点不同)
public class MagnifyTestActivity extends Activity implements SurfaceHolder.Callback {
private MagnificationView mPreview;
private SurfaceHolder mHolder;
private Camera mCamera = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPreview = new MagnificationView(this);
setContentView(mPreview);
mHolder = mPreview.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public class MagnificationView extends SurfaceView {
public MagnificationView(Context context) {
super(context);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth()*2;
int height = display.getHeight()/2;
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void surfaceCreated(SurfaceHolder holder) {
mCamera = Camera.open();
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
mHolder.setFixedSize(w, h);
mCamera.startPreview();
}
}
更新:基于@Pulkit Sethi的响应,可以垂直拉伸/放大SurfaceView,而不是水平放大/放大。要垂直放大SurfaceView,只需将display.getHeight()/ 2替换为上面的display.getHeight()* 2即可。还要注意,在我的代码或Pulkit中,改变宽度不会产生任何水平放大。
答案 0 :(得分:3)
//Activity class
public class CameraActivity extends Activity implements SurfaceListener {
private static final String TAG = "CameraActivity";
Camera mCamera;
CameraPreview mPreview;
private FrameLayout mCameraPreview;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_camera);
mCamera = getCameraInstance();
mPreview = new CameraPreview(this, mCamera);
mCameraPreview = (FrameLayout) findViewById(R.id.camera_preview);
mCameraPreview.addView(mPreview);
}
@Override
protected void onPause() {
super.onPause();
releaseCamera();
}
private Camera getCameraInstance() {
Camera camera = null;
try {
camera = Camera.open();
} catch (Exception e) {
}
return camera;
}
private void releaseCamera() {
if (null != mCamera) {
mCamera.release();
}
mCamera = null;
}
@Override
public void surfaceCreated() {
//Change these mate
int width = 1000;
int height = 1000;
// Set parent window params
getWindow().setLayout(width, height);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
width, height);
mCameraPreview.setLayoutParams(params);
mCameraPreview.requestLayout();
}
}
// Preview class
public class CameraPreview extends SurfaceView implements
SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
Context mContext;
Camera mCamera;
SurfaceHolder mHolder;
public interface SurfaceListener{
public void surfaceCreated();
}
SurfaceListener listener;
public CameraPreview(Context context, Camera camera) {
super(context);
mContext = context;
listener = (SurfaceListener)mContext;
mCamera = camera;
mHolder = getHolder();
mHolder.addCallback(this);
// Required prior 3.0 HC
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
Parameters params = mCamera.getParameters();
//Change parameters here
mCamera.setParameters(params);
mCamera.startPreview();
listener.surfaceCreated();
} catch (Exception e) {
// TODO: handle exception
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
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.
Log.i(TAG, "Surface changed called");
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
mCamera.setDisplayOrientation(90);
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
//Layout file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="@+id/camera_preview"
android:layout_width="300dp"
android:layout_height="400dp"
android:layout_centerHorizontal="true"
android:paddingTop="10dp" >
</FrameLayout>
</RelativeLayout>
答案 1 :(得分:1)
您无法使SurfaceView比屏幕更大。可以说有很多方法。
我发现你可以在SurfaceView中调整画布的大小,这样就可以进行缩放。
public class DrawingThread extends Thread {
private MagnificationView mainPanel;
private SurfaceHolder surfaceHolder;
private boolean run;
public DrawingThread(SurfaceHolder surface, MagnificationView panel){
surfaceHolder = surface;
mainPanel = panel;
}
public SurfaceHolder getSurfaceHolder(){
return surfaceHolder;
}
public void setRunning (boolean run){
this.run = run;
}
public void run(){
Canvas c;
while (run){
c = null;
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder){
mainPanel.OnDraw(c);
}
} finally {
if (c != null){
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
在MagnificationView类中添加一个方法:
public void OnDraw(Canvas canvas){
if (canvas!=null){
canvas.save();
canvas.scale(scaleX,scaleY);
canvas.restore();
}
}
DrawingThread将是您在Activity中开始的一个主题。同样在您的MagnificationView类中,覆盖OnTouchEvent以处理您自己的缩放缩放(这将修改scaleX&amp; scaleY。
希望这可以解决您的问题
答案 2 :(得分:1)
你可以做的是获取窗口并设置其高度:
getWindow()。setLayout(1000,1000);
这会使您的窗口大于制作根视图的屏幕,因此您的表面视图可能包含在大于屏幕的Framelayout内。
这对我有用,请告诉我。
无论如何,上述都会奏效。你想要做的是为你的表面视图监听onSurfaceCreated事件。然后,在启动摄像机视图后,您可以计算包含预览的窗口小部件的大小,您可能希望更改容器窗口小部件的大小。
概念是你的容器小部件(可能是FrameLayout)想要比屏幕大。屏幕本身受活动限制,因此首先设置窗口大小
然后设置framelayout的大小(它总是缩小到最大窗口大小,所以相应地设置)。
在onSurfaceCreated完成后,我完成了所有这些逻辑我已经开始预览了。我通过实现一个小界面在我的活动中监听这个事件,因为我的Camera预览是一个单独的类。
处理所有API级别&gt; = 8。
答案 3 :(得分:0)
此处我的TouchSurfaceView
onMeasure
执行缩放:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension((int) (width * scaleFactor), (int) (height * scaleFactor));
}
这可以根据scaleFactor正确放大和缩小。
我还没有使用相机对此进行测试,但它与MediaPlayer
(表现为VideoView
)一起正常运行。