【转】Android自定义照相机实现(拍照、保存到SD卡,利用Bundle在Acitivity交换数据)

好文,亲测完美!

转自:http://blog.csdn.net/wwj_748/article/details/8927784


Android自定义照相机实现

近期小巫在学校有一个创新项目,也不是最近,是一个拖了很久的项目,之前一直没有去搞,最近因为要中期检查,搞得我跟小组成员一阵忙活,其实开发一款照相机软件并不太难,下面就是通过自定义的方式来实现手机照相的功能。

创建一个项目:FingerTakePicture


首先来搞一下界面:

[html]  view plain copy print ?
  1. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:id="@+id/FrameLayout1"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent" >  
  6.     <!-- 显示预览图形 -->  
  7.     <SurfaceView   
  8.         android:id="@+id/surfaceView"  
  9.         android:layout_width="match_parent"  
  10.         android:layout_height="match_parent"  
  11.         />  
  12.     <!-- 相对布局,放置两个按钮 -->  
  13.         <RelativeLayout  
  14.             android:id="@+id/buttonLayout"  
  15.             android:layout_width="wrap_content"  
  16.             android:layout_height="wrap_content"  
  17.             android:visibility="gone"  
  18.         >  
  19.         <!-- 拍照按钮 -->  
  20.         <Button   
  21.             android:id="@+id/takepicture"  
  22.             android:layout_width="wrap_content"  
  23.             android:layout_height="wrap_content"  
  24.             android:layout_alignParentRight="true"  
  25.             android:layout_alignParentBottom="true"  
  26.             android:background="@drawable/btn_tabkepicture_selector"  
  27.             android:onClick="btnOnclick"  
  28.             />  
  29.         <ImageView   
  30.             android:id="@+id/scalePic"  
  31.             android:layout_width="wrap_content"  
  32.             android:layout_height="wrap_content"  
  33.             android:layout_alignParentLeft="true"  
  34.             android:layout_alignParentBottom="true"  
  35.             android:layout_marginLeft="5dp"  
  36.             android:background="@drawable/img_showpic_selector"  
  37.             android:onClick="imageClick"  
  38.             />  
  39.     </RelativeLayout>  
  40. </FrameLayout>  

界面效果 (无法把预览给截屏下来滴):




权限设置少不了:

[html]  view plain copy print ?
  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     package="com.wwj.finger"  
  3.     android:versionCode="1"  
  4.     android:versionName="1.0" >  
  5.   
  6.     <uses-sdk  
  7.         android:minSdkVersion="4"  
  8.         android:targetSdkVersion="15" />  
  9.   
  10.     <uses-permission android:name="android.permission.CAMERA" />  
  11.     <!-- 在SDCard中创建与删除文件权限 -->  
  12.     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />  
  13.     <!-- 往SDCard写入数据权限 -->  
  14.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
  15. <application  
  16.         android:icon="@drawable/ic_launcher"  
  17.         android:label="@string/app_name"  
  18.         android:theme="@style/AppTheme" >  
  19.         <activity  
  20.             android:name=".MainActivity"  
  21.             android:label="@string/title_activity_main"   
  22.             >  
  23.             <intent-filter>  
  24.                 <action android:name="android.intent.action.MAIN" />  
  25.   
  26.                 <category android:name="android.intent.category.LAUNCHER" />  
  27.             </intent-filter>  
  28.         </activity>  
  29.         <activity   
  30.             android:name=".ShowPicActivity"  
  31.             android:label="@string/app_name"  
  32.             android:theme="@style/AppTheme"  
  33.             android:configChanges="orientation|keyboardHidden"  
  34.             ></activity>  
  35.     </application>  
  36.   
  37. </manifest>  

主Activity:

[java]  view plain copy print ?
  1. package com.wwj.finger;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileOutputStream;  
  5. import java.io.IOException;  
  6. import java.text.SimpleDateFormat;  
  7. import java.util.Date;  
  8.   
  9.   
  10. import android.app.Activity;  
  11. import android.content.Intent;  
  12. import android.graphics.PixelFormat;  
  13. import android.hardware.Camera;  
  14. import android.hardware.Camera.PictureCallback;  
  15. import android.os.Bundle;  
  16. import android.os.Environment;  
  17. import android.view.KeyEvent;  
  18. import android.view.MotionEvent;  
  19. import android.view.Surface;  
  20. import android.view.SurfaceHolder;  
  21. import android.view.SurfaceHolder.Callback;  
  22. import android.view.SurfaceView;  
  23. import android.view.View;  
  24. import android.view.ViewGroup;  
  25. import android.widget.Toast;  
  26.   
  27. /** 
  28.  * Android手指拍照 
  29.  *  
  30.  * @author wwj 
  31.  * @date 2013/4/29 
  32.  */  
  33. public class MainActivity extends Activity {  
  34.     private View layout;  
  35.     private Camera camera;  
  36.     private Camera.Parameters parameters = null;  
  37.   
  38.     Bundle bundle = null// 声明一个Bundle对象,用来存储数据  
  39.   
  40.     @Override  
  41.     public void onCreate(Bundle savedInstanceState) {  
  42.         super.onCreate(savedInstanceState);  
  43.         // 显示界面  
  44.         setContentView(R.layout.activity_main);  
  45.   
  46.         layout = this.findViewById(R.id.buttonLayout);  
  47.   
  48.         SurfaceView surfaceView = (SurfaceView) this  
  49.                 .findViewById(R.id.surfaceView);  
  50.         surfaceView.getHolder()  
  51.                 .setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  
  52.         surfaceView.getHolder().setFixedSize(176144); //设置Surface分辨率  
  53.         surfaceView.getHolder().setKeepScreenOn(true);// 屏幕常亮  
  54.         surfaceView.getHolder().addCallback(new SurfaceCallback());//为SurfaceView的句柄添加一个回调函数  
  55.     }  
  56.   
  57.     /** 
  58.      * 按钮被点击触发的事件 
  59.      *  
  60.      * @param v 
  61.      */  
  62.     public void btnOnclick(View v) {  
  63.         if (camera != null) {  
  64.             switch (v.getId()) {  
  65.             case R.id.takepicture:  
  66.                 // 拍照  
  67.                 camera.takePicture(nullnullnew MyPictureCallback());  
  68.                 break;  
  69.             }  
  70.         }  
  71.     }  
  72.   
  73.     /** 
  74.      * 图片被点击触发的时间 
  75.      *  
  76.      * @param v 
  77.      */  
  78.     public void imageClick(View v) {  
  79.         if (v.getId() == R.id.scalePic) {  
  80.             if (bundle == null) {  
  81.                 Toast.makeText(getApplicationContext(), R.string.takephoto,  
  82.                         Toast.LENGTH_SHORT).show();  
  83.             } else {  
  84.                 Intent intent = new Intent(this, ShowPicActivity.class);  
  85.                 intent.putExtras(bundle);  
  86.                 startActivity(intent);  
  87.             }  
  88.         }  
  89.     }  
  90.   
  91.     private final class MyPictureCallback implements PictureCallback {  
  92.   
  93.         @Override  
  94.         public void onPictureTaken(byte[] data, Camera camera) {  
  95.             try {  
  96.                 bundle = new Bundle();  
  97.                 bundle.putByteArray("bytes", data); //将图片字节数据保存在bundle当中,实现数据交换  
  98.                 saveToSDCard(data); // 保存图片到sd卡中  
  99.                 Toast.makeText(getApplicationContext(), R.string.success,  
  100.                         Toast.LENGTH_SHORT).show();  
  101.                 camera.startPreview(); // 拍完照后,重新开始预览  
  102.   
  103.             } catch (Exception e) {  
  104.                 e.printStackTrace();  
  105.             }  
  106.         }  
  107.     }  
  108.   
  109.     /** 
  110.      * 将拍下来的照片存放在SD卡中 
  111.      * @param data   
  112.      * @throws IOException 
  113.      */  
  114.     public static void saveToSDCard(byte[] data) throws IOException {  
  115.         Date date = new Date();  
  116.         SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); // 格式化时间  
  117.         String filename = format.format(date) + ".jpg";  
  118.         File fileFolder = new File(Environment.getExternalStorageDirectory()  
  119.                 + "/finger/");  
  120.         if (!fileFolder.exists()) { // 如果目录不存在,则创建一个名为"finger"的目录  
  121.             fileFolder.mkdir();  
  122.         }  
  123.         File jpgFile = new File(fileFolder, filename);  
  124.         FileOutputStream outputStream = new FileOutputStream(jpgFile); // 文件输出流  
  125.         outputStream.write(data); // 写入sd卡中  
  126.         outputStream.close(); // 关闭输出流  
  127.     }  
  128.   
  129.   
  130.     private final class SurfaceCallback implements Callback {  
  131.   
  132.         // 拍照状态变化时调用该方法  
  133.         @Override  
  134.         public void surfaceChanged(SurfaceHolder holder, int format, int width,  
  135.                 int height) {  
  136.             parameters = camera.getParameters(); // 获取各项参数  
  137.             parameters.setPictureFormat(PixelFormat.JPEG); // 设置图片格式  
  138.             parameters.setPreviewSize(width, height); // 设置预览大小  
  139.             parameters.setPreviewFrameRate(5);  //设置每秒显示4帧  
  140.             parameters.setPictureSize(width, height); // 设置保存的图片尺寸  
  141.             parameters.setJpegQuality(80); // 设置照片质量  
  142.         }  
  143.   
  144.         // 开始拍照时调用该方法  
  145.         @Override  
  146.         public void surfaceCreated(SurfaceHolder holder) {  
  147.             try {  
  148.                 camera = Camera.open(); // 打开摄像头  
  149.                 camera.setPreviewDisplay(holder); // 设置用于显示拍照影像的SurfaceHolder对象  
  150.                 camera.setDisplayOrientation(getPreviewDegree(MainActivity.this));  
  151.                 camera.startPreview(); // 开始预览  
  152.             } catch (Exception e) {  
  153.                 e.printStackTrace();  
  154.             }  
  155.   
  156.         }  
  157.   
  158.         // 停止拍照时调用该方法  
  159.         @Override  
  160.         public void surfaceDestroyed(SurfaceHolder holder) {  
  161.             if (camera != null) {  
  162.                 camera.release(); // 释放照相机  
  163.                 camera = null;  
  164.             }  
  165.         }  
  166.     }  
  167.   
  168.     /** 
  169.      * 点击手机屏幕是,显示两个按钮 
  170.      */  
  171.     @Override  
  172.     public boolean onTouchEvent(MotionEvent event) {  
  173.         switch (event.getAction()) {  
  174.         case MotionEvent.ACTION_DOWN:  
  175.             layout.setVisibility(ViewGroup.VISIBLE); // 设置视图可见  
  176.             break;  
  177.         }  
  178.         return true;  
  179.     }  
  180.   
  181.       
  182.     @Override  
  183.     public boolean onKeyDown(int keyCode, KeyEvent event) {  
  184.         switch (keyCode) {  
  185.         case KeyEvent.KEYCODE_CAMERA: // 按下拍照按钮  
  186.             if (camera != null && event.getRepeatCount() == 0) {  
  187.                 // 拍照  
  188.                 //注:调用takePicture()方法进行拍照是传入了一个PictureCallback对象——当程序获取了拍照所得的图片数据之后  
  189.                 //,PictureCallback对象将会被回调,该对象可以负责对相片进行保存或传入网络  
  190.                 camera.takePicture(nullnullnew MyPictureCallback());  
  191.             }  
  192.         }  
  193.         return super.onKeyDown(keyCode, event);  
  194.     }  
  195.   
  196.     // 提供一个静态方法,用于根据手机方向获得相机预览画面旋转的角度  
  197.     public static int getPreviewDegree(Activity activity) {  
  198.         // 获得手机的方向  
  199.         int rotation = activity.getWindowManager().getDefaultDisplay()  
  200.                 .getRotation();  
  201.         int degree = 0;  
  202.         // 根据手机的方向计算相机预览画面应该选择的角度  
  203.         switch (rotation) {  
  204.         case Surface.ROTATION_0:  
  205.             degree = 90;  
  206.             break;  
  207.         case Surface.ROTATION_90:  
  208.             degree = 0;  
  209.             break;  
  210.         case Surface.ROTATION_180:  
  211.             degree = 270;  
  212.             break;  
  213.         case Surface.ROTATION_270:  
  214.             degree = 180;  
  215.             break;  
  216.         }  
  217.         return degree;  
  218.     }  
  219. }  


用来显示图片的Activity:

[java]  view plain copy print ?
  1. package com.wwj.finger;  
  2.   
  3.   
  4. import android.app.Activity;  
  5. import android.content.Intent;  
  6. import android.graphics.Bitmap;  
  7. import android.graphics.BitmapFactory;  
  8. import android.graphics.Matrix;  
  9. import android.os.Bundle;  
  10. import android.widget.ImageView;  
  11.   
  12. public class ShowPicActivity extends Activity {  
  13.     private ImageView ivPic = null// 显示图片控件  
  14.   
  15.   
  16.     /** 
  17.      * Activity在创建的时候回调的函数 主要用来初始化一些变量 
  18.      */  
  19.     @Override  
  20.     protected void onCreate(Bundle savedInstanceState) {  
  21.         super.onCreate(savedInstanceState);  
  22.         setContentView(R.layout.showpic);  
  23.         ivPic = (ImageView) findViewById(R.id.ivPic);  
  24.         setImageBitmap(getImageFormBundle());  
  25.   
  26.     }  
  27.   
  28.   
  29.     /** 
  30.      * 将MainActivity传过来的图片显示在界面当中 
  31.      *  
  32.      * @param bytes 
  33.      */  
  34.     public void setImageBitmap(byte[] bytes) {  
  35.         Bitmap cameraBitmap = byte2Bitmap();  
  36.         // 根据拍摄的方向旋转图像(纵向拍摄时要需要将图像选择90度)  
  37.         Matrix matrix = new Matrix();  
  38.         matrix.setRotate(MainActivity.getPreviewDegree(this));  
  39.         cameraBitmap = Bitmap  
  40.                 .createBitmap(cameraBitmap, 00, cameraBitmap.getWidth(),  
  41.                         cameraBitmap.getHeight(), matrix, true);  
  42.         ivPic.setImageBitmap(cameraBitmap);  
  43.     }  
  44.   
  45.     /** 
  46.      * 从Bundle对象中获取数据 
  47.      *  
  48.      * @return 
  49.      */  
  50.     public byte[] getImageFormBundle() {  
  51.         Intent intent = getIntent();  
  52.         Bundle data = intent.getExtras();  
  53.         byte[] bytes = data.getByteArray("bytes");  
  54.         return bytes;  
  55.     }  
  56.   
  57.     /** 
  58.      * 将字节数组的图形数据转换为Bitmap 
  59.      *  
  60.      * @return 
  61.      */  
  62.     private Bitmap byte2Bitmap() {  
  63.         byte[] data = getImageFormBundle();  
  64.         // 将byte数组转换成Bitmap对象  
  65.         Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);  
  66.         return bitmap;  
  67.     }  
  68. }  



这是小巫那个创新项目的一小部分,已经完美实现简单的照相机功能了,保存图片不会像有些网友提供的代码给定一个特定的文件名,不能保存多张图片,还特定把一些方法封装了一下,有需要的朋友好好看看吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值