CameraAPI中的 自定義照相功能

来源:http://www.cnblogs.com/BobGo/archive/2016/07/06/5646958.html
-Advertisement-
Play Games

前幾天的項目需要使用CameraAPI自己定義照相機,之前用過的二維碼也要自己寫底層代碼,於是總結一下使用CameraAPI的幾點事項。現在由於JDK7.0及其以上版本的官方文檔已經不再推薦使用camera包而是camera2包,但這次還是先講camera的使用,至於camera2等以後再講。 首先 ...


前幾天的項目需要使用CameraAPI自己定義照相機,之前用過的二維碼也要自己寫底層代碼,於是總結一下使用CameraAPI的幾點事項。現在由於JDK7.0及其以上版本的官方文檔已經不再推薦使用camera包而是camera2包,但這次還是先講camera的使用,至於camera2等以後再講。

首先是添加照相機許可權,在清單文件中必須添加攝像頭硬體許可權和使用功能,其中功能可以根據項目需求選擇性放入。

 1     <uses-permission android:name="android.permission.CAMERA"/>
 2     <!--使用攝像頭硬體功能-->
 3     <uses-feature android:name="android.hardware.camera"/>
 4     <!--自動對焦功能-->
 5     <uses-feature android:name="android.hardware.camera.autofocus"/>
 6     <!--閃光燈功能-->
 7     <uses-feature android:name="android.hardware.camera.flash"/>
 8     <!--前置攝像頭-->
 9     <uses-feature android:name="android.hardware.camera.front"/>

關於許可權和對應的功能可以參考文章 http://www.cnblogs.com/BobGo/articles/5646751.html;

我在項目中需要兩個功能,一是在顯示攝像頭的SurfaceView上添加一層ImageView,可以在ImageView上繪製不同的遮罩層;還有一個功能是攝像頭拍攝照片之後顯示及保存圖片。

第一是攝像頭簡單的使用,在這裡可能會遇到在SurfaceView中攝像頭的預覽出現變形問題,下麵會提到解決措施:

1         SurfaceHolder surfaceHolder = surfaceView.getHolder();
2         surfaceHolder.addCallback(this);
3         surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

在當前類中實現SurfaceHolder.Callback 介面,重寫三個方法 surfaceCreated(), surfaceChanged(), surfaceDestroy(),這三個方法就是SurfaceView對應的生命周期;

surfaceCreated()中執行Camera.open()返回一個Camera對象,打開攝像頭硬體,在surfaceDestroy()中,Camera對象調用release()釋放攝像頭;在surfaceChanged()中,設置攝像頭參數,其中getBestSize()是確定手機攝像頭硬體可以使用的最合適大小,這個演算法是官方提供的。我在之前不採用這個演算法而直接設置大小,導致在測試機運行時SurfaceView顯示的圖片出現變形。

 1 @Override
 2     public void surfaceCreated(SurfaceHolder holder) {
 3         camera = Camera.open();
 4     }
 5 
 6     @Override
 7     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
 8         //已經獲得Surface的width和height,設置Camera的參數
 9         Camera.Parameters parameters = camera.getParameters();
10         Camera.Size size=getBestSize(parameters.getSupportedPreviewSizes());
11         int w=size.width;
12         int h=size.height;
13         parameters.setPreviewSize(w, h);
14         parameters.setPictureSize(w, h);
15 //        List<Camera.Size> vSizeList = parameters.getSupportedPictureSizes();
16 //        for (int num = 0; num < vSizeList.size(); num++) {
17 //            Camera.Size vSize = vSizeList.get(num);
18 //        }
19 //        if (t?his.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
20             //強制豎屏模式
21             parameters.set("orientation", "portrait");
22             //在2.2以上可以使用,預覽顯示旋轉90
23 //        parameters.setRotation(90);
24             camera.setDisplayOrientation(90);
25 //        } else {
26 //            parameters.set("orientation", "landscape");
27             //在2.2以上可以使用
28 //            camera.setDisplayOrientation(90);
29 //        }
30         camera.setParameters(parameters);
31         try {
32             //設置顯示
33             camera.setPreviewDisplay(holder);
34         } catch (IOException exception) {
35             camera.release();
36             camera = null;
37         }
38         //開始預覽
39         camera.startPreview();
40         //設置自動對焦
41         camera.autoFocus(new Camera.AutoFocusCallback() {
42             @Override
43             public void onAutoFocus(boolean success, Camera camera) {
44                 if (success) {
45                     // success為true表示對焦成功,改變對焦狀態圖像
46                 }
47             }
48         });
49     }
50 
51     private Camera.Size getBestSize(List<Camera.Size> supportedPreviewSizes) {
52         Camera.Size largestSize=supportedPreviewSizes.get(0);
53         int largestArea= supportedPreviewSizes.get(0).height*supportedPreviewSizes.get(0).width;
54         for (Camera.Size s:supportedPreviewSizes){
55             int area=s.width*s.height;
56             if(area>largestArea){
57                 largestArea=area;
58                 largestSize=s;
59             }
60         }
61         return largestSize;
62 
63     }
64 
65     @Override
66     public void surfaceDestroyed(SurfaceHolder holder) {
67         // 釋放手機攝像頭
68         camera.release();
69     }

 也可以在surfaceChanged()中設置閃光燈等功能:

1 parameters.setFlashMode(isChecked?Camera.Parameters.FLASH_MODE_ON:Camera.Parameters.FLASH_MODE_OFF);

最後在需要攝像的點擊監聽中調用takePicture(Camera.ShutterCallback, Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)函數來完成拍照,這個函數中可以四個回調介面,ShutterCallback是快門按下的回調,在這裡我們可以設置播放“咔嚓”聲之類的操作,後面有三個PictureCallback介面,分別對應三份圖像數據:原始圖像、縮放和壓縮圖像和JPG圖像,圖像數據可以在PictureCallback介面的void onPictureTaken(byte[] data, Camera camera)中獲得,三份數據相應的三個回調正好按照參數順序調用,通常我們只關心JPG圖像數據,此時前面兩個PictureCallback介面參數可以直接傳null

每次調用takePicture() 獲取圖像後,攝像頭會停止預覽,假如需要繼續拍照,則我們需要在上面的PictureCallbackonPictureTaken() 函數末尾,Camera對象再次調用startPreview() 函數;在不需要拍照的時候,Camera對象需要主動調用stopPreview() 停止預覽功能;

第二個功能是攝像圖片的顯示和保存,在這個功能中可能會出現兩個問題,一個是拍攝圖片橫屏顯示,另一個是將上邊SurfaceView上方的ImageView遮罩層一同保存到用戶手機,實現類似於圖像合成的效果;

關於圖片橫屏顯示的問題,是因為Android官方認為手機橫屏才是攝像頭的正確打開方式,所以保存的圖片也是橫屏保存的,所以如果想豎屏顯示圖片,就要把圖片順時針旋轉90度,調整到豎屏顯示模式,具體代碼如下:

1 private void setImageByte(ImageView showImage, byte[] data) {
2         Bitmap bitmap= BitmapFactory.decodeByteArray(data, 0, data.length);
3         showImage.setImageBitmap(bitmap);
4         Matrix matrix = showImage.getImageMatrix();
5         matrix.setRotate(90);
6         showImage.setImageBitmap(Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true));
7     }

還有一個問題是解決兩個控制項內容同時保存的問題,這個其實想到了方法就很簡單了,自定義一個FrameLayout的子佈局,在該佈局中只加入一個方法

1     public Bitmap getBitmap(){
2         //設置緩存
3         setDrawingCacheEnabled(true);
4         buildDrawingCache();
5         //從緩存中獲取當前屏幕的圖片
6         return getDrawingCache();
7     }

然後在上文用到的xml佈局中將該佈局作為要同時保存圖像的父控制項。

最後在java代碼中需要保存合成圖片的地方,只需要實例化剛剛自定義的FrameLayout對象調用getBitmap(),就能返回合成之後的Bitmap對象;

所以我們的功能就能完全實現了。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 重寫onKeyDown事件即可 @Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { moveTaskToBack(false); return ...
  • 之前因為工作需要要實現一個類似的 懸浮+視差的headerView的效果, 研究了好久沒研究出來怎麼做,最後用UICollectionView + CSStickyHeaderFlowLayout的方法實現了(不得不說CSStickyHeaderFlowLayout真的是一個很強大的庫,作者對UIC ...
  • //顯示動畫 dialog = new Dialog(context, R.style.loading); dialog.setContentView(R.layout.loadinglayout);//此處佈局為一個progressbar dialog.setCancelable(true); / ...
  • 一,效果圖。 二,工程圖。 三,代碼。 AppDelegate.m #import "AppDelegate.h" //加入頭文件 #import "RoundDiskViewController.h" @implementation AppDelegate - (BOOL)application: ...
  • Android 5.0之後Android新增加的兩個UI控制項RecyclerView,CardView。 RecyclerView可以看出是ListView的加強版,能夠更加靈活的使用、支持動畫等 CardView則是Google提供的一個卡片式視圖組件,可以定義如邊角的弧度、陰影等屬性。從本質上看 ...
  • AsyncTask定義了三種泛型類型 Params,Progress和Result。 Params 啟動任務執行的輸入參數,比如HTTP請求的URL。 Progress 後臺任務執行的百分比。 Result 後臺執行任務最終返回的結果,比如String。 Params 啟動任務執行的輸入參數,比如H ...
  • 在你的主頁面里寫上這個方法 最後用你獲取的text取代cell的一部分 ...
  • 我們在開發app過程中很多時候會需要設置系統許可權,這時就需要在應用中跳轉至系統設置頁面許可權設置頁面,以下是自己結合網上的資料總結的一些經驗: NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; if ([[UI ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...