自定义相机安卓

Posted

技术标签:

【中文标题】自定义相机安卓【英文标题】:Custom camera android 【发布时间】:2012-01-22 12:22:32 【问题描述】:

我想在活动中使用camera preview。我想添加图像(表面视图上的透明框架)。我尝试了以下代码,以便我可以轻松地自定义 xml 布局:

package com.demo;


import java.io.IOException;

import android.app.Activity;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;

public class CameraDemoActivity extends Activity implements SurfaceHolder.Callback
    /** Called when the activity is first created. */
     Camera camera;
     SurfaceView surfaceView;
     SurfaceHolder surfaceHolder;
    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        getWindow().setFormat(PixelFormat.UNKNOWN);
        surfaceView = (SurfaceView)findViewById(R.id.surfaceview);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        camera = Camera.open();
        if(camera!=null)

            try 
             camera.setPreviewDisplay(surfaceHolder);
             camera.startPreview();
             catch (IOException e) 
             Toast.makeText(this, (CharSequence) e, Toast.LENGTH_LONG).show();
            

        


    

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) 
        // TODO Auto-generated method stub

    

    @Override
    public void surfaceCreated(SurfaceHolder holder) 
        // TODO Auto-generated method stub

    

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) 
        // TODO Auto-generated method stub

    

这是我的清单:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.demo"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="8" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".CameraDemoActivity"
                  android:label="@string/app_name" android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-feature android:name="android:hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />
</manifest>

这是我的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_
    android:layout_
    >
<SurfaceView 
android:id="@+id/surfaceview"
android:layout_
android:layout_/>
</LinearLayout>

不知道为什么不显示camera 的预览?

【问题讨论】:

【参考方案1】:

使用此代码

PreviewDemo.java

public class PreviewDemo extends Activity implements OnClickListener 

    private SurfaceView preview = null;
    private SurfaceHolder previewHolder = null;
    private Camera camera = null;
    private boolean inPreview = false;
    ImageView image;
    Bitmap bmp, itembmp;
    static Bitmap mutableBitmap;
    PointF start = new PointF();
    PointF mid = new PointF();
    float oldDist = 1f;
    File imageFileName = null;
    File imageFileFolder = null;
    private MediaScannerConnection msConn;
    Display d;
    int screenhgt, screenwdh;
    ProgressDialog dialog;



    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.preview);

        image = (ImageView) findViewById(R.id.image);
        preview = (SurfaceView) findViewById(R.id.surface);

        previewHolder = preview.getHolder();
        previewHolder.addCallback(surfaceCallback);
        previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        previewHolder.setFixedSize(getWindow().getWindowManager()
            .getDefaultDisplay().getWidth(), getWindow().getWindowManager()
            .getDefaultDisplay().getHeight());


    


    @Override
    public void onResume() 
        super.onResume();
        camera = Camera.open();
    

    @Override
    public void onPause() 
        if (inPreview) 
            camera.stopPreview();
        

        camera.release();
        camera = null;
        inPreview = false;
        super.onPause();
    

    private Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) 
        Camera.Size result = null;
        for (Camera.Size size: parameters.getSupportedPreviewSizes()) 
            if (size.width <= width && size.height <= height) 
                if (result == null) 
                    result = size;
                 else 
                    int resultArea = result.width * result.height;
                    int newArea = size.width * size.height;
                    if (newArea > resultArea) 
                        result = size;
                    
                
            
        
        return (result);
    

    SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() 
        public void surfaceCreated(SurfaceHolder holder) 
            try 
                camera.setPreviewDisplay(previewHolder);
             catch (Throwable t) 
                Log.e("PreviewDemo-surfaceCallback",
                    "Exception in setPreviewDisplay()", t);
                Toast.makeText(PreviewDemo.this, t.getMessage(), Toast.LENGTH_LONG)
                    .show();
            
        

        public void surfaceChanged(SurfaceHolder holder,
        int format, int width,
        int height) 
            Camera.Parameters parameters = camera.getParameters();
            Camera.Size size = getBestPreviewSize(width, height,
            parameters);

            if (size != null) 
                parameters.setPreviewSize(size.width, size.height);
                camera.setParameters(parameters);
                camera.startPreview();
                inPreview = true;
            
        

        public void surfaceDestroyed(SurfaceHolder holder) 
            // no-op
        
    ;


    Camera.PictureCallback photoCallback = new Camera.PictureCallback() 
        public void onPictureTaken(final byte[] data, final Camera camera) 
            dialog = ProgressDialog.show(PreviewDemo.this, "", "Saving Photo");
            new Thread() 
                public void run() 
                    try 
                        Thread.sleep(1000);
                     catch (Exception ex) 
                    onPictureTake(data, camera);
                
            .start();
        
    ;



    public void onPictureTake(byte[] data, Camera camera) 

        bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
        mutableBitmap = bmp.copy(Bitmap.Config.ARGB_8888, true);
        savePhoto(mutableBitmap);
        dialog.dismiss();
    



    class SavePhotoTask extends AsyncTask < byte[], String, String > @Override
        protected String doInBackground(byte[]...jpeg) 
            File photo = new File(Environment.getExternalStorageDirectory(), "photo.jpg");
            if (photo.exists()) 
                photo.delete();
            
            try 
                FileOutputStream fos = new FileOutputStream(photo.getPath());
                fos.write(jpeg[0]);
                fos.close();
             catch (java.io.IOException e) 
                Log.e("PictureDemo", "Exception in photoCallback", e);
            
            return (null);
        
    


    public void savePhoto(Bitmap bmp) 
        imageFileFolder = new File(Environment.getExternalStorageDirectory(), "Rotate");
        imageFileFolder.mkdir();
        FileOutputStream out = null;
        Calendar c = Calendar.getInstance();
        String date = fromInt(c.get(Calendar.MONTH)) + fromInt(c.get(Calendar.DAY_OF_MONTH)) + fromInt(c.get(Calendar.YEAR)) + fromInt(c.get(Calendar.HOUR_OF_DAY)) + fromInt(c.get(Calendar.MINUTE)) + fromInt(c.get(Calendar.SECOND));
        imageFileName = new File(imageFileFolder, date.toString() + ".jpg");
        try 
            out = new FileOutputStream(imageFileName);
            bmp.compress(Bitmap.CompressFormat.JPEG, 100, out);
            out.flush();
            out.close();
            scanPhoto(imageFileName.toString());
            out = null;
         catch (Exception e) 
            e.printStackTrace();
        
    

    public String fromInt(int val) 
        return String.valueOf(val);
    

    public void scanPhoto(final String imageFileName) 
        msConn = new MediaScannerConnection(PreviewDemo.this, new MediaScannerConnectionClient() 
            public void onMediaScannerConnected() 
                msConn.scanFile(imageFileName, null);
                Log.i("msClient obj  in Photo Utility", "connection established");
            
            public void onScanCompleted(String path, Uri uri) 
                msConn.disconnect();
                Log.i("msClient obj in Photo Utility", "scan completed");
            
        );
        msConn.connect();
    

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) 
        if (keyCode == KeyEvent.KEYCODE_MENU && event.getRepeatCount() == 0) 
            onBack();
        
        return super.onKeyDown(keyCode, event);
    

    public void onBack() 
        Log.e("onBack :", "yes");
        camera.takePicture(null, null, photoCallback);
        inPreview = false;
    

    @Override
    public void onClick(View v) 

    


Preview.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_
  android:layout_>

  <android.view.SurfaceView
  android:id="@+id/surface"
  android:layout_
  android:layout_
  />

</RelativeLayout>

使用设备菜单按钮拍照。

在 Manifest 文件中添加权限

检查图片库中的旋转文件夹以获取捕获的图像。

【讨论】:

你能给我完整的 zip 文件吗?只是这个带有按钮的基本摄像头供稿? 你能给我完整的工作项目吗?我无法获得上述完整代码。 非常好的代码。我用 2.3.3 检查了它。在具有“new MediaScannerConnectionClient()”的行上,必须将其更改为“new MediaScannerConnection.MediaScannerConnectionClient() 在 kitkat nexus 4 中尝试过此代码...相机预览调整为 90 dergees..惊讶地看到 你有 image = (ImageView) findViewById(R.id.image);没用过的

以上是关于自定义相机安卓的主要内容,如果未能解决你的问题,请参考以下文章

安卓自定义View进阶-Matrix Camera

安卓自定义View进阶-Matrix Camera

iOS自定义相机界面

使用安卓相机

Android App 自定义相机

为自定义相机转动闪光灯时前置相机崩溃?