android 自定义照相机

本文介绍了如何在Android中创建一个自定义相机应用,通过调用系统相机并保存拍摄的照片到手机。开发者参考了某个博客并增加了项目特定的功能,实现了一个简单的相机界面布局,包括一个1:1比例的视图,并提供了照片的文件路径返回。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

做了一个dome,内容和功能都很简单,当练练手

部分代码参考了一个博客任何自己添加了一些项目的功能,具体那个博客忘记了,不好意思。

具体就是调用系统的摄相机拍照保存到手机,以后返回相片的文件地址

效果图:





照相界面的布局文件:

 <SurfaceView   
        android:id="@+id/surfaceView"  
        android:layout_width="match_parent"  
        android:layout_height="match_parent"  
        />  
    <!-- 相对布局,放置两个按钮 -->

        <RelativeLayout
            android:id="@+id/buttonLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:visibility="visible" >
            <FrameLayout
	            android:id="@+id/fra_shade_top"
	            android:layout_width="match_parent"
	            android:layout_height="150dp"
	            android:layout_alignParentTop="true"
	            android:background="#000000" />

      	 	<FrameLayout
	            android:id="@+id/fra_shade_bottom"
	            android:layout_width="match_parent"
	            android:layout_height="150dp"
	            android:layout_alignParentBottom="true"
	            android:background="#000000" />
			
			<TableLayout
	            android:id="@+id/table1"
	            android:layout_width="fill_parent"
	            android:layout_height="wrap_content"
	            android:layout_alignParentBottom="true"
	            android:padding="4dip"
	            android:stretchColumns="*" >

            <TableRow>

                <Button
                    android:id="@+id/bnt_enter"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="确认" />

                <Button
                    android:id="@+id/bnt_takepicture"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="拍照" />

                <Button
                    android:id="@+id/bnt_cancel"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="5dp"
                    android:text="取消" />
            </TableRow>
       		</TableLayout>

        </RelativeLayout>
其中SurfaceView是用于显示照相机的图像的。

RelativeLayout是相机的遮罩(设定视图的大小,我这里是1:1正方形)

下面是照相机调用和图片保存类:


/**
 * 
 * 自定义相机控件
 * 
 * @author Nickey
 * @date 2014.11.29
 *
 */
public class MainActivity extends Activity implements OnClickListener{
	  private Button bntTakePic;
	  private Button bntEnter;
	  private Button bntCancel;
	  private SurfaceView surfaceView ;
	  private FrameLayout fraShadeTop;
	  private FrameLayout fraShadeBottom;
	  private Camera camera;  
	  private Camera.Parameters parameters = null;  
	  private WindowManager mWindowManager;
	  private int windowWidth ;//获取手机屏幕宽度
	  private int windowHight ;//获取手机屏幕高度
	  private String savePath = "/finger/";
	  private Bundle bundle = null;// 声明一个Bundle对象,用来存储数据    
	  private int IS_TOOK = 0;//是否已经拍照 ,0为否
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		init();
		getActionBar().hide();
		
		
	}
	
	@SuppressWarnings("deprecation")
	private void init(){
		mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
		windowWidth = mWindowManager.getDefaultDisplay().getWidth();
		windowHight = mWindowManager.getDefaultDisplay().getHeight();
		fraShadeTop = (FrameLayout)findViewById(R.id.fra_shade_top);
		fraShadeBottom = (FrameLayout)findViewById(R.id.fra_shade_bottom);
		RelativeLayout.LayoutParams topParams =(RelativeLayout.LayoutParams) fraShadeTop.getLayoutParams();
		topParams.width = windowWidth;
		topParams.height =(windowHight - windowWidth) / 2;
		fraShadeTop.setLayoutParams(topParams);
		fraShadeTop.getBackground().setAlpha(200);
		
		RelativeLayout.LayoutParams bottomParams =(RelativeLayout.LayoutParams) fraShadeBottom.getLayoutParams();
		bottomParams.width = windowWidth;
		bottomParams.height =(windowHight - windowWidth) / 2;
		fraShadeBottom.setLayoutParams(bottomParams);
		fraShadeBottom.getBackground().setAlpha(200);
		
		//按钮
		bntTakePic = (Button)findViewById(R.id.bnt_takepicture);
		bntEnter = (Button)findViewById(R.id.bnt_enter);
		bntCancel = (Button)findViewById(R.id.bnt_cancel);
		
		bntTakePic.setVisibility(View.VISIBLE);
		bntEnter.setVisibility(View.INVISIBLE);
		bntCancel.setVisibility(View.INVISIBLE);
		bntTakePic.setOnClickListener(this);
		bntEnter.setOnClickListener(this);
		bntCancel.setOnClickListener(this);
		
		//照相机预览的空间
		surfaceView = (SurfaceView) this
				.findViewById(R.id.surfaceView);
		surfaceView.getHolder()
				.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		surfaceView.getHolder().setFixedSize(150, 150); // 设置Surface分辨率
		surfaceView.getHolder().setKeepScreenOn(true);// 屏幕常亮
		surfaceView.getHolder().addCallback(new SurfaceCallback());// 为SurfaceView的句柄添加一个回调函数
	}
	
	/**
	 * 三个按钮点击事件
	 */
	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch (v.getId()) {  
	        case R.id.bnt_takepicture:  
	            // 拍照  
	        	 if (camera != null) {
	        		 camera.takePicture(null, null, new MyPictureCallback());  
	        	 }
	            break;  
	        
			case R.id.bnt_enter:
				 if (bundle == null) {  
	                 Toast.makeText(getApplicationContext(), "bundle null",  
	                         Toast.LENGTH_SHORT).show();  
	             } else {  
	                 try {
	                	if (isHaveSDCard())
	                		saveToSDCard(bundle.getByteArray("bytes"));
	                	else
	                		saveToRoot(bundle.getByteArray("bytes"));
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
	                    	
						finish();
	             }  
	             break; 
			case R.id.bnt_cancel:
				 bntTakePic.setVisibility(View.VISIBLE);
	             bntCancel.setVisibility(View.INVISIBLE);
	             bntEnter.setVisibility(View.INVISIBLE);
				 if (camera != null) {
					 IS_TOOK = 0;
					 camera.startPreview();
				 }
			 break;
		}   
	}

	/**
	 * 检验是否有SD卡
	 * @true or false
	 */
	public static boolean isHaveSDCard() {
		return Environment.MEDIA_MOUNTED.equals(Environment
				.getExternalStorageState());
	}
    
	/**
	 * 重构照相类
	 * @author 
	 *
	 */
    private final class MyPictureCallback implements PictureCallback {  
    	
        @Override  
        public void onPictureTaken(byte[] data, Camera camera) {  
            try {  
                bundle = new Bundle();  
                bundle.putByteArray("bytes", data); //将图片字节数据保存在bundle当中,实现数据交换  
                
           //     saveToSDCard(data); // 保存图片到sd卡中  
                Toast.makeText(getApplicationContext(), "success",  
                        Toast.LENGTH_SHORT).show();  
                bntTakePic.setVisibility(View.INVISIBLE);
                bntCancel.setVisibility(View.VISIBLE);
                bntEnter.setVisibility(View.VISIBLE);
              //  camera.startPreview(); // 拍完照后,重新开始预览  
                IS_TOOK = 1;
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
    }  
	
    /** 
     * 将拍下来的照片存放在SD卡中 
     * @param data   
     * @throws IOException 
     */  
    public void saveToSDCard(byte[] data) throws IOException {  
    	//剪切为正方形
    	Bitmap b = byteToBitmap(data);
    	Bitmap bitmap = Bitmap.createBitmap(b, 0, 0, windowWidth, windowWidth ); 
    	//生成文件
        Date date = new Date();  
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); // 格式化时间  
        String filename = format.format(date) + ".jpg";  
        File fileFolder = new File(Environment.getExternalStorageDirectory()  
                + savePath);  
        if (!fileFolder.exists()) { // 如果目录不存在,则创建一个名为"finger"的目录  
            fileFolder.mkdir();  
        }  
        File jpgFile = new File(fileFolder, filename);  
        FileOutputStream outputStream = new FileOutputStream(jpgFile); // 文件输出流  
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
        outputStream.flush();

        
     //   out.close();
      //  outputStream.write(data); // 写入sd卡中  
        outputStream.close(); // 关闭输出流  
        Intent intent = new Intent();
        intent.putExtra("path",Environment.getExternalStorageDirectory() + savePath + filename);
		setResult(1, intent);
    }  
    
    /**
     * 
     */
    public void saveToRoot(byte[] data) throws IOException {  
    	//剪切为正方形
    	Bitmap b = byteToBitmap(data);
    	Bitmap bitmap = Bitmap.createBitmap(b, 0, 0, windowWidth, windowWidth ); 
    	//生成文件
        Date date = new Date();  
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); // 格式化时间  
        String filename = format.format(date) + ".jpg";  
        File fileFolder = new File(Environment.getRootDirectory()  
                + savePath);  
        if (!fileFolder.exists()) { // 如果目录不存在,则创建一个名为"finger"的目录  
            fileFolder.mkdir();  
        }  
        File jpgFile = new File(fileFolder, filename);  
        FileOutputStream outputStream = new FileOutputStream(jpgFile); // 文件输出流  
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
        outputStream.flush();

        
     //   out.close();
      //  outputStream.write(data); // 写入sd卡中  
        outputStream.close(); // 关闭输出流  
        Intent intent = new Intent();
        intent.putExtra("path",Environment.getExternalStorageDirectory() + savePath + filename);
		setResult(1, intent);
    }  
    
    
    
    /**
     * 把图片byte流编程bitmap
     * @param data
     * @return
     */
	private Bitmap byteToBitmap(byte[] data){
    	Options options = new BitmapFactory.Options();
    	options.inJustDecodeBounds = true;
    	Bitmap b = BitmapFactory.decodeByteArray(data, 0, data.length,options);
		int i = 0;
		while (true) {
			if ((options.outWidth >> i <= 1000)
					&& (options.outHeight >> i <= 1000)) {
				options.inSampleSize = (int) Math.pow(2.0D, i);
				options.inJustDecodeBounds = false;
				b = BitmapFactory.decodeByteArray(data, 0, data.length,options);
				break;
			}
			i += 1;
		}
		return b;

    }
    
	/**
	 * 重构相机照相回调类
	 * @author pc
	 *
	 */
    private final class SurfaceCallback implements Callback {

		@SuppressWarnings("deprecation")
		@Override
		public void surfaceChanged(SurfaceHolder holder, int format, int width,
				int height) {
			// TODO Auto-generated method stub
			parameters = camera.getParameters(); // 获取各项参数  
            parameters.setPictureFormat(PixelFormat.JPEG); // 设置图片格式  
            parameters.setPreviewSize(width, height); // 设置预览大小  
            parameters.setPreviewFrameRate(5);  //设置每秒显示4帧  
            parameters.setPictureSize(width, height); // 设置保存的图片尺寸  
            parameters.setJpegQuality(80); // 设置照片质量  
          //  camera.setParameters(parameters);
		}

		@Override
		public void surfaceCreated(SurfaceHolder holder) {
			// TODO Auto-generated method stub
			try {  
                camera = Camera.open(); // 打开摄像头  
                camera.setPreviewDisplay(holder); // 设置用于显示拍照影像的SurfaceHolder对象  
                camera.setDisplayOrientation(getPreviewDegree(MainActivity.this));  
                camera.startPreview(); // 开始预览  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
		}

		@Override
		public void surfaceDestroyed(SurfaceHolder holder) {
			// TODO Auto-generated method stub
			if (camera != null) {  
                camera.release(); // 释放照相机  
                camera = null;  
            }  
		} 
    	
    	
    	
    }
    

  /**
   * 物理按键事件
   */
      
    @Override  
    public boolean onKeyDown(int keyCode, KeyEvent event) {  
        switch (keyCode) {  
        case KeyEvent.KEYCODE_CAMERA: // 按下拍照按钮  
            if (camera != null && event.getRepeatCount() == 0) {  
                // 拍照  
                //注:调用takePicture()方法进行拍照是传入了一个PictureCallback对象——当程序获取了拍照所得的图片数据之后  
                //,PictureCallback对象将会被回调,该对象可以负责对相片进行保存或传入网络  
                camera.takePicture(null, null, new MyPictureCallback());  
            } 
        case KeyEvent.KEYCODE_BACK:
        	if (IS_TOOK == 0)
        		finish();
        	else{
        	//	camera.startPreview();
        		bntCancel.performClick();
        		return false;
        	}
        	
        	break;
        	
        }  
        
        return super.onKeyDown(keyCode, event);  
    }  
    
    // 提供一个静态方法,用于根据手机方向获得相机预览画面旋转的角度  
    public static int getPreviewDegree(Activity activity) {  
        // 获得手机的方向  
        int rotation = activity.getWindowManager().getDefaultDisplay()  
                .getRotation();  
        int degree = 0;  
        // 根据手机的方向计算相机预览画面应该选择的角度  
        switch (rotation) {  
        case Surface.ROTATION_0:  
            degree = 90;  
            break;  
        case Surface.ROTATION_90:  
            degree = 0;  
            break;  
        case Surface.ROTATION_180:  
            degree = 270;  
            break;  
        case Surface.ROTATION_270:  
            degree = 180;  
            break;  
        }  
        return degree;  
    }  
    
    


	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	/**
	 * 通过文件地址获取文件的bitmap
	 * @param path
	 * @return
	 * @throws IOException
	 */
	
	public static Bitmap getBitmapByPath(String path) throws IOException {
		BufferedInputStream in = new BufferedInputStream(new FileInputStream(
				new File(path)));
		BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeStream(in, null, options);
		in.close();
		int i = 0;
		Bitmap bitmap = null;
		while (true) {
			if ((options.outWidth >> i <= 1000)
					&& (options.outHeight >> i <= 1000)) {
				in = new BufferedInputStream(
						new FileInputStream(new File(path)));
				options.inSampleSize = (int) Math.pow(2.0D, i);
				options.inJustDecodeBounds = false;
				bitmap = BitmapFactory.decodeStream(in, null, options);
				break;
			}
			i += 1;
		}
		return bitmap;
	}


}



具体的使用很简单,就是普通的activity间的调用和回调(startActivityForResult);



评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值