Android攝像頭:只拍攝SurfaceView預覽介面特定區域內容(矩形框)---完整實現(原理:底層SurfaceView+上層繪製ImageView)
【後注:】下載程式碼的注意,我的手機是4.3寸的屏,華為U9200.如果不能執行的請修改引數。看前文的第四條。Y的,省的說我傳的程式碼不能用
最近一直在審視以前做過的東西,關於android攝像頭預覽,預覽介面上呈現矩形框,在前文(
)----http://blog.csdn.net/yanzi1225627/article/details/7934710已經實現。最近發現上層繪製矩形框,用surfaceview有點大材小用了。SurfaceView繪製動畫更合適,只繪製個矩形框用ImageView足夠了。但有些時候必須要用SurfaceView來實現。比如360手機安全衛士掃描二維碼的實現應該就是通過上下兩層SurfaceView實現的(見下圖)。上層SurfaceView用於顯示那個可以旋轉的掃描示意框,底層SurfaceView預覽攝像頭視訊。
廢話不說了,稍候幾天我會仿照上面360這個掃描二維碼的介面做一個工程(結合PreviewCallback),公開出來。這次先談用底層surfaceView+上層ImageView實現只拍攝矩形框中的影象。新建一個類繼承ImageView,原始碼如下:
[java] view plain copy print?- 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;
- publicclass DrawImageView extends ImageView{
- public DrawImageView(Context context, AttributeSet attrs) {
-
super
- // 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
- protectedvoid 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 plain copy print?
- <LinearLayoutxmlns: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_width="wrap_content"
- 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:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@drawable/photo_img_btn"
- android:layout_gravity="center"/>
- </LinearLayout>
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 plain copy print?- publicvoid 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 重複的東西我就不發了。
效果圖如下所示:
點選拍照,檢視儲存後的圖片如下:
反思:
1,SurfaceView為啥 無論translucent半透明還是 transparent透明基本沒啥區別?而且surfaceview的setAlpha函式不能用。
2,在這裡surfaceview一定要在底層(預設如此),如果設成頂層會看不到紅色矩形框。可以自己測試下。
3,最糾結的一點,第一副圖片裡的360掃描二維碼的介面,底層的預覽surfaceview是半透明的,底色是灰色的,只有中間的掃描矩形框是透明的,亮色。這一塊究竟是怎麼實現的??下午實驗了n種方法愣是無濟於事。我擦。。。如果有高人,希望能不吝指點下。 不過說實話,人家已經設計出來的產品介面看著就是好,不得不服阿。以後要多多模仿鑽研這些成型產品的設計。
歡迎android愛好者加群248217350,備註:yanzi