Android11_圖片處理

安卓多媒體編程算法

1,計算機圖形的表示方式方法編程

1.1canvas

①像素點形式(單色位圖),一個像素點至關於1*1個像素,8個像素點就是80011佔據一個byte的位置,200*200=40000 40000/8 = 5000byte字節api

24位位圖,一個像素點有24(224次方)來表示顏色 ,3byte.40000*24/8 = 120000byte字節異步

256位圖,一個像素點佔256,(28次方),一個byte.40000byte就能夠表示.ide

1.2工具

矢量圖形:儲存的是指令,而不是像素點佈局

 

位圖的缺陷:佔據體積比較大post

常見位圖格式:JPEG,PNG,BMP,前面兩種經過圖片壓縮算法減小儲存空間(即相同的顏色進行壓縮,由於人眼沒法識別這些細微差異)ui

 

2,加載圖片到內存

①經過BitmapFactory.docodeFile(path)解碼圖片到內存上

BitmapFactory.docodeXX,還能夠轉換流,文件(默認都是32位的位圖,a(透明度)rgb(顏色))

②若是加載過大的圖片,會出現OOM:Out of MemoryError 內存不足異常

雖然一個圖片看起來不大,可是經過BitMapFactory加載出來的圖片,是跟圖片的分辨率有關,一個像素就須要4byte去表示

建立模擬器的時候有一個選項VM heep一個應用程序能申請的最大內存空間,默認16MB

 

2.2 加載大圖片到手機中

對圖片進行縮放:BitMapFactory.docodeFIle(path,opts(能夠是空,也能夠壓縮));

Option opts = new Option();

opts.inSampleSize=xx,設置採樣率,若是設置的值大於1,就會從新採樣原圖,返回一個小一點的圖片用來節約內存,若是等於4,就把原來的圖片寬高縮小爲原來四分之一,至關於總像素個數佔原來的十六分之一.

通常的計算方式:根據當前手機的分辨率進行計算

①獲取手機的寬高信息,和圖片的分辨率

②獲取圖片的分辨率(寬高信息)

ExifInterface exif =new xxxx(filepath);//獲得照片的頭信息(拍攝信息,時間,地點,類型)

exif.getAttribute(ExifInterface.XXXX);//有一些常量能夠獲取信息.

exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH,默認值(0))

//有的文件是經過圖片軟件生成的,或畫出來的,沒有頭信息

這時候就要採用另外一種作法

Option opt1 = new Option();

Opt1.inJustDecodeBounds = true;//設置爲false就沒有把bitmap加載到內存

//不把圖片加載到內存,而是先獲取寬高,再進行縮放比

//注意這裏須要先讓程序解析一次

BitmapFactory.decodeFile(img.getAbsolutePath(), opts);

Opt1.outHeight; opt1.outWidth;

//設置爲false以後再解析一次

BitmapFactory.decodeFile(img.getAbsolutePath(), opts);

 

③獲取手機屏幕的寬高

//獲取屏幕管理器

WindowManager wm = getSystemService(WINDOW_SERVICE);

wm.getDefultDisplay().getXXX()//寬高,(推薦使用getSize(Point outsize)大小)

Point outsize = new Point();//api13開始使用的

④計算縮放比,按大一點的縮放比比較好一些,按公司的業務需求來

 

3,圖形的縮放

需求,對圖片進行縮放並顯示在頁面上

①獲取原圖,

BitMap srcMap= BitMapFactory.decodeFile(path);

把原圖加載進內存(通常都不對原圖進行處理,而是處理原圖在內存中的拷貝)建立原圖在內存中的拷貝:

//建立一個等大小,類型的空白圖片

copyedBitmap = BitMap.createBitMap(,,圖形的類型)//返回一個能夠編輯的bmp圖片,指定寬高和類型,通常在安卓裏指定32位位圖,獲取原圖的類型,srcMap.getConfig();

//建立一個畫板,傳入建立的空白圖片

Canvas canvas = new Canvas(copyedBitmap);

//建立一個畫筆

Paint paint new Paint();

//設置畫筆的顏色

paint.setColor(Color.Black);

//開始畫畫

Matrix matrix = new Matrix();//按照1:1的比例做畫

matrix.setScale(sx(0.2f),sy)//水平,豎直方向的縮放比,單位f

canvas.drawBitMap(原圖,變化矩陣,paint);

//把拷貝出來的圖片顯示在界面上,

setImageBitMap()會自動處理圖片適應屏幕

 

3.2

3.2.1圖片的平移

matrix.setTranslate(dx,dy);//水平,豎直方向的偏移量,移動圖片的像素點(會丟失圖片內容)

3.2.2圖片的旋轉

matrix.setRotate(旋轉的角度);以左上角爲原點進行旋轉

matrix.setRotate(旋轉的角度,px,py)//以指定的座標旋轉(若是想讓它以中心旋轉,座標設置寬高的二分之一)

3.2.3鏡面效果,本質上是X座標軸取反,Y軸不變,而後平移過來(或者覆蓋原有圖片)

matrix.setScale(-1,1)//寬度變成原來的負值,這時候圖片會超出屏幕,須要移動回來

matrix.setTranslate(srcbitmap.getWidth(),0)//移動對應圖片的寬度

setXXX都是設置的方法,不能同時生效,後面的會覆蓋前面的

若是但願後面的方法實現,須要使用postTranslate(XXXXX)方法,在上一次修改以後的基礎上進行變化.

3.2.4倒影效果,上下翻轉(Y軸取反,X軸不變)(跟旋轉180度效果不是同樣的)

 

4,練習,隨手塗鴉

4.1 ui佈局

第一排,工具欄,供用戶選擇畫筆的顏色,並顯示對應顏色的區塊,

畫筆的粗細(用戶輸入,或經過SeekBar設置也能夠)

setMax(最大值),默認值progress(5,其它也能夠)

剩餘區域繪畫區域

4.2 MainActivity,找到這些控件,設置對應的點擊事件

①建立一個畫筆

Paint paint = new Paint();

paint.setColor( 指定畫筆的顏色);

paint.setStorkeWidth(width);//設置畫筆的寬度

SeekBar相關

SeekBar.setOnSeekBarChangeListener();//拖動變化監聽器

seekbar.getProgress()//獲取當前拖動的狀態

 

4.3①做畫位置實際是在一個ImageView中做畫

要提早指定ImageView的寬高,由於一旦被加載就固定了

//imageView註冊一個觸摸事件

iv.setOnTouchListener(new OnTouchListener(){

//當被觸摸的時候調用

public boolean onTouch(View v,MotionEvent event){

//經過按下的動做判斷(按下觸摸的時候,保持拖動的時候,鬆開觸摸的時候)

switch(event.getAction){

case: MotionEvent.Action_MOVE

每移動一個像素點調用一次

break;

case: MotionEvent.Action_DOWN

break;

case: MotionEvent.Action_UP

break;

}

//返回值默認返回一個false,表明:事件沒有處理完畢,要等待事件處理完畢.

//若是爲flase移動和鬆開手指的事件就不會執行,一直在等待按下事件結束.

//true:表明事件已經處理完畢,沒有處理完就不會觸發鬆開和拖動事件

//

return true;

}

});

②須要一個能夠被修改的圖片

BitMap alertMap ;//須要的圖片

Canvas canvas;//定義畫板,畫筆已經有了

alertMap = BitMap.createBitMap(320,320,BitMap.ARGB_8888);//8888高質量的位圖.

Canvas = new Canvas(alertMap);

③在控件觸摸事件方法中

定義橫縱座標int x int y .

在按下的位置,獲取座標

在拖動的時候,獲取座標

canvas.drawLine(sx,sy,nx,ny,畫筆);//執行完這個方法後就畫出了一條線

Iv.setImageBitMap(alertMap)//把線顯示在控件上

//可是這樣作,會出現開始座標固定的狀況下畫出一個不想要的圖形,須要從新初始化手指在屏幕上的座標(實際上一條線是由無數個短線拼接,也就是兩個像素點之間的拼接,而不改變初始位置,就會像畫了個大圓餅)

 

4.4 其它細節問題

(0)拿取控件的寬高拿不到,由於控件的繪製是跟Activity異步的,就算執行了onCreate,onStart,onResume()都拿不到.

(1)要經過view繪製成功的監聽獲取,但在監聽的時候若是繪製的view發生改變了,就會從新繪製一次,因此能夠在獲取到一次數據以後把監聽註銷掉

(2)獲取繪製監聽事件iv.getViewTreeObs

(3)LinearLayout繪製順序,先繪製最外層的Liner 再按設置的順序,從上至下繪製,樹形結構的繪製,開發中不建議佈局LinearLayOut的嵌套,由於比較消耗時間

     //註冊View繪製監聽事件

   iv_show.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

@Override

public void onGlobalLayout() {

//註銷監聽

iv_show.getViewTreeObserver().removeGlobalOnLayoutListener(this);

}

});

①在Activity,onCreateOptionMenu(Menu menu)//建立一個選項菜單調用的方法

//本質上就是一個在底部出現的ListView視圖,裏面的控件都是item

判斷用戶點擊的是哪個條目menu.getItemId();

//保存圖片,BitMap轉換爲流,能夠保存在內存中,內存輸出流

alertBitMap.compress(format(保存的格式),quality(圖片的質量1-100),stream輸出流);

記得關流

//這樣輸出的圖片背景顏色是黑色,由於BitMap默認都是黑色的,因此建立好了畫板以後

canvas.drawColor(Color.WHITE);//畫一個白色的背景

②在圖庫應用中找不到畫的圖片,由於系統圖庫是不知道這個圖片被添加了,只有在開機或SD卡拔從新插入添加以後纔會掃描添加

這時候就要告訴圖庫,圖片被添加了

經過模擬SD卡被插入的廣播,告訴圖庫須要從新掃描一次 4.4版本以後就不能用了

Intent intent = new Intent();//建立意圖

intent.setAction(Intent.ACTION.MEDIA_MOUNTED);//設置動做

intent.setData(Uri.fromFile(Environment.getExternalStorageDirectory()));//設置文件

sendBroadCast(intent);//發送廣播

 

5.撕衣服的小應用

①對圖片進行縮放處理,代碼拷貝圖片,不對原圖進行操做

本質上是兩張圖片相互覆蓋,若是在圖片上滑動,就把滑動的區域設置爲透明.

//不要修改原圖,先建立一個原圖的拷貝

建立空白圖片,建立畫板,建立畫筆,畫一個跟原圖同樣的圖片

②設置觸摸事件

onTouch方法返回值記得設置爲true

觸摸的點設置爲透明

設置按下點爲透明,alertBitmap.setPixel(x,y,Color.TRANSPARENT)//設置爲透明的

而後從新設置圖片lv.setImageBitMap(圖片)便可

③撕衣服用戶體驗差,須要提升撕衣服的範圍

//經過 for循環把對應座標點的周圍的點也設置爲透明

這樣每次的透明塊是一個矩形塊,很差看,要每次的透明塊爲一個圓形更好

由此圖可知,須要一個圓形,就表明這個像素點的座標到圓心的距離小於等於3(經過勾股定理能夠算出)

Math.sqrt()開平方

④若是超出圖片範圍就崩潰.

處理方式:把異常捕獲進來,而後超出圖片就不會出異常(尷尬)

⑤getX()和getrawX()的區別raw(未經處理的)

getrawX()距離屏幕左邊的距離.getrawY()距離屏幕上邊的距離

getX()距離當前控件的左邊距離,getY()距離當前控件上邊的距離

 

6,圖片顏色的處理

圖像顏色的處理:把每一個像素點的顏色按照必定的規則進行變化,就會出現新的效果

顏色矩陣模板代碼:

ColorMatrix cm = new ColocrMartix();//顏色矩陣

Cm.set(new float[]{

1*result(變化比例),0,0,0,0, //red

0,1,0,0,0, //green

0,0,1,0,0, //blue

0,0,0,1,0 //透明度

});

paint.setColorFilter(new ColorMatrixColorFilter(cm));//設置顏色過濾器

而後根據拖動條改變對應的顏色便可

相關文章
相關標籤/搜索