• Android摄像头:只拍摄SurfaceView预览界面特定区域内容(矩形框)---完整(原理:底层SurfaceView+上层绘制ImageView)


     

    Android摄像头:只拍摄SurfaceView预览界面特定区域内容(矩形框)---完整实现(原理:底层SurfaceView+上层绘制ImageView) 

    分类: Android开发 Android UI
     

    目录(?)[+]

     

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

    最近一直在审视以前做过的东西,关于android摄像头预览,预览界面上呈现矩形框,在前文(

    Android开发 摄像头SurfaceView预览 背景带矩形框 实现(原理:双surfaceview,顶层画矩形框,底层预览视频)

    )----http://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(100, 200, 400, 500), paint);//绘制矩形  
    33.           
    34.     }  
    35.       
    36.       
    37.   
    38.   
    39.       
    40.   
    41. }  

    布局文件里与前文http://blog.csdn.net/yanzi1225627/article/details/8577756这里一样,只是在帧布局里加一个上面自定义的DrawImageView,整个布局文件示下:
    [html] view plaincopy
     
    1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    2.     xmlns:tools="http://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, 0, 0, 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, 540, 800, true);  
    17.             Bitmap rectBitmap = Bitmap.createBitmap(sizeBitmap, 100, 200, 300, 300);//截取  
    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按键效果)------------

    http://blog.csdn.net/yanzi1225627/article/details/8577756   重复的东西我就不发了。

         效果图如下所示:

    点击拍照,查看保存后的图片如下:

          反思:

    1,SurfaceView为啥 无论translucent半透明还是 transparent透明基本没啥区别?而且surfaceview的setAlpha函数不能用。 

    2,在这里surfaceview一定要在底层(默认如此),如果设成顶层会看不到红色矩形框。可以自己测试下。

    3,最纠结的一点,第一副图片里的360扫描二维码的界面,底层的预览surfaceview是半透明的,底色是灰色的,只有中间的扫描矩形框是透明的,亮色。这一块究竟是怎么实现的??下午实验了n种方法愣是无济于事。我擦。。。如果有高人,希望能不吝指点下。 不过说实话,人家已经设计出来的产品界面看着就是好,不得不服阿。以后要多多模仿钻研这些成型产品的设计。

    源码下载:http://download.csdn.net/detail/yanzi1225627/5063105

  • 相关阅读:
    我总结的面试题系列:kafka
    RabbitMQ大厂面试题
    [Algorithm] 并查集
    [LintCode] 编辑距离
    [LeetCode] Length of Longest Fibonacci Subsequence
    [LintCode] 交叉字符串
    [LeetCode] Permutation Sequence
    Permutation Sequence
    [LeetCode] Next Permutation
    [LeetCode] Longest Palindromic Substring
  • 原文地址:https://www.cnblogs.com/qingchen1984/p/4766706.html
Copyright © 2020-2023  润新知