2015年11月29日 星期日

Canvas, Bitmap, Drawable



Bitmap指的是你今天有一張圖片存在電腦,
它的格式可能是bmp, jpg, png或者gif, 常看到的是這幾個,
而Android剛好也支援這幾個, 因此我們可以用Bitmap這個類別的物件,
將我們的圖檔讀進Android, 通常讀進去以後它就變成串流模式(Stream),

View你可以想像成一種容器, 它可以用來裝你的Bitmap,
根據你事先排好的格式, 然後呈現在畫面上,
那系統因應user的需求, 也制定了一些需要的View容器給大家來使用,
例如ImageView、GridView、ListView、Button、EditText...等等。

Canvas就是一張畫布, 上面可以讓你畫你想畫的東西,
你可以想像成他就是小畫家工具,你想畫一條線, 一個矩形...等等,都可以。
那畫完以後把它裝到容器裡面,容器有哪些?
就是我們前面講的ImageView、GridView、ListView...等等, 就是系統幫我們做好的容器,
把我們畫的東西包成一個容器,容器裡面裝的是我們的畫布。

Drawable有時候我們會想要畫矩形, 畫圓形或者畫弧形之類的,
而如果是自己用手畫, 很容易, 但是如果是用程式畫,
你就必須自己設定角度、長度、大小、顏色等屬性,
這些步驟有點麻煩, 因此通常都會設定好一個框架讓你使用,
只需要你指定屬性值, Android就會幫你設計好, 不用在自己設計一套,
例如Drawable的子類別ShapeDrawable就可以幫你完成許多圖形,
ArcShape, OvalShape, RectShape...等等。


Paint就是畫筆, 你在小畫家上面畫畫的時候,
都會選擇畫筆來作畫, 像顏色, 粗細等之類的屬性,
將結果畫在畫布上面,通常Paint都會跟在Drawable的相關類別或者自定View類別一起使用。

ex: 取得Drawable的畫筆, 將畫筆改成藍色,最後完成藍色的矩形。
public class CustomDrawableView extends View{
    private ShapeDrawable mDrawable;
    private Paint mPaint;
    private int x = 0;
    private int y = 0;
    private int width = 100;
    private int height = 50;
    public CustomDrawableView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        mDrawable = new ShapeDrawable(new RectShape());
        mDrawable.setBounds(x,y,x+width,y+height);
   
        mPaint = mDrawable.getPaint();
        mPaint.setColor(Color.BLUE);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        mDrawable.draw(canvas);
    }
}






-----------------------------------
1. Bitmap 使用方法:
-----------------------------------

* 重點注意事項:
可配合 BitmapFactory 將 ByteArray, File, Resource, Stream 轉為 bitmap 物件。
同時可選配 BitmapFactory.Options 來設定 Bitmap 內容。

 - BitmapFactory 
decodeByteArray(byte[] data, int offset, int length, BitmapFactory.Options opts)
decodeFile(String pathName, BitmapFactory.Options opts)
decodeResource(Resources res, int id, BitmapFactory.Options opts)
decodeStream(InputStream is, Rect outPadding, BitmapFactory.Options opts)
 - BitmapFactory.Options
inJustDecodeBounds // 取得 Bitmap 參數,但不回傳 bitmap
inInputShareable
inPurgeable
inSampleSize // 設定取樣尺寸, 以此壓縮 尺寸來減少記憶體消耗
outHeight
outWidth

常用參數:
getHeight()
getWidth()
getScaledHeight(DisplayMetrics metrics)  //參考 display 解析度
getScaledWidth(DisplayMetrics metrics) //參考 display 解析度
setHeight(int height)
setHeight(int height)
isRecycled()

常用方法:
 - createBitmap
createBitmap(Bitmap source, int x, int y, int width, int height)
createBitmap(int width, int height, Bitmap.Config config)
createBitmap(DisplayMetrics display, int width, int height, Bitmap.Config config)
createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)
 - 其他效果
createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)
eraseColor(int c) //擦除颜色(INT C)
extractAlpha() //提取阿尔法()
recycle()

EX: 先讀取常寬,再縮放重制
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(data, 0, data.length, options);

int width=options.outWidth;
int height=options.outHeight;
float scale = 1000/height;

options = new BitmapFactory.Options();

options.inPurgeable = true;
options.inInputShareable = true;
options.inSampleSize=(int)scale;
Bitmap newbp = BitmapFactory.decodeByteArray(data, 0, data.length, options);


參考資料:

EX: Bitmap Touch 點擊事件

@Override
public boolean onTouchEvent(MotionEvent event)
{
    float x = event.getX();
    float y = event.getY();
    switch(event.getAction())
    {
        case MotionEvent.ACTION_DOWN:
        //Check if the x and y position of the touch is inside the bitmap
        if( x > bitmapXPosition && x < bitmapXPosition + bitmapWidth && y > bitmapYPosition && y < bitmapYPosition + bitmapHeight )
        {
            //Bitmap touched
        }
        return true;
    }
    return false;
}

How to make a bitmap using canvas clickable? :http://stackoverflow.com/questions/18826808/how-to-make-a-bitmap-using-canvas-clickable






-----------------------------------
2. Canvas 使用方法:
-----------------------------------
* 重點注意事項:
可繪製文字、圖型、顏色、圖片( 可參考 Rect 或 Matrix ,進行縮放或變形處理 )

常用參數:
getHeight
getWidth
getMatrix
getMaximumBitmapHeight
getMaximumBitmapWidth

常用方法:
drawARGB
drawColor
drawPoints  // 畫點
drawPath     // 畫線
drawArc       // 畫圓弧
drawOval     // 畫橢圓
drawCircle
drawLine, drawLines

drawText
drawRect
drawRoundRect
drawBitmap  (Bitmap bitmap, Matrix matrix, Paint paint), drawBitmap(Bitmap bitmap, Rect srcRectF dst, Paint paint)

rotate
scale
translate
skew            // 傾斜
restore()
save

EX:
1. 將文字繪製 Bitmap 上

Bitmap tempBp = Bitmap.createBitmap(PidBitmap.getWidth(), PidBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas tempCv = new Canvas(tempBp); // 依 tempBp 為基底
canvas.drawText( "Android Canvas" , center_x , center_y, mPaint);
canvas.restore();
// 透過 Canvas 在 tempBp 上繪製處理後,tempBp 將自動儲存變為新的結果 

2. 用於 SurfaceView 的繪製方式,透過 save and restore 來刷新視屏
canvas.save();
canvas.drawColor(Color.WHITE); // 繪製填滿色
canvas.rotate(45, center_x, center_y);
canvas.drawText( "Android Canvas" , center_x , center_y, mPaint);
canvas.restore();



參考資料:




-----------------------------------
3. Drawable 使用方法:
-----------------------------------
Drawable就是一個可畫的對象,其可能是一張位圖(BitmapDrawable),也可能是一個圖形(ShapeDrawable),
還有可能是一個圖層(LayerDrawable),我們根據畫圖的需求,創建相應的可畫對象
有別於 View,Drawable 沒有任何 facility 來接收處理事件和互相作用關係。
結合與 Drawable Resources ,用於動態圖片或圖片編輯中。

1、將Drawable轉化为Bitmap 
public static Bitmap drawableToBitmap(Drawable drawable) {   
        // 取 drawable 的長寬   
        int w = drawable.getIntrinsicWidth();   
        int h = drawable.getIntrinsicHeight();   
   
        // 取 drawable 的顏色格式   
        Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888   
                : Bitmap.Config.RGB_565;   
       // 建立對應 bitmap   
        Bitmap bitmap = Bitmap.createBitmap(w, h, config);   
        // 建立對應 bitmap 的畫布   
        Canvas canvas = new Canvas(bitmap);   
        drawable.setBounds(0, 0, w, h);   
        // 把 drawable 內容畫到畫布中   
        drawable.draw(canvas);   
        return bitmap;   
    }  

2、Bitmap轉換成Drawable 
Bitmap bm=xxx; //xxx根據你的情況獲取   
BitmapDrawable bd= new BitmapDrawable(getResource(), bm);    
因为BtimapDrawable是Drawable的子類,最終直接使用bd對象即可。

3、Drawable縮放 
public static Drawable zoomDrawable(Drawable drawable, int w, int h) {   
    int width = drawable.getIntrinsicWidth();   
   int height = drawable.getIntrinsicHeight();   
    // drawable轉換成bitmap   
    Bitmap oldbmp = drawableToBitmap(drawable);   
    // 創建操作圖片用的Matrix對象   
   Matrix matrix = new Matrix();   
    // 計算縮放比例   
    float sx = ((float) w / width);   
    float sy = ((float) h / height);   
    // 設置縮放比例   
    matrix.postScale(sx, sy);   
    // 建立新的bitmap,其內容是對原bitmap的縮放後的圖   
    Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height,   
            matrix, true);   
    return new BitmapDrawable(newbmp);   
}  

4利用ImageView 在畫面上顯示圖片

【第一種方式】xml layout 中 設定 src 屬性,讀取res/drawable中的圖片

【第二種方式】利用ImageView類別的方法,將res/drawable 中的圖片載入
    secondImage = (ImageView) findViewById(R.id.imageView2);
    secondImage.setImageResource(R.drawable.firefox);

【第三種方式】網址(url)抓到圖片再顯示
    thirdImage = (ImageView) findViewById(R.id.imageView3);
    thirdImage.setImageDrawable(loadImageFromURL("http://cdn.inside.com.tw/wp-content/uploads/2012/05/Chrome.jpg")); 


    private Drawable loadImageFromURL(String url){
        try{
            InputStream is = (InputStream) new URL(url).getContent();
            Drawable draw = Drawable.createFromStream(is, "src");
            return draw;
        }catch (Exception e) {
            //TODO handle error
            Log.i("loadingImg", e.toString());
            return null;
        }
    }



參考資料:




*補充:Drawable Resources
1. 使用種類:
 - Bitmap File
 - Layer List (LayerDrawable)
 - Clip Drawable (夾)
 - Scale Drawable 
 - Shape Drawable

2. 自定義圖形: Shape Drawable
Shape drawables provide four basic shapesRectangle (矩形)Oval (橢圓)Line, and Ring

All four shape types support the following tags (some of the shapes support additional tags, but this is the set supported by all of them):
 - gradient: Specify gradient backgrounds                                                           背景梯度 (漸層效果)
 - solid:         Specify solid background color                                                         實質背景顏色
 - padding: Specify padding between the edge of the shape and its contents    邊與內容之間的間距
 - size:         Specify the width and height                                                              長寬尺寸
 - stroke:         Specify a stroke line around the edge of the shape                           邊線設定 (線寬、顏色等等)

EX:rectangle.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:shape="rectangle">
  
  <solid android:color="#5500FF66" />

  <stroke 
    android:width="5dp"
    android:color="#009933" />

  <padding
    android:left="30dp"
    android:right="30dp"
    android:top="30dp"
    android:bottom="30dp" />
</shape>  

EX:shape_rounded_blue_rect.xml
<?xml version="1.0" encoding="utf-8"?>
<shape
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:shape="rectangle">
  
  <!-- Specify a gradient for the background -->
  <gradient
      android:angle="90"
      android:startColor="#55000066"
      android:centerColor="#FFFFFF"
      android:endColor="#55000066" />
  
  <!-- Specify a dark blue border -->
  <stroke 
    android:width="2dp"
    android:color="#000066" />
  
  <!-- Specify the margins that all content inside the drawable must adhere to -->
  <padding
    android:left="5dp"
    android:right="5dp"
    android:top="15dp"
    android:bottom="15dp" />
  
  <corners
      android:topLeftRadius="10dp"
      android:topRightRadius="10dp"
      android:bottomLeftRadius="10dp"
      android:bottomRightRadius="10dp" />
</shape>

EX: shape_oval_yellow.xml
<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">

    <gradient
        android:type="radial"
        android:gradientRadius="20"
        android:centerX=".6"
        android:centerY=".35"
        android:startColor="#FFFF00"
        android:endColor="#FFFF99" />

    <size
        android:width="100dp"
        android:height="100dp"/>
</shape>

EX: shape_oval_blue.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">

    <solid android:color="#0000FF" />

    <size
        android:width="30dp"
        android:height="30dp"/>

    <stroke
        android:dashWidth="3dp"
        android:dashGap="3dp"
        android:width="2dp"
        android:color="#0000FF" />
</shape>

EX: shape_oval_purple_gradient.xml
<?xml version="1.0" encoding="utf-8"?>
<shape
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:shape="oval">
  
  <gradient 
      android:type="sweep"
      android:startColor="#77990099"
      android:endColor="#22990099"/>
  
  <stroke
    android:width="1dp"
    android:color="#aa990099" />
  
  <padding
      android:left="10dp"
      android:right="10dp"
      android:top="10dp"
      android:bottom="10dp" />
</shape>



參考資料:

沒有留言:

張貼留言