多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內(nèi)最全IT社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當前位置:首頁 > 互聯(lián)網(wǎng) > Android調(diào)用系統(tǒng)相機、自定義相機、處理大圖片

Android調(diào)用系統(tǒng)相機、自定義相機、處理大圖片

來源:程序員人生   發(fā)布時間:2014-09-29 08:00:01 閱讀次數(shù):3399次
Android調(diào)用系統(tǒng)相機和自定義相機實例


本博文主要是介紹了android上使用相機進行拍照并顯示的兩種方式,并且由于涉及到要把拍到
的照片顯示出來,該例子也會涉及到Android加載大圖片時候的處理(避免OOM),還有簡要提一下有些人SurfaceView出現(xiàn)黑屏的原因。


Android應(yīng)用拍照的兩種方式,下面為兩種形式的Demo展示出來的效果。

   


知識點:

一、調(diào)用系統(tǒng)自帶的相機應(yīng)用

二、自定義我們自己的拍照界面


三、關(guān)于計算機解析圖片原理(如何正確加載圖片到Android應(yīng)用中)



所需權(quán)限:


<uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />


一、調(diào)用系統(tǒng)照相機程序拍照(方式一)


1.定義所需要的權(quán)限
2.我們需要定義調(diào)用系統(tǒng)相機App的Intent,當然是通過設(shè)定IntentFilter中的Action來打開我們想要的activity了。


MediaStore.ACTION_IMAGE_CAPTURE - 這個Action將打開拍照的系統(tǒng)相機。返回一個Image


MediaStore.ACTION_VIDEO_CAPTURE - 這個Action將打開錄像的系統(tǒng)相機。返回一個Video


在MediaStore.ACTION_IMAGE_CAPTURE中,我們可以看到這段話:


【The caller may pass an extra EXTRA_OUTPUT to control where this image will be 


written. If the EXTRA_OUTPUT is not present, then a small sized image is returned 


as a Bitmap object in the extra field. This is useful for applications that only 


need a small image. If the EXTRA_OUTPUT is present, then the full-sized image will 


be written to the Uri value of EXTRA_OUTPUT.】



3.API規(guī)定我們傳入拍照得到圖片的存儲位置的Uri。否則Bimmap將以一個壓縮后的形式返回到
我們當前Activity.


intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file name

則會把拍照的圖片存儲到我們傳入的Uri對應(yīng)的File里面。



4.我們調(diào)用startActivityForResult(intent)來啟動這樣一個系統(tǒng)相機app之后,然后在當前應(yīng)
用Activity的onActivityResult()中接受到返回拍照成功或者失敗的消息,做相應(yīng)處理。


5.“壓縮處理”(Android應(yīng)用中加載大圖片),并顯示到ImageView中。


二、自定義照相機


1.檢查相機是否存在,并獲取相機Camera。

2.創(chuàng)建一個相機圖像預(yù)覽類:extends SurfaceView 并 implements SurfaceHolder (我定義:MySurfaceView)
3.把這個預(yù)覽類放入一個自定義布局layout里面,并且可以在layout里添加自己的其他按鈕
4.設(shè)置對應(yīng)的拍照按鈕然后聽事件
5.捕獲照片和保存圖片

6.釋放掉我們使用的相機Camera,不然之后其他應(yīng)用將無法使用它。


三、計算機解析圖片的方式和Android中大圖片Bitmap的壓縮顯示處理

這個問題有點老生長談了,平時我們經(jīng)常遇到一些圖片資源,我們把它加載到內(nèi)存發(fā)現(xiàn)拋出內(nèi)存不夠用的異常,即OOM,當然加載圖片時出現(xiàn)的OOM情況有很多種,比如單張圖片沒有做壓縮,導(dǎo)致圖片占用內(nèi)存過大而發(fā)生內(nèi)存溢出,也有多張圖片一次性加載進來,導(dǎo)致的內(nèi)存溢出。

通常單張大圖,我們加載進來往往會經(jīng)過一個圖片的壓縮處理的過程,而如果多張圖片加載,我們可能就需要一些緩存機制,再加上一些算法來保證程序不出現(xiàn)OOM。

我們這里想要講的知識點跟單張大圖比較有關(guān)系

首先,我們知道一個圖片,它是由很多像素點來表示的,而像素點的個數(shù)只跟圖片的分辨率有關(guān),而跟圖片所占的內(nèi)存空間大小無關(guān)。比如我們的桌面壁紙:1280 * 768 的分辨率,那么它就有 1280 * 768 = 983040個像素點,這意味著什么呢?我們知道我們要表示一個像素點的顏色,最經(jīng)常我們需要RGB三種顏色來表示,而R:0~255,相當于兩個FF的位置,就是8位,這樣的話RGB合起來,一個像素點的表示就需要24位(這就是我們平衡聽到的24位圖),而加上透明度的8位,就是平時說的32位圖。那么一張圖片,它加載到內(nèi)存中的話,它會占用多大的空間呢?

計算方法:(像素點 * 一個像素所占用的byte數(shù)) / 1024 / 1024 (MB) 

1280 * 768 的分辨率,32位圖為例:所占內(nèi)存大小: ((1280 * 768 * (32 / 8)) / 1024)/1024=3.75(MB)

說了這么多,那么我們再來說下Android系統(tǒng)的規(guī)定吧,Android系統(tǒng)嚴格規(guī)定了每個應(yīng)用所能分配的最大的內(nèi)存為多少,我們知道有一個VM值(在我們創(chuàng)建模擬器的時候),這個VM值里面便是我們所說的堆空間(Heap Size),當你的應(yīng)用占用的空間已經(jīng)超出我們定義的堆空間大小,那么不好意思,OOM

這樣的話,我們明白了圖片的大小占據(jù)原理,還有盡量不要超出這個堆空間,那么OK,現(xiàn)在問題變得簡單了。如果我們有一種方式可以在圖片加載進來之前,知道圖片的大小,然后改變它的長、寬,這樣的話,分辨率便變小了,這樣出來的乘積也就變小了。比如:我們的屏幕只有320 * 240, 這時候你加載大分辨的圖片進來最多也只能顯示成這樣,所以我們常采用的是對圖片進行壓縮處理。這里有個概念叫壓縮比:

長:1024 / 320 = 3.2  約等于 3

寬:768 / 240 = 3.2 

那這樣我們?nèi)绻褕D片壓縮成這樣大小的,最后的圖片加載進來的大小便是

((320 * 240 * (32 / 8)) / 1024)/1024=0.29(MB)


希望我這樣講完,大家都能聽懂了,我這里先把照相機實例中出現(xiàn)的關(guān)于如果處理這塊圖片的代碼先粘出來

//-----------------------Android大圖的處理方式--------------------------- private void setPicToImageView(ImageView imageView, File imageFile){ int imageViewWidth = imageView.getWidth(); int imageViewHeight = imageView.getHeight(); BitmapFactory.Options opts = new Options(); //設(shè)置這個,只得到Bitmap的屬性信息放入opts,而不把Bitmap加載到內(nèi)存中 opts.inJustDecodeBounds = true; BitmapFactory.decodeFile(imageFile.getPath(), opts); int bitmapWidth = opts.outWidth; int bitmapHeight = opts.outHeight; //取最大的比例,保證整個圖片的長或者寬必定在該屏幕中可以顯示得下 int scale = Math.max(imageViewWidth / bitmapWidth, imageViewHeight / bitmapHeight); //縮放的比例 opts.inSampleSize = scale; //內(nèi)存不足時可被回收 opts.inPurgeable = true; //設(shè)置為false,表示不僅Bitmap的屬性,也要加載bitmap opts.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodeFile(imageFile.getPath(), opts); imageView.setImageBitmap(bitmap); }


關(guān)于堆空間:

堆(HEAP)是VM中占用內(nèi)存最多的部分,通常是動態(tài)分配的。堆的大小不是一成不變的,通常有一個分配機制來控制它的大小。比如初始的HEAP是4M大,當4M的空間被占用超過75%的時候,重新分配堆為8M大;當8M被占用超過75%,分配堆為16M大。倒過來,當16M的堆利用不足30%的時候,縮減它的大小為8M大。重新設(shè)置堆的大小,尤其是壓縮,一般會涉及到內(nèi)存的拷貝,所以變更堆的大小對效率有不良影響。


廢話少說下面就看代碼咯~~為了大家看起來方便點,代碼的結(jié)構(gòu)可能不是很規(guī)范!


源碼下載地址:http://download.csdn.net/detail/u011133213/7844683


代碼部分: 

一、用系統(tǒng)的相機


按鈕點擊之后開啟系統(tǒng)相機Activity

findViewById(R.id.system_camera_btn).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); imageFileUri = getOutFileUri(TYPE_FILE_IMAGE);//得到一個File Uri intent.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri); startActivityForResult(intent, SYSTEM_CAMERA_REQUESTCODE); } });


生成File文件,并得到Uri

//-----------------------生成Uri--------------------------------------- //得到輸出文件的URI private Uri getOutFileUri(int fileType) { return Uri.fromFile(getOutFile(fileType)); } //生成輸出文件 private File getOutFile(int fileType) { String storageState = Environment.getExternalStorageState(); if (Environment.MEDIA_REMOVED.equals(storageState)){ Toast.makeText(getApplicationContext(), "oh,no, SD卡不存在", Toast.LENGTH_SHORT).show(); return null; } File mediaStorageDir = new File (Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) ,"MyPictures"); if (!mediaStorageDir.exists()){ if (!mediaStorageDir.mkdirs()){ Log.i("MyPictures", "創(chuàng)建圖片存儲路徑目錄失敗"); Log.i("MyPictures", "mediaStorageDir : " + mediaStorageDir.getPath()); return null; } } File file = new File(getFilePath(mediaStorageDir,fileType)); return file; } //生成輸出文件路徑 private String getFilePath(File mediaStorageDir, int fileType){ String timeStamp =new SimpleDateFormat("yyyyMMdd_HHmmss") .format(new Date()); String filePath = mediaStorageDir.getPath() + File.separator; if (fileType == TYPE_FILE_IMAGE){ filePath += ("IMG_" + timeStamp + ".jpg"); }else if (fileType == TYPE_FILE_VEDIO){ filePath += ("VIDEO_" + timeStamp + ".mp4"); }else{ return null; } return filePath; }



二、用自定義的相機


檢測相機設(shè)備是否存在:

/*檢測相機是否存在*/ private boolean checkCameraHardWare(Context context){ PackageManager packageManager = context.getPackageManager(); if (packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)){ return true; } return false; }

按鈕按下之后的判斷:

findViewById(R.id.myapp_camera_btn).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (checkCameraHardWare(getApplicationContext())){ Intent intent = new Intent(getApplicationContext(), MyCameraActivity.class); startActivity(intent); }else{ Toast.makeText(getApplicationContext(), "沒有相機存在", Toast.LENGTH_SHORT).show(); } } });

自定義的SurfaceView類:

package cn.panghu.camera; import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; import android.hardware.Camera; import android.util.AttributeSet; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{ private Camera camera = null; private SurfaceHolder surfaceHolder = null; public MySurfaceView(Context context, Camera camera) { super(context); this.camera = camera; surfaceHolder = getHolder(); surfaceHolder.addCallback(this); surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } public MySurfaceView(Context context) { super(context); // TODO Auto-generated constructor stub } @Override public void surfaceCreated(SurfaceHolder holder) { try{ camera.setPreviewDisplay(surfaceHolder); camera.startPreview(); }catch(Exception e){ e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { //根本沒有可處理的SurfaceView if (surfaceHolder.getSurface() == null){ return ; } //先停止Camera的預(yù)覽 try{ camera.stopPreview(); }catch(Exception e){ e.printStackTrace(); } //這里可以做一些我們要做的變換。 //重新開啟Camera的預(yù)覽功能 try{ camera.setPreviewDisplay(surfaceHolder); camera.startPreview(); }catch(Exception e){ e.printStackTrace(); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { } }

自定義相機Activity類:(為了避免當用戶按下Home鍵,之后再回到我們App中,SurfaceView變黑屏,我們需要將SurfaceView加載到FrameLayout中的代碼寫在onResume中)

package cn.panghu.camera; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import android.app.Activity; import android.hardware.Camera; import android.hardware.Camera.PictureCallback; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.FrameLayout; import android.widget.Toast; import com.example.camerademoapp.R; public class MyCameraActivity extends Activity { private Button btn_camera_capture = null; private Button btn_camera_cancel = null; private Button btn_camera_ok = null; private Camera camera = null; private MySurfaceView mySurfaceView = null; private byte[] buffer = null; private final int TYPE_FILE_IMAGE = 1; private final int TYPE_FILE_VEDIO = 2; private PictureCallback pictureCallback = new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { if (data == null){ Log.i("MyPicture", "picture taken data: null"); }else{ Log.i("MyPicture", "picture taken data: " + data.length); } buffer = new byte[data.length]; buffer = data.clone(); } }; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.mycamera_layout); btn_camera_capture = (Button) findViewById(R.id.camera_capture); btn_camera_ok = (Button) findViewById(R.id.camera_ok); btn_camera_cancel = (Button) findViewById(R.id.camera_cancel); btn_camera_capture.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { camera.takePicture(null, null, pictureCallback); btn_camera_capture.setVisibility(View.INVISIBLE); btn_camera_ok.setVisibility(View.VISIBLE); btn_camera_cancel.setVisibility(View.VISIBLE); } }); btn_camera_ok.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //保存圖片 saveImageToFile(); camera.startPreview(); btn_camera_capture.setVisibility(View.VISIBLE); btn_camera_ok.setVisibility(View.INVISIBLE); btn_camera_cancel.setVisibility(View.INVISIBLE); } }); btn_camera_cancel.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { camera.startPreview(); btn_camera_capture.setVisibility(View.VISIBLE); btn_camera_ok.setVisibility(View.INVISIBLE); btn_camera_cancel.setVisibility(View.INVISIBLE); } }); } @Override protected void onPause() { // TODO Auto-generated method stub super.onPause(); camera.release(); camera = null; } @Override protected void onResume() { // TODO Auto-generated method stub super.onResume(); if (camera == null){ camera = getCameraInstance(); } //必須放在onResume中,不然會出現(xiàn)Home鍵之后,再回到該APP,黑屏 mySurfaceView = new MySurfaceView(getApplicationContext(), camera); FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview); preview.addView(mySurfaceView); } /*得到一相機對象*/ private Camera getCameraInstance(){ Camera camera = null; try{ camera = camera.open(); }catch(Exception e){ e.printStackTrace(); } return camera; } //-----------------------保存圖片--------------------------------------- private void saveImageToFile(){ File file = getOutFile(TYPE_FILE_IMAGE); if (file == null){ Toast.makeText(getApplicationContext(), "文件創(chuàng)建失敗,請檢查SD卡讀寫權(quán)限", Toast.LENGTH_SHORT).show(); return ; } Log.i("MyPicture", "自定義相機圖片路徑:" + file.getPath()); Toast.makeText(getApplicationContext(), "圖片保存路徑:" + file.getPath(), Toast.LENGTH_SHORT).show(); if (buffer == null){ Log.i("MyPicture", "自定義相機Buffer: null"); }else{ try{ FileOutputStream fos = new FileOutputStream(file); fos.write(buffer); fos.close(); }catch(IOException e){ e.printStackTrace(); } } } //-----------------------生成Uri--------------------------------------- //得到輸出文件的URI private Uri getOutFileUri(int fileType) { return Uri.fromFile(getOutFile(fileType)); } //生成輸出文件 private File getOutFile(int fileType) { String storageState = Environment.getExternalStorageState(); if (Environment.MEDIA_REMOVED.equals(storageState)){ Toast.makeText(getApplicationContext(), "oh,no, SD卡不存在", Toast.LENGTH_SHORT).show(); return null; } File mediaStorageDir = new File (Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) ,"MyPictures"); if (!mediaStorageDir.exists()){ if (!mediaStorageDir.mkdirs()){ Log.i("MyPictures", "創(chuàng)建圖片存儲路徑目錄失敗"); Log.i("MyPictures", "mediaStorageDir : " + mediaStorageDir.getPath()); return null; } } File file = new File(getFilePath(mediaStorageDir,fileType)); return file; } //生成輸出文件路徑 private String getFilePath(File mediaStorageDir, int fileType){ String timeStamp =new SimpleDateFormat("yyyyMMdd_HHmmss") .format(new Date()); String filePath = mediaStorageDir.getPath() + File.separator; if (fileType == TYPE_FILE_IMAGE){ filePath += ("IMG_" + timeStamp + ".jpg"); }else if (fileType == TYPE_FILE_VEDIO){ filePath += ("VIDEO_" + timeStamp + ".mp4"); }else{ return null; } return filePath; } }



生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 国产精品永久免费视频 | 欧美视频不卡 | 五月伊人婷婷 | 国产精品国产亚洲精品不卡 | 国产精品久久久亚洲 | 亚洲精品国产不卡在线观看 | 国产在线精品福利91香蕉 | 亚洲国产一区二区三区在线观看 | 欧美一级视频在线高清观看 | 亚洲性生活视频 | 精品欧美一区二区在线看片 | 国产一区二区亚洲精品 | 欧美日本成人 | 综合免费一区二区三区 | 亚州都市春色校园小说另类 | 国产国语一级毛片在线放 | 爱爱小视频日本 | 国产欧美一区二区三区视频在线观看 | 午夜理伦三级播放 | 欧美性生活视频免费播放网址大全观看 | 国产精品亚洲综合一区在线观看 | 午夜在线免费观看 | h视频在线观看免费网站 | 羞羞网站在线看 | 日本欧美一区二区三区在线观看 | 亚洲欧美国产另类视频 | 网红毛片| 亚洲成aⅴ人在线观看 | 欧美精品人爱a欧美精品 | 亚洲精品久久久久久久网站 | 国内精品久久久久影院中国 | 亚州免费视频 | 欧美videos黑人巨大 | 欧美日韩精品免费一区二区三区 | 国内精品不卡一区二区三区 | 麻豆精品国产免费观看 | 免费看成人毛片日本久久 | 在线观看免费精品国自产 | 欧洲色吧 | 国内精品久久久久久网站 | 亚洲最大在线 |