安卓多媒體編程算法
1,計算機圖形的表示方式方法編程
1.1canvas
①像素點形式(單色位圖),一個像素點至關於1*1個像素,8個像素點就是8個0011佔據一個byte的位置,200*200=40000 40000/8 = 5000byte字節api
②24位位圖,一個像素點有24位(2的24次方)來表示顏色 ,3個byte.40000*24/8 = 120000byte字節異步
③256位圖,一個像素點佔256色,爲(2的8次方),一個byte.40000byte就能夠表示.ide
1.2工具
矢量圖形:儲存的是指令,而不是像素點佈局
位圖的缺陷:佔據體積比較大post
常見位圖格式:JPEG,PNG,BMP,前面兩種經過圖片壓縮算法減小儲存空間(即相同的顏色進行壓縮,由於人眼沒法識別這些細微差異)ui
2,加載圖片到內存
①經過BitmapFactory.docodeFile(path)解碼圖片到內存上
BitmapFactory.docodeXX,還能夠轉換流,文件(默認都是32位的位圖,a(透明度)rgb(顏色))
②若是加載過大的圖片,會出現OOM:Out of MemoryError 內存不足異常
雖然一個圖片看起來不大,可是經過BitMapFactory加載出來的圖片,是跟圖片的分辨率有關,一個像素就須要4個byte去表示
建立模擬器的時候有一個選項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));//設置顏色過濾器
而後根據拖動條改變對應的顏色便可