Android?Camera開(kāi)發(fā)實(shí)現(xiàn)可復(fù)用的相機(jī)組件
本文實(shí)例為大家分享了Android Camera實(shí)現(xiàn)可復(fù)用相機(jī)組件的具體代碼,供大家參考,具體內(nèi)容如下
若自己的應(yīng)用需要使用camera,有兩種解決方案。
1. 使用Intent調(diào)用自帶的Camera程序
2. 使用Camera API在程序中構(gòu)造自己的Camera。
本文主要講解第二種。
構(gòu)造一個(gè)相機(jī)APP,通常需要六個(gè)步驟
1. 聲明Manifest的相機(jī)權(quán)限
2. 創(chuàng)建一個(gè)相機(jī)預(yù)覽類(lèi)(繼承SurfaceView)
3. 創(chuàng)建一個(gè)類(lèi)實(shí)現(xiàn)相機(jī)拍照之后的回調(diào)函數(shù)
本文將一步步帶你實(shí)現(xiàn)上述三個(gè)步驟。
1. 聲明Manifest的相機(jī)權(quán)限。
應(yīng)為我們需要寫(xiě)文件與調(diào)用相機(jī),所以在你的manifest文件中加上。
<uses-permission android:name="android.permission.CAMERA" /> ?<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2. 創(chuàng)建一個(gè)相機(jī)預(yù)覽類(lèi)
由于相機(jī)的預(yù)覽是使用的SurfaceView,所以這里我們創(chuàng)建一個(gè)SurfaceView的子類(lèi)。
為了讓這個(gè)View所見(jiàn)即所得,我們將其設(shè)置為4/3的比例。重寫(xiě)它的onMeasure方法
代碼如下:
package com.example.cameratutorial; ? import android.content.Context; ? import android.util.Log; import android.view.SurfaceView; ? /** ?* @author CTGU小龍同學(xué) 2014-6-21 ?*/ public class CameraSurfaceView extends SurfaceView { ?? ?private static final String TAG = "CameraSurfaceView"; ?? ?// 用四比三的比例 ?? ?public static double RATIO = 3.0 / 4.0; ? ?? ?/** ?? ? * @param context ?? ? */ ?? ?public CameraSurfaceView(Context context) { ?? ??? ?super(context); ? ?? ?} ? ?? ?@Override ?? ?protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { ?? ??? ? ?? ??? ?int height = MeasureSpec.getSize(heightMeasureSpec); ?? ??? ?int width = MeasureSpec.getSize(widthMeasureSpec); ?? ??? ?Log.d("Measured", "before width" + width + "height" + height); ? ?? ??? ?boolean isWidthLonger; ?? ??? ?int longSide; ?? ??? ?int shortSide; ?? ??? ?// 以短邊為準(zhǔn)確定一下長(zhǎng)邊 ?? ??? ?if (width < height) { ?? ??? ??? ?height = (int) (width / RATIO); ?? ??? ??? ?isWidthLonger = false; ? ?? ??? ?} else { ?? ??? ??? ?width = (int) (height / RATIO); ?? ??? ??? ?isWidthLonger = true; ?? ??? ?} ? ?? ??? ?Log.d("Measured", "after width" + width + "height" + height); ?? ??? ?setMeasuredDimension(width, height); ? ?? ?} ? }
3. 現(xiàn)在我們使用一個(gè)實(shí)現(xiàn)了SurfaceHolder.Callback, Camera.PictureCallback 的Fragment來(lái)把我們需要的組件都封裝起來(lái)。
代碼如下:
package com.example.cameratutorial; ? import java.io.*; import java.util.*; import android.app.Activity; import android.app.Fragment; import android.graphics.*; ? import android.graphics.Bitmap.CompressFormat; import android.hardware.Camera; import android.hardware.Camera.CameraInfo; import android.hardware.Camera.Size; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.*; ? ? import android.widget.RelativeLayout; import android.widget.Toast; ? /** ?* @author CTGU小龍同學(xué) 2014-6-21 ?*/ public class CameraFragment extends Fragment implements SurfaceHolder.Callback, Camera.PictureCallback { ?? ?private Camera mCamera; ?? ?// CameraPreview的holder ?? ?private SurfaceHolder mSurfaceHolder; ?? ?private CameraSurfaceView preview; ?? ?private int mFrontCameraId = -1; ?? ?private int mBackCameraId = -1; ? ?? ?@Override ?? ?public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ? ?? ??? ?preview = new CameraSurfaceView(getActivity()); ?? ??? ?preview.getHolder().addCallback(this); ? ?? ??? ?RelativeLayout layout = new RelativeLayout(getActivity()); ?? ??? ?layout.addView(preview); ? ?? ??? ?return layout; ? ?? ?} ? ?? ?@Override ?? ?public void onAttach(Activity activity) { ?? ??? ?super.onAttach(activity); ?? ??? ?findAvailableCameras(); ? ?? ?} ? ?? ?@Override ?? ?public void onResume() { ? ?? ??? ?super.onResume(); ?? ??? ?Log.d("camera", "mFrontCameraId" + mFrontCameraId); ?? ??? ?Log.d("camera", "mbackCameraId" + mBackCameraId); ?? ??? ?if (mBackCameraId != -1) { ? ?? ??? ??? ?mCamera = Camera.open(mBackCameraId); ? ?? ??? ?} else { ?? ??? ??? ?Toast.makeText(getActivity(), "fialed to open camera", Toast.LENGTH_SHORT).show(); ?? ??? ?} ? ?? ?} ? ?? ?@Override ?? ?public void onPause() { ?? ??? ?super.onPause(); ? ?? ??? ?mCamera.stopPreview(); ?? ??? ?mCamera.release(); ?? ?} ? ?? ?/** ?? ? * 獲得可用的相機(jī),并設(shè)置前后攝像機(jī)的ID ?? ? */ ?? ?private void findAvailableCameras() { ? ?? ??? ?Camera.CameraInfo info = new CameraInfo(); ?? ??? ?int numCamera = Camera.getNumberOfCameras(); ?? ??? ?for (int i = 0; i < numCamera; i++) { ?? ??? ??? ?Camera.getCameraInfo(i, info); ?? ??? ??? ?// 找到了前置攝像頭 ?? ??? ??? ?if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { ?? ??? ??? ??? ?mFrontCameraId = info.facing; ?? ??? ??? ?} ?? ??? ??? ?// 招到了后置攝像頭 ?? ??? ??? ?if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { ?? ??? ??? ??? ?mBackCameraId = info.facing; ?? ??? ??? ?} ? ?? ??? ?} ? ?? ?} ? ?? ?/** ?? ? * 當(dāng)相機(jī)拍照時(shí)會(huì)回調(diào)該方法 ?? ? */ ?? ?@Override ?? ?public void onPictureTaken(byte[] data, Camera camera) { ?? ??? ?final Bitmap bitmap; ? ?? ??? ?final String path; ?? ??? ?try { ?? ??? ??? ?// /storage/emulated/0/Pictures/XXX.jpg ? ?? ??? ??? ?path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath() + "/" + new Date().toLocaleString() + ".jpg"; ?? ??? ??? ?Log.d("Path", path); ?? ??? ??? ?bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); ?? ??? ??? ?camera.stopPreview(); ? ?? ??? ??? ?final int displayOrientation = getCorrectOrientation(); ?? ??? ??? ?new Thread(new Runnable() { ? ?? ??? ??? ??? ?@Override ?? ??? ??? ??? ?public void run() { ?? ??? ??? ??? ??? ?FileOutputStream fos; ?? ??? ??? ??? ??? ?Matrix matrix = new Matrix(); ?? ??? ??? ??? ??? ?matrix.postRotate(displayOrientation); ?? ??? ??? ??? ??? ?Bitmap rotaBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false); ? ?? ??? ??? ??? ??? ?try { ?? ??? ??? ??? ??? ??? ?fos = new FileOutputStream(path); ?? ??? ??? ??? ??? ??? ?rotaBitmap.compress(CompressFormat.JPEG, 100, fos); ?? ??? ??? ??? ??? ??? ?fos.close(); ?? ??? ??? ??? ??? ?} catch (Exception e) { ?? ??? ??? ??? ??? ??? ?// TODO Auto-generated catch block ?? ??? ??? ??? ??? ??? ?e.printStackTrace(); ?? ??? ??? ??? ??? ?} ? ?? ??? ??? ??? ?} ?? ??? ??? ?}).start(); ? ?? ??? ?} catch (Exception e) { ? ?? ??? ?} ?? ??? ?camera.startPreview(); ?? ?} ? ?? ?/** ?? ? * 讓預(yù)覽跟照片符合正確的方向。<br/> ?? ? * 因?yàn)轭A(yù)覽默認(rèn)是橫向的。如果是一個(gè)豎向的應(yīng)用,就需要把預(yù)覽轉(zhuǎn)90度<br/> ?? ? * 比如橫著時(shí)1280*960的尺寸時(shí),1280是寬.<br/> ?? ? * 豎著的時(shí)候1280就是高了<br/> ?? ? * 這段代碼來(lái)自官方API。意思就是讓拍出照片的方向和預(yù)覽方向正確的符合設(shè)備當(dāng)前的方向(有可能是豎向的也可能使橫向的) ?? ? *? ?? ? */ ?? ?private int getCorrectOrientation() { ?? ??? ?android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); ?? ??? ?android.hardware.Camera.getCameraInfo(mBackCameraId, info); ?? ??? ?int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation(); ?? ??? ?int degrees = 0; ?? ??? ?switch (rotation) { ?? ??? ?case Surface.ROTATION_0: ?? ??? ??? ?degrees = 0; ?? ??? ??? ?break; ?? ??? ?case Surface.ROTATION_90: ?? ??? ??? ?degrees = 90; ?? ??? ??? ?break; ?? ??? ?case Surface.ROTATION_180: ?? ??? ??? ?degrees = 180; ?? ??? ??? ?break; ?? ??? ?case Surface.ROTATION_270: ?? ??? ??? ?degrees = 270; ?? ??? ??? ?break; ?? ??? ?} ? ?? ??? ?int result; ?? ??? ?if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { ?? ??? ??? ?result = (info.orientation + degrees) % 360; ?? ??? ??? ?result = (360 - result) % 360; // compensate the mirror ?? ??? ?} else { // back-facing ?? ??? ??? ?result = (info.orientation - degrees + 360) % 360; ?? ??? ?} ?? ??? ?Log.d("orientationResult", result + ""); ?? ??? ?return result; ?? ?} ? ?? ?public void takePicture() { ?? ??? ?mCamera.takePicture(null, null, this); ?? ?} ? ?? ?@Override ?? ?public void surfaceCreated(SurfaceHolder holder) { ?? ??? ?mSurfaceHolder = holder; ? ?? ??? ?startPreView(); ? ?? ?} ? ?? ?private void startPreView() { ?? ??? ?try { ?? ??? ??? ?mCamera.setPreviewDisplay(mSurfaceHolder); ?? ??? ??? ?setPreviewSize(); ?? ??? ??? ?setDisplayOrientation(); ?? ??? ??? ?mCamera.startPreview(); ?? ??? ?} catch (IOException e) { ?? ??? ??? ?// TODO Auto-generated catch block ?? ??? ??? ?e.printStackTrace(); ?? ??? ?} ? ?? ?} ? ?? ?private void setDisplayOrientation() { ?? ??? ?int displayOrientation = getCorrectOrientation(); ? ?? ??? ?mCamera.setDisplayOrientation(displayOrientation); ?? ?} ? ?? ?/** ?? ? * 我們用4比3的比例設(shè)置預(yù)覽圖片 ?? ? */ ?? ?private void setPreviewSize() { ?? ??? ?Camera.Parameters params = mCamera.getParameters(); ?? ??? ?List<Size> sizes = params.getSupportedPreviewSizes(); ?? ??? ?for (Size size : sizes) { ?? ??? ??? ?Log.d("previewSize", "width:" + size.width + " height " + size.height); ?? ??? ?} ?? ??? ?for (Size size : sizes) { ?? ??? ??? ?if (size.width / 4 == size.height / 3) { ?? ??? ??? ??? ?params.setPreviewSize(size.width, size.height); ?? ??? ??? ??? ?Log.d("previewSize", "SET width:" + size.width + " height " + size.height); ?? ??? ??? ??? ?break; ?? ??? ??? ?} ?? ??? ?} ? ?? ??? ?// params一定要記得寫(xiě)回Camera ?? ??? ?mCamera.setParameters(params); ? ?? ?} ? ?? ?private void setPictureSize() { ?? ??? ?Camera.Parameters params = mCamera.getParameters(); ?? ??? ?List<Size> sizes = params.getSupportedPictureSizes(); ?? ??? ?for (Size size : sizes) { ?? ??? ??? ?Log.d("picSize", "width:" + size.width + " height " + size.height); ?? ??? ?} ?? ??? ?for (Size size : sizes) { ?? ??? ??? ?if (size.width / 4 == size.height / 3) { ?? ??? ??? ??? ?params.setPictureSize(size.width, size.height); ?? ??? ??? ??? ?break; ?? ??? ??? ?} ?? ??? ?} ? ?? ?} ? ?? ?@Override ?? ?public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { ? ?? ?} ? ?? ?@Override ?? ?public void surfaceDestroyed(SurfaceHolder holder) { ?? ??? ?mCamera.release(); ?? ?} ? }
4. 程序的Mainactivity以及相應(yīng)的布局文件
package com.example.cameratutorial; ? import android.os.Bundle; import android.app.Activity; import android.app.FragmentManager; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; ? public class MainActivity extends Activity { ?? ? ?? ?@Override ?? ?protected void onCreate(Bundle savedInstanceState) { ?? ??? ?super.onCreate(savedInstanceState); ?? ??? ?setContentView(R.layout.activity_main); ?? ??? ?final CameraFragment fragment=(CameraFragment) getFragmentManager().findFragmentById(R.id.camera_fragment); ?? ??? ?Button button=(Button) findViewById(R.id.TakePic); ?? ??? ?button.setOnClickListener(new OnClickListener() { ?? ??? ??? ? ?? ??? ??? ?@Override ?? ??? ??? ?public void onClick(View v) { ?? ??? ??? ??? ?fragment.takePicture(); ?? ??? ??? ??? ? ?? ??? ??? ?} ?? ??? ?}); ?? ??? ? ?? ?} ? }
布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" ? ? xmlns:tools="http://schemas.android.com/tools" ? ? android:layout_width="match_parent" ? ? android:layout_height="match_parent"? ? ? android:orientation="vertical" ? ? > ? ? ? <fragment ? ? ? ? android:id="@+id/camera_fragment" ? ? ? ? android:name="com.example.cameratutorial.CameraFragment" ? ? ?? ? ? ? ? android:layout_width="match_parent" ? ? ? ? android:layout_height="match_parent" ? ? ? ? /> ? ? ? <Button ? ? ? ? android:id="@+id/TakePic" ? ? ? ? android:layout_width="match_parent" ? ? ? ? android:layout_height="wrap_content" ? ? ? ? android:layout_alignParentBottom="true" ? ? ? ? android:text="capture" /> ? </RelativeLayout>
這樣,我們一個(gè)可以復(fù)用的相機(jī)組件就完成了。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android寫(xiě)一個(gè)實(shí)時(shí)輸入框功能
這篇文章主要介紹了Android寫(xiě)一個(gè)實(shí)時(shí)輸入框功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04淺談Android安全風(fēng)險(xiǎn)與防范措施
這篇文章主要介紹了淺談Android安全風(fēng)險(xiǎn)與防范措施,對(duì)安全感興趣的同學(xué)可以參考下2021-04-04Android如何動(dòng)態(tài)改變App桌面圖標(biāo)
這篇文章主要介紹了 Android動(dòng)態(tài)改變App桌面圖標(biāo)的方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下2017-01-01源碼解析Android Jetpack組件之ViewModel的使用
Jetpack 是一個(gè)豐富的組件庫(kù),它的組件庫(kù)按類(lèi)別分為 4 類(lèi),分別是架構(gòu)(Architecture)、界面(UI)、 行為(behavior)和基礎(chǔ)(foundation)。本文將從源碼和大家講講Jetpack組件中ViewModel的使用2023-04-04Android開(kāi)發(fā)RecyclerView單獨(dú)刷新使用技巧
本篇文章主要是分享下RecyclerView中子item如何單獨(dú)刷新以及子item的某一部分內(nèi)容如何實(shí)現(xiàn)單獨(dú)刷新,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09Flutter實(shí)現(xiàn)倒計(jì)時(shí)功能
這篇文章主要為大家詳細(xì)介紹了Flutter實(shí)現(xiàn)倒計(jì)時(shí)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03Android仿Keep運(yùn)動(dòng)休息倒計(jì)時(shí)圓形控件
這篇文章主要為大家詳細(xì)介紹了Android仿Keep運(yùn)動(dòng)休息倒計(jì)時(shí)圓形控件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09