Android自定義照相機(jī)的實(shí)例
Android自定義照相機(jī)實(shí)現(xiàn)
近期小巫在學(xué)校有一個(gè)創(chuàng)新項(xiàng)目,也不是最近,是一個(gè)拖了很久的項(xiàng)目,之前一直沒(méi)有去搞,最近因?yàn)橐衅跈z查,搞得我跟小組成員一陣忙活,其實(shí)開(kāi)發(fā)一款照相機(jī)軟件并不太難,下面就是通過(guò)自定義的方式來(lái)實(shí)現(xiàn)手機(jī)照相的功能。
創(chuàng)建一個(gè)項(xiàng)目:FingerTakePicture
首先來(lái)搞一下界面:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/FrameLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- 顯示預(yù)覽圖形 -->
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<!-- 相對(duì)布局,放置兩個(gè)按鈕 -->
<RelativeLayout
android:id="@+id/buttonLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
>
<!-- 拍照按鈕 -->
<Button
android:id="@+id/takepicture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:background="@drawable/btn_tabkepicture_selector"
android:onClick="btnOnclick"
/>
<ImageView
android:id="@+id/scalePic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:layout_marginLeft="5dp"
android:background="@drawable/img_showpic_selector"
android:onClick="imageClick"
/>
</RelativeLayout>
</FrameLayout>
界面效果(無(wú)法把預(yù)覽給截屏下來(lái)滴):

權(quán)限設(shè)置少不了:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.wwj.finger"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="4"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.CAMERA" />
<!-- 在SDCard中創(chuàng)建與刪除文件權(quán)限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!-- 往SDCard寫(xiě)入數(shù)據(jù)權(quán)限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ShowPicActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme"
android:configChanges="orientation|keyboardHidden"
></activity>
</application>
</manifest>
主Activity:
package com.wwj.finger;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.app.Activity;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.os.Bundle;
import android.os.Environment;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
/**
* Android手指拍照
*
* @author wwj
* @date 2013/4/29
*/
public class MainActivity extends Activity {
private View layout;
private Camera camera;
private Camera.Parameters parameters = null;
Bundle bundle = null; // 聲明一個(gè)Bundle對(duì)象,用來(lái)存儲(chǔ)數(shù)據(jù)
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 顯示界面
setContentView(R.layout.activity_main);
layout = this.findViewById(R.id.buttonLayout);
SurfaceView surfaceView = (SurfaceView) this
.findViewById(R.id.surfaceView);
surfaceView.getHolder()
.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceView.getHolder().setFixedSize(176, 144); //設(shè)置Surface分辨率
surfaceView.getHolder().setKeepScreenOn(true);// 屏幕常亮
surfaceView.getHolder().addCallback(new SurfaceCallback());//為SurfaceView的句柄添加一個(gè)回調(diào)函數(shù)
}
/**
* 按鈕被點(diǎn)擊觸發(fā)的事件
*
* @param v
*/
public void btnOnclick(View v) {
if (camera != null) {
switch (v.getId()) {
case R.id.takepicture:
// 拍照
camera.takePicture(null, null, new MyPictureCallback());
break;
}
}
}
/**
* 圖片被點(diǎn)擊觸發(fā)的時(shí)間
*
* @param v
*/
public void imageClick(View v) {
if (v.getId() == R.id.scalePic) {
if (bundle == null) {
Toast.makeText(getApplicationContext(), R.string.takephoto,
Toast.LENGTH_SHORT).show();
} else {
Intent intent = new Intent(this, ShowPicActivity.class);
intent.putExtras(bundle);
startActivity(intent);
}
}
}
private final class MyPictureCallback implements PictureCallback {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
try {
bundle = new Bundle();
bundle.putByteArray("bytes", data); //將圖片字節(jié)數(shù)據(jù)保存在bundle當(dāng)中,實(shí)現(xiàn)數(shù)據(jù)交換
saveToSDCard(data); // 保存圖片到sd卡中
Toast.makeText(getApplicationContext(), R.string.success,
Toast.LENGTH_SHORT).show();
camera.startPreview(); // 拍完照后,重新開(kāi)始預(yù)覽
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 將拍下來(lái)的照片存放在SD卡中
* @param data
* @throws IOException
*/
public static void saveToSDCard(byte[] data) throws IOException {
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); // 格式化時(shí)間
String filename = format.format(date) + ".jpg";
File fileFolder = new File(Environment.getExternalStorageDirectory()
+ "/finger/");
if (!fileFolder.exists()) { // 如果目錄不存在,則創(chuàng)建一個(gè)名為"finger"的目錄
fileFolder.mkdir();
}
File jpgFile = new File(fileFolder, filename);
FileOutputStream outputStream = new FileOutputStream(jpgFile); // 文件輸出流
outputStream.write(data); // 寫(xiě)入sd卡中
outputStream.close(); // 關(guān)閉輸出流
}
private final class SurfaceCallback implements Callback {
// 拍照狀態(tài)變化時(shí)調(diào)用該方法
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
parameters = camera.getParameters(); // 獲取各項(xiàng)參數(shù)
parameters.setPictureFormat(PixelFormat.JPEG); // 設(shè)置圖片格式
parameters.setPreviewSize(width, height); // 設(shè)置預(yù)覽大小
parameters.setPreviewFrameRate(5); //設(shè)置每秒顯示4幀
parameters.setPictureSize(width, height); // 設(shè)置保存的圖片尺寸
parameters.setJpegQuality(80); // 設(shè)置照片質(zhì)量
}
// 開(kāi)始拍照時(shí)調(diào)用該方法
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera = Camera.open(); // 打開(kāi)攝像頭
camera.setPreviewDisplay(holder); // 設(shè)置用于顯示拍照影像的SurfaceHolder對(duì)象
camera.setDisplayOrientation(getPreviewDegree(MainActivity.this));
camera.startPreview(); // 開(kāi)始預(yù)覽
} catch (Exception e) {
e.printStackTrace();
}
}
// 停止拍照時(shí)調(diào)用該方法
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (camera != null) {
camera.release(); // 釋放照相機(jī)
camera = null;
}
}
}
/**
* 點(diǎn)擊手機(jī)屏幕是,顯示兩個(gè)按鈕
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
layout.setVisibility(ViewGroup.VISIBLE); // 設(shè)置視圖可見(jiàn)
break;
}
return true;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_CAMERA: // 按下拍照按鈕
if (camera != null && event.getRepeatCount() == 0) {
// 拍照
//注:調(diào)用takePicture()方法進(jìn)行拍照是傳入了一個(gè)PictureCallback對(duì)象——當(dāng)程序獲取了拍照所得的圖片數(shù)據(jù)之后
//,PictureCallback對(duì)象將會(huì)被回調(diào),該對(duì)象可以負(fù)責(zé)對(duì)相片進(jìn)行保存或傳入網(wǎng)絡(luò)
camera.takePicture(null, null, new MyPictureCallback());
}
}
return super.onKeyDown(keyCode, event);
}
// 提供一個(gè)靜態(tài)方法,用于根據(jù)手機(jī)方向獲得相機(jī)預(yù)覽畫(huà)面旋轉(zhuǎn)的角度
public static int getPreviewDegree(Activity activity) {
// 獲得手機(jī)的方向
int rotation = activity.getWindowManager().getDefaultDisplay()
.getRotation();
int degree = 0;
// 根據(jù)手機(jī)的方向計(jì)算相機(jī)預(yù)覽畫(huà)面應(yīng)該選擇的角度
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;
}
}
用來(lái)顯示圖片的Activity:
package com.wwj.finger;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.os.Bundle;
import android.widget.ImageView;
public class ShowPicActivity extends Activity {
private ImageView ivPic = null; // 顯示圖片控件
/**
* Activity在創(chuàng)建的時(shí)候回調(diào)的函數(shù) 主要用來(lái)初始化一些變量
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.showpic);
ivPic = (ImageView) findViewById(R.id.ivPic);
setImageBitmap(getImageFormBundle());
}
/**
* 將MainActivity傳過(guò)來(lái)的圖片顯示在界面當(dāng)中
*
* @param bytes
*/
public void setImageBitmap(byte[] bytes) {
Bitmap cameraBitmap = byte2Bitmap();
// 根據(jù)拍攝的方向旋轉(zhuǎn)圖像(縱向拍攝時(shí)要需要將圖像選擇90度)
Matrix matrix = new Matrix();
matrix.setRotate(MainActivity.getPreviewDegree(this));
cameraBitmap = Bitmap
.createBitmap(cameraBitmap, 0, 0, cameraBitmap.getWidth(),
cameraBitmap.getHeight(), matrix, true);
ivPic.setImageBitmap(cameraBitmap);
}
/**
* 從Bundle對(duì)象中獲取數(shù)據(jù)
*
* @return
*/
public byte[] getImageFormBundle() {
Intent intent = getIntent();
Bundle data = intent.getExtras();
byte[] bytes = data.getByteArray("bytes");
return bytes;
}
/**
* 將字節(jié)數(shù)組的圖形數(shù)據(jù)轉(zhuǎn)換為Bitmap
*
* @return
*/
private Bitmap byte2Bitmap() {
byte[] data = getImageFormBundle();
// 將byte數(shù)組轉(zhuǎn)換成Bitmap對(duì)象
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
return bitmap;
}
}
這是小巫那個(gè)創(chuàng)新項(xiàng)目的一小部分,已經(jīng)完美實(shí)現(xiàn)簡(jiǎn)單的照相機(jī)功能了,保存圖片不會(huì)像有些網(wǎng)友提供的代碼給定一個(gè)特定的文件名,不能保存多張圖片,還特定把一些方法封裝了一下,有需要的朋友好好看看吧。
相關(guān)文章
Android BottomNavigationBar底部導(dǎo)航的使用方法
這篇文章主要為大家詳細(xì)介紹了Android BottomNavigationBar底部導(dǎo)航的使用方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-11-11
從源碼分析Android的Glide庫(kù)的圖片加載流程及特點(diǎn)
這篇文章主要介紹了從源碼分析Android的Glide庫(kù)的圖片加載流程及特點(diǎn),Glide庫(kù)是Android下一款人氣很高的多媒體資源管理庫(kù),特別是在處理gif加載方面受到眾多開(kāi)發(fā)者青睞,需要的朋友可以參考下2016-04-04
Android文字匹配度算法及實(shí)際應(yīng)用示例
本文介紹了Android應(yīng)用中常用的文字匹配度算法Levenshtein Distance,并給出了實(shí)際應(yīng)用示例,通過(guò)合理選擇和應(yīng)用文字匹配度算法,可以實(shí)現(xiàn)多種功能,提升用戶(hù)體驗(yàn),增強(qiáng)應(yīng)用的實(shí)用性,需要的朋友可以參考下2024-05-05
Android使用Gallery實(shí)現(xiàn)照片拖動(dòng)的特效
這篇文章主要介紹了Android如何使用Gallery實(shí)現(xiàn)照片拖動(dòng)的特效,幫助大家更好的理解和利用Android進(jìn)行開(kāi)發(fā),感興趣的朋友可以了解下2021-01-01
Art 虛擬機(jī)系列Heap內(nèi)存模型分配策略詳解
這篇文章主要為大家介紹了Art 虛擬機(jī)系列Heap內(nèi)存模型分配策略詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03

