綁定帳號登入

Android 台灣中文網

打印 上一主題 下一主題

[其他] Android 處理圖像的方法 - (一) 避免記憶體不足的異常

[複製連結] 查看: 8768|回覆: 16|好評: 2
跳轉到指定樓層
樓主
ploglin | 收聽TA | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
發表於 2011-9-13 11:54

馬上加入Android 台灣中文網,立即免費下載應用遊戲。

您需要 登錄 才可以下載或查看,沒有帳號?註冊

x
本帖最後由 ploglin 於 2011-9-13 11:55 編輯

原文連結 http://huee11.blogspot.com/2011/07/android.html

近日的一個案件需要處理相片,包含了將原始圖片縮小, 黑白效果, 相片合成, 濾鏡的效果。在網路上找了相當多的文章,當然....大部份都是失敗的方法,在東撿撿、西撿撿後,終於完成了需要的效果,大致的說明如下。

避免記憶體不足的異常
因為相機所拍出的相片畫質如果比較高,在處理圖片縮小時很有可能會遇到VM記憶體不足的問題。而Android本身有提供幾個參數。

首先是

inSampleSize

If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory. The sample size is the number of pixels in either dimension that correspond to a single pixel in the decoded bitmap. For example, inSampleSize == 4 returns an image that is 1/4 the width/height of the original, and 1/16 the number of pixels. Any value <= 1 is treated the same as 1. Note: the decoder will try to fulfill this request, but the resulting bitmap may have different dimensions that precisely what has been requested. Also, powers of 2 are often faster/easier for the decoder to honor.

主要是說,如果將值設定為 1 以上的數值,系統便會回傳一個比原始圖像還要小的圖像,目的是為了減少記憶體的使用,相關的邏輯在原文中也有述說。

另一個是

inJustDecodeBounds

If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels.

如果將此值設為 true 的話,系統在decode時不會直接回傳一個Bitmap的物件,但我們可以取得原始圖像的高度和寬度等相關資訊。這邊是為了防止記憶體不足,利用取回的資訊,去計算出 inSampleSize 的數值。
Bitmap recycle

Free the native object associated with this bitmap, and clear the reference to the pixel data.
這個相當的重要。如果你所處理的圖像很多,記得把已經需要用到的 Bitmap 物件 recycle ,以釋放記憶體。


實際用法如下
  1. public class CameraRunActivity extends Activity implements Callback, OnClickListener {
  2. private static final String TAG = CameraRunActivity.class.getSimpleName();
  3. private SurfaceView surfaceview;
  4. private SurfaceHolder surfaceholder;
  5. private Camera myCamera;
  6. private ImageView camera_action;
  7. private Bitmap finalBMP;
  8. private final int HANDLER_OF_PROCESS = 0;

  9. /** Called when the activity is first created. */
  10. @Override
  11. public void onCreate(Bundle savedInstanceState) {
  12.   super.onCreate(savedInstanceState);
  13.   requestWindowFeature(Window.FEATURE_NO_TITLE);
  14.   setContentView(R.layout.camera_run);
  15.   setRequestedOrientation(1);
  16.   // 定義 Layout 中的 SurfaceView
  17.   surfaceview = (SurfaceView) findViewById(R.id.surfaceview);
  18.   surfaceholder = surfaceview.getHolder();
  19.   // 定義 SurfaceView Holder 相關的處理
  20.   surfaceholder.addCallback(this);
  21.   surfaceholder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  22.   // 實際觸發拍照的物件
  23.   camera_action = (ImageView) findViewById(R.id.camera_action);
  24.   camera_action.setOnClickListener(this);
  25. }

  26. @Override
  27. public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
  28.   Camera.Parameters parameters = myCamera.getParameters();
  29.   // 開啟自動對焦的模式
  30.   parameters.setFocusMode("auto");
  31.   // 設定輸出的圖像格式
  32.   parameters.setPictureFormat(PixelFormat.JPEG);
  33.   myCamera.setParameters(parameters);
  34.   // 同步 SurfaceView 與 Camera
  35.   myCamera.startPreview();
  36.   isCameraOpen = true;
  37. }
  38. @Override
  39. public void surfaceCreated(SurfaceHolder holder) {
  40.   try {
  41.    myCamera = Camera.open();
  42.    myCamera.setPreviewDisplay(surfaceholder);
  43.    // 將相機轉 90 度,因為手機要保持直立
  44.    myCamera.setDisplayOrientation(90);
  45.   } catch (IOException e) {
  46.    myCamera.release();
  47.    myCamera = null;
  48.   }
  49. }
  50. @Override
  51. public void surfaceDestroyed(SurfaceHolder holder) {
  52.   myCamera.stopPreview();
  53.   isCameraOpen = false;
  54.   myCamera.release();
  55.   myCamera = null;
  56. }

  57. @Override
  58. public void onClick(View v) {
  59.   switch (v.getId()) {
  60.    case R.id.camera_action :
  61.     isCameraOpen = false;
  62.     // 先觸發自動對焦,然後再拍照
  63.     myCamera.autoFocus(autoFacusCallback);
  64.     break;
  65.   }
  66. }

  67. private ShutterCallback shutterCallback = new ShutterCallback() {
  68.   public void onShutter() {
  69.    // Shutter has closed
  70.   }
  71. };

  72. private PictureCallback rawCallback = new PictureCallback() {
  73.   public void onPictureTaken(byte[] _data, Camera _camera) {
  74.    // TODO Handle RAW image data
  75.   }
  76. };

  77. private PictureCallback jpegCallback = new PictureCallback() {
  78.   public void onPictureTaken(byte[] _data, Camera _camera) {
  79.    // 設定 inJustDecodeBounds = true
  80.    BitmapFactory.Options options = new BitmapFactory.Options();
  81.    options.inJustDecodeBounds = true;
  82.    Bitmap bitmap_def = BitmapFactory.decodeByteArray(_data, 0, _data.length, options);
  83.    // 取得圖像的長寬
  84.    int width = bitmap_def.getWidth();
  85.    int height = bitmap_def.getHeight();
  86.   }
  87. };

  88. AutoFocusCallback autoFacusCallback = new AutoFocusCallback() {

  89.   @Override
  90.   public void onAutoFocus(boolean focused, Camera camera) {
  91.    // 當相機捉到焦點時,再啟動相機拍照
  92.    if (focused == true) {
  93.     myCamera.takePicture(shutterCallback, rawCallback, jpegCallback);
  94.    }
  95.   }
  96. };

  97. }
複製代碼
「用Android 就來APK.TW」,快來加入粉絲吧!
Android 台灣中文網(APK.TW)

評分

參與人數 10碎鑽 +5 幫助 +10 收起 理由
kathylai + 1
joeliupeter + 1
傻庭兒 + 1 + 1 非常讚
kdic + 1 讚一個!
wingi1219 + 1 偶像,看完你的內容,讓我找到了活著的意義.
zxc1313 + 1 + 1 非常讚
ez32451 + 1 很給力!
fineking + 1 + 1 非常讚
yenhorng + 1 + 1 非常讚
cadgis + 1 非常讚

查看全部評分

收藏收藏13 分享分享 分享專題
用Android 就來Android 台灣中文網(https://apk.tw)
回覆

使用道具 舉報

沙發
gammer99 | 收聽TA | 只看該作者
發表於 2011-10-6 12:54
謝謝你的經驗分享。收下了。
用Android 就來Android 台灣中文網(https://apk.tw)
回覆 支持 反對

使用道具 舉報

板凳
piano1542 | 收聽TA | 只看該作者
發表於 2011-10-20 15:15
感謝大大經驗分享...
用Android 就來Android 台灣中文網(https://apk.tw)
回覆 支持 反對

使用道具 舉報

地板
splayer | 收聽TA | 只看該作者
發表於 2011-10-23 07:13
感謝經驗分享,3Q
用Android 就來Android 台灣中文網(https://apk.tw)
回覆 支持 反對

使用道具 舉報

5
joeasy | 收聽TA | 只看該作者
發表於 2011-11-11 16:58
學習了,謝謝大大
用Android 就來Android 台灣中文網(https://apk.tw)
回覆 支持 反對

使用道具 舉報

6
hankar | 收聽TA | 只看該作者
發表於 2011-11-30 21:23
真是太棒了!!非常感謝您的分享~小弟我虛心的收下了~~
用Android 就來Android 台灣中文網(https://apk.tw)
回覆 支持 反對

使用道具 舉報

7
garypipi | 收聽TA | 只看該作者
發表於 2012-1-17 15:52
感謝您的分享,會好好收藏的
用Android 就來Android 台灣中文網(https://apk.tw)
回覆 支持 反對

使用道具 舉報

8
kentisme | 收聽TA | 只看該作者
發表於 2012-2-9 13:44
感謝分享,嵌入式系統的資源應用,少了這些分享。自己摸索可能永遠都找不到最佳解!
用Android 就來Android 台灣中文網(https://apk.tw)
回覆 支持 反對

使用道具 舉報

9
machines | 收聽TA | 只看該作者
發表於 2012-3-31 01:35
完全看不懂..........................
用Android 就來Android 台灣中文網(https://apk.tw)
回覆 支持 反對

使用道具 舉報

10
yenhorng | 收聽TA | 只看該作者
發表於 2012-10-27 00:21
目前還看不懂,先收藏。有天需要時可參考。
用Android 就來Android 台灣中文網(https://apk.tw)
回覆 支持 反對

使用道具 舉報

您需要登錄後才可以回帖 登錄 | 註冊

本版積分規則