android圖片繪制
『壹』 Android音視頻之使用OpenGL ES繪制圖片
關於 OpenGL ES 的介紹,請先看上篇: Android 音視頻之使用 OpenGL ES 繪制三角形 。
使用 OpenGL ES 繪制簡單的幾何形狀還不夠,OpenGL 更多地是用來顯示而紋理圖像,比如本地圖片、相機畫面。簡單說,紋理(texture)就是一個圖像或照片,它們可以被載入進 OpenGL 中。
OpenGL 中的紋理可以擾判用來表示圖像、照片等,每個二維的紋理都由許多小緩缺改的紋理元素組成,它們是小塊的數據,類似片段和像素。要使用紋理,最常用的方式是直接從一個圖像文件載入數據。
紋理不會被直接繪制,它們要被綁定到紋理單元,然後把這些紋理單元傳遞給著色器。紋理映射的基本思想就是:首先為圖元中的每個頂點指定恰當的紋理坐標,然後通過紋理坐標在紋理圖中可以確定選中的紋理區域,最後將選中紋理區域中的內容根據紋理坐標映射到指定的圖元上。
紋理的坐標系和頂點著色器的坐標系是不一樣的。紋理坐標用浮點數來表示,范圍 [0, 1],左上角坐標為 (0.0, 0.0),右上角坐標為 (1.0, 0.0)。注意:要將紋理坐標對應到正確的頂點上,才能使紋理正確扮銀地顯示。
定義頂點和紋理坐標,兩者的順序必須一一對應。
定義著色器。
載入圖片到 OpenGL 中。
計算變換矩陣,採用 CenterInside 或者 CenterCrop 的方式顯示。
顯示圖片。
源碼在 GitHub 上。
參考資料:
『貳』 Android的.9圖製作
先來認識一下界面,並可以看到不管是橫縱向拉升都使得圖片失真
下面四個小選項分別是
從上圖我們可以看到,不對圖片進行任何修改,圖片在某一方向拉伸時都是整體縮放的. 縮放同時,圖片圓角也會跟埋圓著縮放,導致最終展示效果很差.
在編輯區可以看到要編輯的圖片四周多了一像素的內容,這就是我們可以操作的區域了。
繪制小黑點 :只需要在四邊需要的位置左鍵單擊繪制小黑點,或者拖動繪制小黑線(其實是連續的多個小黑點)
刪除小黑點 :按shift鍵,並左鍵單擊或拖動進行刪除操作,也可以按住滑鼠右鍵進行擦除。
小黑點在png圖最外層有一像素寬的邊,除了四個頂角,小黑點可以繪制在png最外邊的任一點處,
每個小黑點占據一像素
小黑點繪制之後。其規定一個區域,即小黑點處,垂直於所在邊,且一像備液清素寬的區域
頂部:在水平拉伸的時候,保持其他位置不動,只在這個點代表區域做無限的延伸
左邊:在豎直拉伸的時候,保持其他位置不動,只在這個點代表區域做無限的延伸
底部:在水平拉伸的時候,指定圖片里的內容顯示的區域
右邊:在豎直拉伸的時候,指定圖片里的內容顯示的區域
從上圖可以看出拉伸後我們希望的箭頭區域沒有失真,並且而且箭頭距離右邊距與上邊距的距離沒有變因此,保證了想要部分不失真
首先沒有本質上的區別,下面通過一個例子來理解
假如有一個5px 5px大小的圖片,橫向上需要拉伸至20px
那麼就是要橫向拉升H=15px
假如橫向上畫了一個小黑點--則每個小黑點所代表區域拉伸h=15px h=H/1
假如橫向上畫了三個小黑點--則每個小黑點所代表區域拉伸h=5px h=H/3
因此 每條邊上的每個小黑點所代表區域拉伸的寬度是一樣的 *
所以要合理的布置我們的小喝仿前點以至png圖能夠達到我們想要的方向伸縮
點擊左上file- save,保存文件,自動生成一張後綴名為「*.9.png」格式的圖片,圖片上下左右各增加了1px的黑線。
9patch圖片是andriod app開發里一種特殊的圖片形式,文件的擴展名為:.9.png
「點九」也是由於Android平台多種解析度需適配的需求下,發展出來的一種獨特的技術。它可以將圖片橫向和縱向隨意進行拉伸,而保留像素精細度、漸變質感和圓角的原大小,實現多解析度下的完美顯示效果,同時減少不必要的圖片資源,可謂切圖利器。
.9.PNG確實是標準的PNG格式,只是在最外面一圈額外增加1px的邊框,這個1px的邊框就是用來定義圖片中可擴展的和靜態不變的區域。特別說明,left和top邊框中交叉部分是可拉伸部分,未選中部分是靜態區域部分。right和bottom邊框中交叉部分則是內容部分
無論是left和top,還是right和bottom都是把圖片分成9塊 (邊角四塊是不能縮放的,其他的四塊則是允許縮放的),所以叫做9.PNG。
.9.png圖片,android系統程序有對其優化的演算法。
參考
http://www.jianshu.com/p/3fd048644e3f
http://bbs.itheima.com/thread-251222-1-1.html
http://www.yimui.com/archives/117
『叄』 android 如何重寫imageview 讓圖片有圓角效果
android 自定義圓角ImageView以及鋸齒的處理
看到很多人開發過程中要使用圓角圖片時,解決方法有:
1.重新繪制一張圖片
2.通過布局來配置
3.通過重寫View來實現
其中1,2在這里就不講了,重點講講方法三的實現。
實現一:通過截取畫布一個圓形區域與圖片的相交部分進行繪制,缺點:鋸齒明顯,設置Paint,Canvas抗鋸齒無效。
package com.open.circleimageview.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Region;
import android.util.AttributeSet;
import android.view.View;
public class CircleImageViewA extends View {
public CircleImageViewA(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CircleImageViewA(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CircleImageViewA(Context context) {
super(context);
}
private Bitmap bitmap;
private Rect bitmapRect=new Rect();
private PaintFlagsDrawFilter pdf=new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);
private Paint paint = new Paint();
{
paint.setStyle(Paint.Style.STROKE);
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
paint.setAntiAlias(true);// 設置畫筆的鋸齒效果。 true是去除,大家一看效果就明白了
}
private Path mPath=new Path();
public void setImageBitmap(Bitmap bitmap)
{
this.bitmap=bitmap;
}
@Override
protected void onDraw(Canvas canvas) {
if(null==bitmap)
{
return;
}
bitmapRect.set(0, 0, getWidth(), getHeight());
canvas.save();
canvas.setDrawFilter(pdf);
mPath.reset();
canvas.clipPath(mPath); // makes the clip empty
mPath.addCircle(getWidth()/2, getWidth()/2, getHeight()/2, Path.Direction.CCW);
canvas.clipPath(mPath, Region.Op.REPLACE);
canvas.drawBitmap(bitmap, null, bitmapRect, paint);
canvas.restore();
}
}
實現二:通過PorterDuffXfermode 方式(注意要設置硬體加速,否則部分機子無效),優點:鋸齒基本沒有
package com.open.circleimageview.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
public class CircleImageViewB extends View {
public CircleImageViewB(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public CircleImageViewB(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CircleImageViewB(Context context) {
super(context);
init();
}
private Bitmap bitmap;
private Rect bitmapRect=new Rect();
private PaintFlagsDrawFilter pdf=new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);
private Paint paint = new Paint();
{
paint.setStyle(Paint.Style.STROKE);
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
paint.setAntiAlias(true);// 設置畫筆的鋸齒效果。 true是去除,大家一看效果就明白了
}
private Bitmap mDstB=null;
private PorterDuffXfermode xfermode=new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY);
private void init()
{
try {
if(android.os.Build.VERSION.SDK_INT>=11)
{
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void setImageBitmap(Bitmap bitmap)
{
this.bitmap=bitmap;
}
private Bitmap makeDst(int w, int h)
{
Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bm);
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
p.setColor(Color.parseColor("#ffffffff"));
c.drawOval(new RectF(0, 0, w, h), p);
return bm;
}
@Override
protected void onDraw(Canvas canvas) {
if(null==bitmap)
{
return;
}
if(null==mDstB)
{
mDstB=makeDst(getWidth(), getHeight());
}
bitmapRect.set(0, 0, getWidth(), getHeight());
canvas.save();
canvas.setDrawFilter(pdf);
canvas.drawBitmap(mDstB, 0, 0, paint);
paint.setXfermode(xfermode);
canvas.drawBitmap(bitmap, null, bitmapRect, paint);
paint.setXfermode(null);
canvas.restore();
}
}
『肆』 android是否可以以畫圖的形式將圖片畫在某位置
可以。
1、在View的onDraw中獲取canvas
java">@Override
protectedvoidonDraw(Canvascanvas){//onDraw中獲取參數中的canvas
//TODOAuto-generatedmethodstub
super.onDraw(canvas);
}
2、獲取圖片,轉化為Bitmap對象
//從資源文件中生成點陣圖bitmap
Bitmapbitmap=BitmapFactory.decodeResource(getResources(),R.drawable.icon);
3、通過canvas的drawbitmap方法,把圖片畫到任意位置。
//Bitmap:圖片對象,left:偏移左邊的位置,top:偏移頂部的位置
//rawBitmap(Bitmapbitmap,floatleft,floattop,Paintpaint)
canvas.drawBitmap(bitmap,10,60,paint);//在10,60處開始繪制圖片
『伍』 android 鑳藉湪灞忓箷涓婄粯涓寮犲皬鍥劇墖錛岀劧鍚庨忔槑鑳屾櫙錛岃繕鑳芥搷浣滆兘鐪嬪埌鐨勮儗鏅妗岄潰鍥炬爣鎴栫▼搴忋
package com.qdsx.cml;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
//import android.view.animation.AnimationUtils;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
public class TestdonghuaActivity extends Activity {
private ImageView tweenMM;
// private Animation animation;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tweenMM =(ImageView)findViewById(R.id.imageView1);
}
//娓愬彉
public void BtnAlphaOnClick(View view){
//this.doStartAnimation(R.anim.alpha_animation);
Animation b = new AlphaAnimation(0.1f, 1.0f);
b.setDuration(2000);
tweenMM.startAnimation(b);
}
//鏃嬭漿
public void BtnrotateOnClick(View view){
//this.doStartAnimation(R.anim.rotate_animation);
Animation c = new RotateAnimation(0, 360,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
c.setDuration(3000);
tweenMM.startAnimation(c);
}
//緙╂斁
public void BtnScaleOnClick(View view){
//this.doStartAnimation(R.anim.scale_animation);
Animation d = new ScaleAnimation(0f, 1f, 0f, 1f, Animation.RELATIVE_TO_SELF,0.5f, Animation.RELATIVE_TO_SELF,0.5f);
d.setDuration(3000);
tweenMM.startAnimation(d);
}
//浣嶇Щ
public void BtnTransalteOnclick(View view){
//this.doStartAnimation(R.anim.translate_animation);
Animation a= new TranslateAnimation(0, 100, 0, 100);
a.setDuration(5000);
a.setFillAfter(true);//浣垮浘鐗囩Щ鍔ㄥ悗鍥哄畾
tweenMM.startAnimation(a);
}
//寮濮嬪姩鐢繪柟娉
/* private void doStartAnimation(int animid){
animation = AnimationUtils.loadAnimation(this, animid);
animation.setFillAfter(true);//浣垮浘鐗囩Щ鍔ㄥ悗鍥哄畾
tweenMM.startAnimation(animation);
}*/
}
『陸』 Android超簡單實現炫酷的圖片展示效果
這里的實現原理很簡單,就是添加多個矩形路徑,並不斷的延長各個矩形路徑的寬度(通過onDraw方法的遞歸實現),然後在矩形路徑中繪制Bitmap即可。
1. 構建用於展示的Bitmap
這里我們選擇在onSizeChanged方法中初始化Bitmap,因為當控制項大小改變時方便我們重新計算所需展示Bitmap的大小。
2. 構建矩形裁剪區域並添加到Path中
3. 在對應的路徑中繪制出Bitmap
這里使用Canvas的clipPath方法將畫布裁切成路徑的形狀,然後在裁切後的畫布上繪制圖片。
4. 利用遞歸實現動畫效果
5. 當圖片完全顯示時替換圖片
圖片完全顯示也是cilpWidth>控制項寬度的時候。
掃描式圖片展示
『柒』 android畫一張圖片,縮放顯示並且放大不失真
這個問題涉及圖片呈現的一整套方案。歸納而言這個問題是:給定任意尺寸的圖片如何在任意尺寸解析度的機器上顯示?並且能夠保持圖片原來的清晰度。一般採用如下方案來解決這個問題:
1、首先給原圖片創建一塊內存緩存副本。如果不創建緩存的話,那麼任何一次圖片的剪切、縮放等操作都將丟失圖片信息,使得保持原有圖片的滋味那是不可能的。當然對於一般的程序而言,這個操作只需要調用簡單的API即可完成。例如Android,只需要創建一個對應圖片的Bitmap對象即可。
2、如果想要在設備顯示的初始化狀態圖片即為滿屏,那麼必須調用相關API動態獲得設備的解析度。然後按設備解析度的大小對圖片進行剪切並顯示到設備上。
注意:在獲得圖片解析度後,如果解析度大於圖片,那不用說,直接顯示圖片就好。但是如果小於圖片,此時有多種選擇。可以將圖片縮放至屏幕解析度(圖片縱橫比可能失真)也可以選擇剪切圖片的一部分顯示到屏幕上。
3、對圖片進行縮放或者移動
我們在圖片第一次顯示的時候無論是選擇縮放還是剪切,都要記錄下圖片被縮放的比例或者剪輯的范圍。這樣在用戶再次移動或者縮放的時候,根據之前的縮放比例和移動坐標,計算當前應該移動的位置和縮放比例。並且根據計算結果對緩存的圖片進行剪輯並顯示到屏幕上。
其實整個過程可以概括為如下流程:
——>圖片的初始縮放比例和顯示起點坐標——>用戶觸發縮放或者移動操作——>計算新的圖片縮放比例和顯示起點坐標——>根據新的縮放比例和顯示起點坐標剪輯緩存圖片並繪制到屏幕上......