閱讀335 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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

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

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

Android開發 攝像頭SurfaceView預覽 背景帶矩形框 實現(原理:雙surfaceview,頂層畫矩形框,底層預覽視頻)

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


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

[java] view plaincopy
  1. package yan.guoqi.rectphoto;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Canvas;  
  5. import android.graphics.Color;  
  6. import android.graphics.Paint;  
  7. import android.graphics.Paint.Style;  
  8. import android.graphics.Rect;  
  9. import android.util.AttributeSet;  
  10. import android.widget.ImageView;  
  11.   
  12. public class DrawImageView extends ImageView{  
  13.   
  14.     public DrawImageView(Context context, AttributeSet attrs) {  
  15.         super(context, attrs);  
  16.         // TODO Auto-generated constructor stub  
  17.     }  
  18.       
  19.     Paint paint = new Paint();  
  20.     {  
  21.         paint.setAntiAlias(true);  
  22.         paint.setColor(Color.RED);  
  23.         paint.setStyle(Style.STROKE);  
  24.         paint.setStrokeWidth(2.5f);//設置線寬  
  25.         paint.setAlpha(100);  
  26.     };  
  27.       
  28.     @Override  
  29.     protected void onDraw(Canvas canvas) {  
  30.         // TODO Auto-generated method stub  
  31.         super.onDraw(canvas);  
  32.         canvas.drawRect(new Rect(100200400500), paint);//繪製矩形  
  33.           
  34.     }  
  35.       
  36.       
  37.   
  38.   
  39.       
  40.   
  41. }  

布局文件裏與前文https://blog.csdn.net/yanzi1225627/article/details/8577756這裏一樣,隻是在幀布局裏加一個上麵自定義的DrawImageView,整個布局文件示下:

[html] view plaincopy
  1. <LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="https://schemas.android.com/tools"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:orientation="vertical" >  
  6.   
  7.     <TextView  
  8.         android:layout_width="wrap_content"  
  9.         android:layout_height="wrap_content"  
  10.         android:text="@string/BestWish"  
  11.         tools:context=".RectPhoto" />  
  12.   
  13.     <FrameLayout  
  14.         android:layout_width="wrap_content"  
  15.         android:layout_height="wrap_content" >  
  16.   
  17.         <SurfaceView  
  18.             android:id="@+id/previewSV"  
  19.             android:layout_width="fill_parent"  
  20.             android:layout_height="800px" />  
  21.           
  22.         <yan.guoqi.rectphoto.DrawImageView  
  23.              android:id="@+id/drawIV"  
  24.              android:layout_width="fill_parent"  
  25.              android:layout_height="800px"  
  26.             />  
  27.     </FrameLayout>  
  28.   
  29.     <ImageButton  
  30.         android:id="@+id/photoImgBtn"  
  31.         android:layout_width="wrap_content"  
  32.         android:layout_height="wrap_content"  
  33.         android:background="@drawable/photo_img_btn"  
  34.         android:layout_gravity="center" />  
  35.   
  36. </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()函數的源碼如下:

[java] view plaincopy
  1. public void onPictureTaken(byte[] data, Camera camera) {  
  2.             // TODO Auto-generated method stub  
  3.             Log.i(tag, "myJpegCallback:onPictureTaken...");  
  4.             if(null != data){  
  5.                 mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);//data是字節數據,將其解析成位圖  
  6.                 myCamera.stopPreview();  
  7.                 isPreview = false;  
  8.             }  
  9.             //設置FOCUS_MODE_CONTINUOUS_VIDEO)之後,myParam.set("rotation", 90)失效。圖片竟然不能旋轉了,故這裏要旋轉下  
  10.             Matrix matrix = new Matrix();  
  11.             matrix.postRotate((float)90.0);  
  12.             Bitmap rotaBitmap = Bitmap.createBitmap(mBitmap, 00, mBitmap.getWidth(), mBitmap.getHeight(), matrix, false);  
  13.               
  14.             //旋轉後rotaBitmap是960×1280.預覽surfaview的大小是540×800  
  15.             //將960×1280縮放到540×800  
  16.             Bitmap sizeBitmap = Bitmap.createScaledBitmap(rotaBitmap, 540800true);  
  17.             Bitmap rectBitmap = Bitmap.createBitmap(sizeBitmap, 100200300300);//截取  
  18.               
  19.               
  20.             //保存圖片到sdcard  
  21.             if(null != rectBitmap)  
  22.             {  
  23.                 saveJpeg(rectBitmap);  
  24.             }  
  25.   
  26.             //再次進入預覽  
  27.             myCamera.startPreview();  
  28.             isPreview = true;  
  29.         }   


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

2013新春奉送:Android攝像頭開發完美demo---(循環聚焦,縮放大小,旋轉picture,查詢支持的picturesize, ImageButton按鍵效果)------------

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

     效果圖如下所示:



點擊拍照,查看保存後的圖片如下:


      反思:

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

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

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

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


最後更新:2017-04-03 18:52:01

  上一篇:go Chrome 是通向新應用經濟的後門
  下一篇:go Google+兩次改版設計風格探析