[Android] 給圖像添加相框、圓形圓角顯示圖片、圖像合成知識
來源:程序員人生 發布時間:2014-11-13 08:58:42 閱讀次數:3189次
前1篇文章講述了Android觸屏setOnTouchListener實現突破縮放、移動、繪制和添加水印,繼續我的"隨手拍"項目完成給圖片添加相框、圓形圓角顯示圖片和圖象合成的功能介紹.希望文章對大家有所幫助.
1. 打開圖片和顯示assets文件中圖片
首先,對XML中activity_main.xml進行布局,通過使用RelativeLayout相對布局完成(XML代碼后面附).然后,在Mainctivity.java中public
class MainActivity extends Activity函數添加代碼以下,添加點擊按鈕監聽事件:
//控件
private Button openImageBn; //打開圖片
private Button showImageBn; //顯示assets資源圖片
private Button showImageBn1; //模式1加成
private Button showImageBn2; //模式2加成
private Button roundImageBn; //圓角圖片
private ImageView imageShow; //顯示圖片
//自定義變量
private Bitmap bmp; //原始圖片
private final int IMAGE_OPEN = 0; //打開圖片
private Canvas canvas; //畫布
private Paint paint; //畫刷
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//打開圖片
openImageBn = (Button)findViewById(R.id.button1);
imageShow = (ImageView) findViewById(R.id.imageView1);
openImageBn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, IMAGE_OPEN);
}
});
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
}
//打開圖片
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode==RESULT_OK && requestCode==IMAGE_OPEN) {
Uri imageFileUri = data.getData();
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels; //手機屏幕水平分辨率
int height = dm.heightPixels; //手機屏幕垂直分辨率
try {
//載入圖片尺寸大小沒載入圖片本身 true
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = true;
bmp = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageFileUri), null, bmpFactoryOptions);
int heightRatio = (int)Math.ceil(bmpFactoryOptions.outHeight/(float)height);
int widthRatio = (int)Math.ceil(bmpFactoryOptions.outWidth/(float)width);
//inSampleSize表示圖片占原圖比例 1表示原圖
if(heightRatio>1&&widthRatio>1) {
if(heightRatio>widthRatio) {
bmpFactoryOptions.inSampleSize = heightRatio;
}
else {
bmpFactoryOptions.inSampleSize = widthRatio;
}
}
//圖象真正解碼 false
bmpFactoryOptions.inJustDecodeBounds = false;
bmp = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageFileUri), null, bmpFactoryOptions);
imageShow.setImageBitmap(bmp);
}
catch(FileNotFoundException e) {
e.printStackTrace();
}
} //end if
}
上面點擊"打開"按鈕能實現打開圖片,而在講述為圖片添加邊框時,它其實就是通過兩張或多張圖片的合成實現的.
在jacpy.may《Android圖片處理總結》文檔中建議圖片不要放在drawable目錄下,由于屏幕分辨率會影響圖片的大小.最好放在assets目錄里,它代表利用沒法直接訪問的原生資源(通常加載PNG透明圖實現邊框合成),只能以流的方式讀取并且小于1M.
讀取assets文件夾中圖片的方法以下,首先手動添加PNG圖片至assets目錄,然后在omCreate函數中添加以下代碼:
//顯示assets中圖片
showImageBn = (Button)findViewById(R.id.button2);
showImageBn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Bitmap bitmap = getImageFromAssets("image01.png");
imageShow.setImageBitmap(bitmap);
}
});
再通過自定義函數getImageFromAssets實現獲得圖片"image01.png":
//獲得assets中資源并轉換為Bitmap
private Bitmap getImageFromAssets(String fileName)
{
//Android中使用assets目錄寄存資源,它代表利用沒法直接訪問的原生資源
Bitmap imageAssets = null;
AssetManager am = getResources().getAssets();
try {
InputStream is = am.open(fileName);
imageAssets = BitmapFactory.decodeStream(is);
is.close();
} catch(IOException e) {
e.printStackTrace();
}
return imageAssets;
}
顯示效果以下圖所示:
其中XML代碼以下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.touchimagetest.MainActivity"
tools:ignore="MergeRootFrame" >
<!-- 底部添加按鈕 -->
<RelativeLayout
android:id="@+id/MyLayout_bottom"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:gravity="center">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_alignParentBottom="true" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="打開" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="顯示" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="邊框" />
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="桃心" />
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="圓形" />
</LinearLayout>
</RelativeLayout>
<!-- 頂部顯示圖片 -->
<RelativeLayout
android:id="@+id/Content_Layout"
android:orientation="horizontal"
android:layout_above="@id/MyLayout_bottom"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="#000000"
android:gravity="center">
<ImageView
android:id="@+id/imageView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_horizontal" />
</RelativeLayout>
</RelativeLayout>
2. 添加相框與圖片合成
然后開始完成圖片合成的工作,這里我采取兩種方法完成.繼續在onCreate函數中添加代碼:
//模式1合成圖片
showImageBn1 = (Button)findViewById(R.id.button3);
showImageBn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Bitmap bitmap = getImageFromAssets("image01.png");
addFrameToImage(bitmap);
}
});
通過自定義函數addFrameToImage實現加載圖片合成.首先創建1個空的可變成圖對象,它的大小和配置與打開的圖象相同,隨后構建1個Canvas對象和1個Paint對象,在畫布上繪制第1個位圖對象,它成了合成操作的目標.
現在設置Paint對象上的過渡模式,通過傳入1個定義操作模式的常量,實例化1個新的PorterDuffXfermode對象.然后在Canvas對象上繪制第2個位圖對象,并將ImageView設置為新的位圖對象.代碼以下:
//圖片合成1
private void addFrameToImage(Bitmap bm) //bmp原圖(前景) bm資源圖片(背景)
{
Bitmap drawBitmap =Bitmap.createBitmap(bmp.getWidth(),
bmp.getHeight(), bmp.getConfig());
canvas = new Canvas(drawBitmap);
paint = new Paint();
canvas.drawBitmap(bmp, 0, 0, paint);
paint.setXfermode(new PorterDuffXfermode(android.
graphics.PorterDuff.Mode.LIGHTEN));
//對邊框進行縮放
int w = bm.getWidth();
int h = bm.getHeight();
//縮放比 如果圖片尺寸超過邊框尺寸 會自動匹配
float scaleX = bmp.getWidth()*1F / w;
float scaleY = bmp.getHeight()*1F / h;
Matrix matrix = new Matrix();
matrix.postScale(scaleX, scaleY); //縮放圖片
Bitmap copyBitmap = Bitmap.createBitmap(bm, 0, 0, w, h, matrix, true);
canvas.drawBitmap(copyBitmap, 0, 0, paint);
imageShow.setImageBitmap(drawBitmap);
}
第2種方法是參照《Android多媒體開發高級編程》,但是它圖片104合成效果不是很好:
//模式2合成圖片
showImageBn2 = (Button)findViewById(R.id.button4);
showImageBn2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Bitmap bitmap = getImageFromAssets("image07.png");
//第2種合成方法
imageShow.setImageBitmap(addFrameToImageTwo(bitmap));
}
});
然后通過自定義函數實現:
//圖片合成
private Bitmap addFrameToImageTwo(Bitmap frameBitmap) //bmp原圖 frameBitmap資源圖片(邊框)
{
//bmp原圖 創建新位圖
int width = bmp.getWidth();
int height = bmp.getHeight();
Bitmap drawBitmap =Bitmap.createBitmap(width, height, Config.RGB_565);
//對邊框進行縮放
int w = frameBitmap.getWidth();
int h = frameBitmap.getHeight();
float scaleX = width*1F / w; //縮放比 如果圖片尺寸超過邊框尺寸 會自動匹配
float scaleY = height*1F / h;
Matrix matrix = new Matrix();
matrix.postScale(scaleX, scaleY); //縮放圖片
Bitmap copyBitmap = Bitmap.createBitmap(frameBitmap, 0, 0, w, h, matrix, true);
int pixColor = 0;
int layColor = 0;
int newColor = 0;
int pixR = 0;
int pixG = 0;
int pixB = 0;
int pixA = 0;
int newR = 0;
int newG = 0;
int newB = 0;
int newA = 0;
int layR = 0;
int layG = 0;
int layB = 0;
int layA = 0;
float alpha = 0.8F;
float alphaR = 0F;
float alphaG = 0F;
float alphaB = 0F;
for (int i = 0; i < width; i++)
{
for (int k = 0; k < height; k++)
{
pixColor = bmp.getPixel(i, k);
layColor = copyBitmap.getPixel(i, k);
// 獲得原圖片的RGBA值
pixR = Color.red(pixColor);
pixG = Color.green(pixColor);
pixB = Color.blue(pixColor);
pixA = Color.alpha(pixColor);
// 獲得邊框圖片的RGBA值
layR = Color.red(layColor);
layG = Color.green(layColor);
layB = Color.blue(layColor);
layA = Color.alpha(layColor);
// 色彩與純黑色相近的點
if (layR < 20 && layG < 20 && layB < 20)
{
alpha = 1F;
}
else
{
alpha = 0.3F;
}
alphaR = alpha;
alphaG = alpha;
alphaB = alpha;
// 兩種色彩疊加
newR = (int) (pixR * alphaR + layR * (1 - alphaR));
newG = (int) (pixG * alphaG + layG * (1 - alphaG));
newB = (int) (pixB * alphaB + layB * (1 - alphaB));
layA = (int) (pixA * alpha + layA * (1 - alpha));
// 值在0~255之間
newR = Math.min(255, Math.max(0, newR));
newG = Math.min(255, Math.max(0, newG));
newB = Math.min(255, Math.max(0, newB));
newA = Math.min(255, Math.max(0, layA));
//繪制
newColor = Color.argb(newA, newR, newG, newB);
drawBitmap.setPixel(i, k, newColor);
}
}
return drawBitmap;
}
它的運行效果以下所示,其中前2附圖是方法1,但是它的合成效果不是很優秀,而第3張圖是第2種方法,但是它的響應時間略微要長些.

在第1種方法通過PoterDuffXfermode類作為過渡模式,該類因Thomas Porter和Tom Duff而得名,他們于1984年在ACM SIGGRAPH計算機圖形學發表“Compositing digital images(合成數字圖象)”的文章,它介紹了彼此堆疊繪制圖象的不同規則.這些規則定義了哪些圖象的哪些部份將出現在結果輸出中.
在Android的PorterDuff.Mode類中羅列了Porter和Duff及其他更多人制定的規則.
android.graphics.PorterDuff.Mode.SRC:此規則意味著只繪制源圖象,當前它正是利用此規則的Paint對象.
android.graphics.PorterDuff.Mode.DST:此規則意味著只顯示目標圖象,在已有畫布上的初始圖象.
以下圖所示,定義Mode值以下:

其中,有4個規則定義了當1幅圖象放置在另外一幅圖象上時如何合成這兩幅圖象,它是我們常常使用的值:
android.graphics.PorterDuff.Mode.LIGHTEN:取得每一個位置上兩幅圖象中最亮的像素并顯示.
android.graphics.PorterDuff.Mode.DARKEN:取得每一個位置上兩幅圖象中最暗的像素并顯示.
android.graphics.PorterDuff.Mode.MULTIPLY:將每一個位置的兩個像素相乘,除以255,使用該值創建1個新的像素進行顯示.結果色彩=頂部色彩*底部色彩/255.
android.graphics.PorterDuff.Mode.SCREEN:反轉每一個色彩,履行相同操作.結果色彩=255-(((255-頂部色彩)*(255-底部色彩))/255)
3. 圓形和圓角矩形顯示圖片
最后講述如何實現圓形和圓角矩形顯示圖片,在onCreate函數中添加以下代碼:
//圓角合成圖片
roundImageBn = (Button)findViewById(R.id.button5);
roundImageBn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
imageShow.setImageBitmap(getRoundedCornerBitmap(bmp) );
}
});
然后通過自定義函數getRoundedCornerBitmap實現圓形:
//生成圓角圖片
private Bitmap getRoundedCornerBitmap(Bitmap bitmap)
{
Bitmap roundBitmap = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(roundBitmap);
int color = 0xff424242;
Paint paint = new Paint();
//設置圓形半徑
int radius;
if(bitmap.getWidth()>bitmap.getHeight()) {
radius = bitmap.getHeight()/2;
}
else {
radius = bitmap.getWidth()/2;
}
//繪制圓形
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawCircle( bitmap.getWidth()/ 2, bitmap.getHeight() / 2, radius, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, 0, 0, paint);
return roundBitmap;
}
一樣,如果把該函數里面內容替換便可實現圓形矩形顯示圖片:
private Bitmap getRoundedCornerBitmap(Bitmap bitmap)
{
//繪制圓角矩形
Bitmap roundBitmap = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(roundBitmap);
int color = 0xff424242;
Paint paint = new Paint();
Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
RectF rectF = new RectF(rect);
float roundPx = 80; //轉角設置80
//繪制
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
}
運行結果以下圖所示:

總結:
該文章主要講述如何給圖象增加相框,圓角顯示圖象和圖象合成的介紹.里面主要通過源碼并有詳細的進程,為何要寫這篇文章?由于在圖象處理中我認為這類添加邊框、改變邊框、圖片合成都屬于同1種類型的變化和渲染.該圖象處理軟件還沒有整合,推薦大家看下面資料中兩本書.
最后希望文章對大家有所幫助,如果有不足或毛病的地方請見諒!不論如何,我覺得這篇文章自己寫得不錯,自己先給自己1個贊吧!加油(^o^)/~
下載地址:http://download.csdn.net/detail/eastmount/8102845
源碼基本格式以下圖所示:

(By:Eastmount 2014⑴0⑶1 夜3點 http://blog.csdn.net/eastmount)
參考資料與推薦博文:
1.最該感謝的是兩本書的作者《Android多媒體開發高級編程》和《Android圖片處理總結 著:jacpy.may》,網上很多資料都是它們.
2.android圖象處理系列之6--給圖片添加邊框(下)-圖片疊加
作者-SJF0115 他是轉載了該書的1些文章,也非常不錯.
3.Android 圖片合成:添加蒙板效果 不規則相框 透明度漸變效果的實現
作者-HappyDelano 非常不錯的文章,講述了4張圖實現桃心顯示的效果.
4.Android圖片合成 作者-johnlxj 講述了圖片合成的實現進程.
5.Android 完善實現圖片圓角和圓形(對實現進行分析)
作者-鴻洋_ 該作者很多android文章都非常不錯
6.android 畫圖之setXfermode 作者-lipeng88213
推薦起鏈接的Android圖片倒影
7.Android ImageView點擊選中后添加邊框 作者-黑米粥 該方法在切換圖片中實用
8.android 輕松實現在線即時聊天【圖片、語音、表情、文字】 作者-anonymousblogs
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈