內容如題:
以前對於圖片縮放時出現oom,也是束手無策。昨天看了Android_Tutor對於圖片處理的文章,今天就斗膽將這部分的內容演習下。
首先創建一個佈局文件:用imageview控件加載圖片
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/show"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<ImageView
android:id="@+id/imageview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="matrix"
android:src="@drawable/ic_launcher" />
</LinearLayout>
其次:用公共類ImageCacheUtil對圖片進行壓縮處理:這樣可以保證圖片太大的時候不會出現oom
/**
* @FILE:ImageCacheUtil.java
* @AUTHOR:hui-ye
* @DATE:2013-6-19 下午2:23:56
**/
package com.view.imagecachedemo;
import java.io.InputStream;
import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.net.Uri;
/*******************************************
*
* @CLASS:ImageCacheUtil
* @DESCRIPTION:獲得經過縮放處理的bitmap,以保證不會出現oom
* @AUTHOR:hui-ye
* @VERSION:v1.0
* @DATE:2013-6-19 下午2:23:56
*******************************************/
public class ImageCacheUtil {
/**
* @description:獲取bitmap
* @author:hui-ye
* @param path 圖片文件的路徑
* @param data 圖片的文件的數據
* @param context 上下文對象
* @param uri 資源
* @param target 模板寬或者高的大小
* @param width 是否是寬度
* @return:
*/
public static Bitmap getResizedBitmap(String path, byte[] data,
Context context, Uri uri, int target, boolean width)
throws Exception {
// android api
// BitmapFactory.Options options = new BitmapFactory.Options();
// options.inJustDecodeBounds = true;
// BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
// int imageHeight = options.outHeight;
// int imageWidth = options.outWidth;
// String imageType = options.outMimeType;
Bitmap bitmap = null;
// 添加一個Options對象
Options options = null;
if (target > 0) {
options = new Options();
// 設置options的屬性:inJustDecodeBounds=true的時候讀取圖片的時候,bitmap爲null,將圖片寬和高放到options中
options.inJustDecodeBounds = true;
// 獲得圖片(這樣會將圖片的寬和高放入到options中)
decode(path, data, context, uri, options);
// 獲得壓縮的比例
int outWidth = options.outWidth;
// 這樣做寬和高就是相等了
if (!width) {
outWidth = Math.max(outWidth, options.outHeight);
}
// 計算壓縮比例
int ssize = sampleSize(outWidth, target);
options.inSampleSize = ssize;
// 設置inJustDecodeBounds = false,從新構建bitmap
options.inJustDecodeBounds = false;
bitmap = decode(path, data, context, uri, options);
}
return bitmap;
}
/**
* @description:解析Bitmap的公用方法.注意各個方法的參數必須要有options
* @author:hui-ye
* @param path
* @param data
* @param context
* @param uri
* @param options
* @return:
*/
public static Bitmap decode(String path, byte[] data, Context context,
Uri uri, BitmapFactory.Options options) throws Exception {
Bitmap bitmap = null;
if (path != null) {
bitmap = BitmapFactory.decodeFile(path, options);
} else if (data != null) {
BitmapFactory.decodeByteArray(data, 0, data.length, options);
} else if (uri != null) {
// uri不爲空的時候context也不要爲空.:ContentResolver;Uri內容解析器
ContentResolver resolver = context.getContentResolver();
InputStream is;
is = resolver.openInputStream(uri);
bitmap = BitmapFactory.decodeStream(is, null, options);
}
return bitmap;
}
/**
* @description:獲取samplesize圖片的壓縮比例 (這裏就簡單實現都是2的倍數啦.也就是說看width會是target的倍數)
* @author:hui-ye
* @param width
* @param target
* @return:
*/
private static int sampleSize(int width, int target) {
int result = 1;
for (int i = 0; i < 10; i++) {
if (width < target * 2) {
break;
}
width = width / 2;
result = result * 2;
}
return result;
}
}
計算好了壓縮比例,返回一個被壓縮處理過的圖片。
再次。打開相冊,從中選擇圖片,進行壓縮處理,將處理過的圖片放到imageview中:
對於各個屬性的說明:
/**
* 打開本地相冊的requestcode.
*/
public static final int OPEN_PHOTO_REQUESTCODE = 0x1;
/**
* 圖片的target大小.
*/
private static final int target = 400;
private ImageView image;
/**
* matrix:這是一個圖片的變化矩陣(提供記錄圖片位置、記錄圖片縮放比例、實現圖片移動等 )
*/
private Matrix matrix;
/**
* curmatrix:記錄圖片當前位置的變換矩陣
*/
private Matrix curmatrix;
// 初始化模式參數
private int mode = 0;
// 無模式
private static final int NONE = 0;
// 拖拉模式
private static final int DRAG = 1;
// 縮放模式
private static final int ZOOM = 2;
/**
* startPoint:第一個點的座標
*/
private PointF startPoint = new PointF();;
/**
* startDistance:縮放前兩個點之間的距離
*/
private float startDistance;
/**
* endDistance:縮放後兩個點之間的距離
*/
private float endDistance;
/**
* middlePoint:兩個點之間的中點
*/
private PointF middlePoint;
/**
* ZOOM_THRESHOLD:當兩點的 startDistance距離大於ZOOM_THRESHOLD的時候才縮放
*/
private static final float ZOOM_THRESHOLD = 10.0f;
private Button show;
/**
* @description:打開相冊
* @author:hui-ye:
*/
private void setupViews() {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_PICK);
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
"image/jpeg");
startActivityForResult(intent, OPEN_PHOTO_REQUESTCODE);
}
從相冊中選擇圖片後,進行壓縮處理,並將圖片顯示在imageview中
// 對startActivityForResult(intent,OPEN_PHOTO_REQUESTCODE );啓動後的返回結果處理
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case OPEN_PHOTO_REQUESTCODE:
if (resultCode == RESULT_OK) {
Bitmap bitmap = null;
// 將返回的數據構建成bitmap
try {
bitmap = ImageCacheUtil.getResizedBitmap(null, null, this,
data.getData(), target, false);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "生成圖片失敗", 1).show();
}
if (bitmap != null) {
// 爲imageview設置圖片
image.setImageBitmap(bitmap);
}
}
break;
default:
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
最後處理圖片的縮放:
// 這裏對圖片的縮放處理
image.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
// 取得第一個觸控點的座標
case MotionEvent.ACTION_DOWN:
// 設置當前的模式爲拖拉模式
mode = DRAG;
// 記錄圖片當前的移動位置
curmatrix.set(image.getImageMatrix());
// 記錄當前的座標
startPoint.set(event.getX(), event.getY());
break;
// 屏幕上已經有觸控點了
case MotionEvent.ACTION_POINTER_DOWN:
// 如果是兩點觸控,則將mode設置爲縮放模式
mode = ZOOM;
// 獲取當前座標和第一個座標之間的距離
startDistance = spacing(event);
if (startDistance > ZOOM_THRESHOLD) {
// 獲取兩點之間的中點
middlePoint = getMiddlePoint(event);
// 記錄圖片當前的縮放比例
curmatrix.set(image.getImageMatrix());
}
break;
// 判斷觸控點的移動(一個點移動還是多點移動 )
case MotionEvent.ACTION_MOVE:
// 一個點的移動爲拖拉模式
if (mode == DRAG) {
// 獲取x軸的移動距離
float distanceX = event.getX() - startPoint.x;
// 獲取y軸的移動距離
float distanceY = event.getY() - startPoint.y;
// 設置 移動變換
curmatrix.set(image.getImageMatrix());
// 設置圖片的移動
matrix.postTranslate(distanceX, distanceY);
} else if (mode == ZOOM) {
// 結束距離
endDistance = spacing(event);
if (endDistance > ZOOM_THRESHOLD) {
// 縮放比例
float scale = endDistance / startDistance;
matrix.set(curmatrix);
matrix.postScale(scale, scale, middlePoint.x,
middlePoint.y);
}
}
case MotionEvent.ACTION_UP:
// 當手指離開屏幕,但屏幕上仍有其他觸點(手指)時觸發該事件
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
default:
break;
}
image.setImageMatrix(matrix);
return true;
}
});
// 計算移動距離
private float spacing(MotionEvent event) {
// event.getX(0)第一個點座標,event.getX(1)爲第二個點的座標
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
/**
* @description:獲得兩個點的中點座標
* @author:hui-ye
* @param event
* @return:
*/
public static PointF getMiddlePoint(MotionEvent event) {
float x = (event.getX(0) + event.getX(1)) / 2;
float y = (event.getY(0) + event.getY(1)) / 2;
return new PointF(x, y);
}
好了,介紹就到此爲止,其他的希望大家去研究 android API http://developer.android.com/training/displaying-bitmaps/index.html
附件是完整的程序代碼