天天看點

Android攝像頭:隻拍攝SurfaceView預覽界面特定區域内容(矩形框)---完整實作(原理:底層SurfaceView+上層繪制ImageView)

http://blog.csdn.net/yanzi1225627/article/details/8580034

最近一直在審視以前做過的東西,關于android攝像頭預覽,預覽界面上呈現矩形框,在前文(

)----http://blog.csdn.net/yanzi1225627/article/details/7934710已經實作。最近發現上層繪制矩形框,用surfaceview有點大材小用了。surfaceview繪制動畫更合适,隻繪制個矩形框用imageview足夠了。但有些時候必須要用surfaceview來實作。比如360手機安全衛士掃描二維碼的實作應該就是通過上下兩層surfaceview實作的(見下圖)。上層surfaceview用于顯示那個可以旋轉的掃描示意框,底層surfaceview預覽攝像頭視訊。

Android攝像頭:隻拍攝SurfaceView預覽界面特定區域内容(矩形框)---完整實作(原理:底層SurfaceView+上層繪制ImageView)

     廢話不說了,稍候幾天我會仿照上面360這個掃描二維碼的界面做一個工程(結合previewcallback),公開出來。這次先談用底層surfaceview+上層imageview實作隻拍攝矩形框中的圖像。建立一個類繼承imageview,源碼如下:

[java] view

plaincopy

package yan.guoqi.rectphoto;  

import android.content.context;  

import android.graphics.canvas;  

import android.graphics.color;  

import android.graphics.paint;  

import android.graphics.paint.style;  

import android.graphics.rect;  

import android.util.attributeset;  

import android.widget.imageview;  

public class drawimageview extends imageview{  

    public drawimageview(context context, attributeset attrs) {  

        super(context, attrs);  

        // todo auto-generated constructor stub  

    }  

    paint paint = new paint();  

    {  

        paint.setantialias(true);  

        paint.setcolor(color.red);  

        paint.setstyle(style.stroke);  

        paint.setstrokewidth(2.5f);//設定線寬  

        paint.setalpha(100);  

    };  

    @override  

    protected void ondraw(canvas canvas) {  

        // todo auto-generated method stub  

        super.ondraw(canvas);  

        canvas.drawrect(new rect(100, 200, 400, 500), paint);//繪制矩形  

}  

布局檔案裡與前文http://blog.csdn.net/yanzi1225627/article/details/8577756這裡一樣,隻是在幀布局裡加一個上面自定義的drawimageview,整個布局檔案示下:

[html] view

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"  

    xmlns:tools="http://schemas.android.com/tools"  

    android:layout_width="fill_parent"  

    android:layout_height="fill_parent"  

    android:orientation="vertical" >  

    <textview  

        android:layout_width="wrap_content"  

        android:layout_height="wrap_content"  

        android:text="@string/bestwish"  

        tools:context=".rectphoto" />  

    <framelayout  

        android:layout_height="wrap_content" >  

        <surfaceview  

            android:id="@+id/previewsv"  

            android:layout_width="fill_parent"  

            android:layout_height="800px" />  

        <yan.guoqi.rectphoto.drawimageview  

             android:id="@+id/drawiv"  

             android:layout_width="fill_parent"  

             android:layout_height="800px"  

            />  

    </framelayout>  

    <imagebutton  

        android:id="@+id/photoimgbtn"  

        android:background="@drawable/photo_img_btn"  

        android:layout_gravity="center" />  

</linearlayout>  

      在主程式檔案裡,oncreate()函數裡設定底層surfaceview為底層且透明(如果不設也可以,預設就是如此):

mpreviewsv.setzorderontop(false);

mysurfaceholder.setformat(pixelformat.transparent);//translucent半透明 transparent透明

     在主ui線程裡的oncreate()函數裡添加代碼: 

        //繪制矩形的imageview

        mdrawiv = (yan.guoqi.rectphoto.drawimageview)findviewbyid(r.id.drawiv);

        mdrawiv.ondraw(new canvas());

       看上面的drawimageview的函數裡的ondraw,畫的矩形是rect(100, 200, 400, 500)。在onpicturetaken(byte[] data, camera camera)函數裡,先将圖檔旋轉90度,大小成為寬×高(960×1280)。由于預覽surfaceview的大小是寬×高(540×800),是以在onpicturetaken函數裡将960×1280的圖檔縮放到540×800, 縮放相同大小後就可以用矩陣的坐标直接截取子圖了。核心函數就是這兩句:

        //将960×1280縮放到540×800

            bitmap sizebitmap = bitmap.createscaledbitmap(rotabitmap, 540, 800, true);

            bitmap rectbitmap = bitmap.createbitmap(sizebitmap, 100, 200, 300, 300);//截取

     注意這個截取的函數參數和矩陣的坐标關系,分别是x軸 y軸起始坐标及 x軸寬度 y軸寬度。截取出來的圖檔大小應該是300×300. onpicturetaken()函數的源碼如下:

public void onpicturetaken(byte[] data, camera camera) {  

            // todo auto-generated method stub  

            log.i(tag, "myjpegcallback:onpicturetaken...");  

            if(null != data){  

                mbitmap = bitmapfactory.decodebytearray(data, 0, data.length);//data是位元組資料,将其解析成位圖  

                mycamera.stoppreview();  

                ispreview = false;  

            }  

            //設定focus_mode_continuous_video)之後,myparam.set("rotation", 90)失效。圖檔竟然不能旋轉了,故這裡要旋轉下  

            matrix matrix = new matrix();  

            matrix.postrotate((float)90.0);  

            bitmap rotabitmap = bitmap.createbitmap(mbitmap, 0, 0, mbitmap.getwidth(), mbitmap.getheight(), matrix, false);  

            //旋轉後rotabitmap是960×1280.預覽surfaview的大小是540×800  

            //将960×1280縮放到540×800  

            bitmap sizebitmap = bitmap.createscaledbitmap(rotabitmap, 540, 800, true);  

            bitmap rectbitmap = bitmap.createbitmap(sizebitmap, 100, 200, 300, 300);//截取  

            //儲存圖檔到sdcard  

            if(null != rectbitmap)  

            {  

                savejpeg(rectbitmap);  

            //再次進入預覽  

            mycamera.startpreview();  

            ispreview = true;  

        }   

涉及到的其他函數如savejpeg()參見前文:

http://blog.csdn.net/yanzi1225627/article/details/8577756   重複的東西我就不發了。

     效果圖如下所示:

Android攝像頭:隻拍攝SurfaceView預覽界面特定區域内容(矩形框)---完整實作(原理:底層SurfaceView+上層繪制ImageView)

點選拍照,檢視儲存後的圖檔如下:

Android攝像頭:隻拍攝SurfaceView預覽界面特定區域内容(矩形框)---完整實作(原理:底層SurfaceView+上層繪制ImageView)

      反思:

1,surfaceview為啥 無論translucent半透明還是 transparent透明基本沒啥差別?而且surfaceview的setalpha函數不能用。 

2,在這裡surfaceview一定要在底層(預設如此),如果設成頂層會看不到紅色矩形框。可以自己測試下。

3,最糾結的一點,第一副圖檔裡的360掃描二維碼的界面,底層的預覽surfaceview是半透明的,底色是灰色的,隻有中間的掃描矩形框是透明的,亮色。這一塊究竟是怎麼實作的??下午實驗了n種方法愣是無濟于事。我擦。。。如果有高人,希望能不吝指點下。 不過說實話,人家已經設計出來的産品界面看着就是好,不得不服阿。以後要多多模仿鑽研這些成型産品的設計。

源碼下載下傳:http://download.csdn.net/detail/yanzi1225627/5063105     

繼續閱讀