如何画上surfaceview? [英] How to draw on a surfaceview?

查看:216
本文介绍了如何画上surfaceview?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,我试图做一个QR code读者,所以我使用dlzaaro66它提供了方便的实现Zxing库所提供的使用QR codeReaderView库。在code为扫描QR code,但我想让排序的参考框,从而以指示code正在从相机表面观扫描下落我试图用正常平局技术。它不给任何错误,但它不是画要么你能不能帮我哪里有问题可能会发生。

这我的活动课。

 进口android.app.Activity;
进口android.content.Intent;
进口android.graphics.Canvas;
进口android.graphics.Color;
进口android.graphics.Paint;
进口android.graphics.PointF;
进口android.net.Uri;
进口android.os.Bundle;
进口android.view.Menu;
进口android.view.MenuItem;
进口android.widget.CompoundButton;
进口android.widget.Switch;
进口android.widget.Toast;进口com.dlazaro66.qr codereaderview.QR codeReaderView;
进口com.dlazaro66.qr codereaderview.QR codeReaderView.OnQR codeReadListener;
公共类MyActivity扩展活动实现OnQR $ C $ {cReadListener    QR codeReaderView德codeR;
    开关START_STOP;
    涂料粉刷;    @覆盖
    保护无效的onCreate(捆绑savedInstanceState){
        super.onCreate(savedInstanceState);
        的setContentView(R.layout.activity_my);
        德codeR =(QR codeReaderView)findViewById(R.id.view2);
        德coder.setOnQR codeReadListener(本);
        START_STOP =(开关)findViewById(R.id.switch1);
        start_stop.setChecked(真);        start_stop.setOnCheckedChangeListener(新CompoundButton.OnCheckedChangeListener(){
            @覆盖
            公共无效onCheckedChanged(CompoundButton compoundButton,布尔B){
                如果(B)的{
                    。德coder.getCameraManager()启动preVIEW();
                }
                其他{
                    。德coder.getCameraManager()停止preVIEW();
                }
            }
        });
        油漆=新的油漆();
        paint.setColor(Color.RED);
        paint.setStrokeWidth(100);
        paint.setAntiAlias​​(真);
        paint.setStyle(Paint.Style.STROKE);    }
    @覆盖
    公共布尔onCreateOptionsMenu(菜单菜单){
        //充气菜单;如果是present这增加了项目操作栏。
        。getMenuInflater()膨胀(R.menu.my,菜单);
        返回true;
    }    @覆盖
    公共布尔onOptionsItemSelected(菜单项项){
        //处理动作栏项目点击这里。操作栏会
        //自动处理上点击主页/向上按钮,只要
        //你在AndroidManifest.xml中指定一个父活动。
        INT ID = item.getItemId();
        如果(ID == R.id.action_settings){
            返回true;
        }
        返回super.onOptionsItemSelected(项目);
    }    @覆盖
    公共无效onQR codeREAD(字符串文本的PointF []点){
        start_stop.setChecked(假);
        如果(text.startsWith(HTTP)){
            Toast.makeText(getApplicationContext(),文本,Toast.LENGTH_SHORT).show();
            最终意向意图=新意图(Intent.ACTION_VIEW).setData(Uri.parse(文本));
            startActivity(意向);
        }
        其他{
            Toast.makeText(getApplicationContext(),文本,Toast.LENGTH_SHORT).show();
        }
        帆布帆布=新的Canvas();
        的for(int i = 0; I< points.length-1;我++){
            canvas.drawLine(分[I] .X,点[I] .Y,点[I + 1] .X,点[I + 1] .Y,油漆);
        }    }    @覆盖
    公共无效cameraNotFound(){    }    @覆盖
    公共无效QR codeNotFoundOnCamImage(){    }}

这是从那里我得到的方法和自定义surfaceview库项目类

 公共类QR codeReaderView延伸SurfaceView实现SurfaceHolder.Callback,摄像头。$ P $ {pviewCallback    公共接口OnQR $ C $ {cReadListener        公共无效onQR codeREAD(字符串文本的PointF []点);
        公共无效cameraNotFound();
        公共无效QR codeNotFoundOnCamImage();
    }    私人OnQR codeReadListener mOnQR codeReadListener;    私有静态最后弦乐TAG = QR codeReaderView.class.getName();    私人QR codeReader MQR codeReader;
    私人诠释米previewWidth;
    私人诠释米previewHeight;
    私人SurfaceHolder mHolder;
    私人CameraManager mCameraManager;    公共QR codeReaderView(上下文的背景下){
        超级(上下文);
        在里面();
    }    公共QR codeReaderView(上下文的背景下,ATTRS的AttributeSet){
        超(背景下,ATTRS);
        在里面();
    }    公共无效setOnQR codeReadListener(OnQR codeReadListener onQR codeReadListener){
        mOnQR codeReadListener = onQR codeReadListener;
    }    公共CameraManager getCameraManager(){
        返回mCameraManager;
    }    @燮pressWarnings(德precation)
    私人无效的init(){
        如果(checkCameraHardware(的getContext())){
            mCameraManager =新CameraManager(的getContext());            mHolder = this.getHolder();
            mHolder.addCallback(本);
            mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); //需要设置该标志,尽管这是德precated
        }其他{
            Log.e(TAG,错误:未找到摄像头);
            mOnQR codeReadListener.cameraNotFound();
        }
    }    / ******************* ***
     * SurfaceHolder.Callback,摄像头。previewCallback
     ************************************************** ** /    @覆盖
    公共无效surfaceCreated(SurfaceHolder持有人){
        尝试{
            //指示摄像头,我们认为维
            mCameraManager.openDriver(保持,this.getWidth(),this.getHeight());
        }赶上(IOException异常五){
            Log.w(TAG,不能openDriver:+ e.getMessage());
            mCameraManager.closeDriver();
        }        尝试{
            MQR codeReader =新的QR codeReader();
            mCameraManager.start preVIEW();
        }赶上(例外五){
            Log.e(TAG,异常:+ e.getMessage());
            mCameraManager.closeDriver();
        }
    }    @覆盖
    公共无效surfaceDestroyed(SurfaceHolder持有人){
        Log.d(TAGsurfaceDestroyed);
        mCameraManager.getCamera()设定previewCallback(空)。
        。mCameraManager.getCamera()停止preVIEW();
        mCameraManager.getCamera()版本()。
        mCameraManager.closeDriver();
    }    //当相机拍摄一帧调用
    @覆盖
    在previewFrame(字节[]数据,相机摄像头){公共无效        PlanarYUVLuminanceSource源= mCameraManager.buildLuminanceSource(数据中,M previewWidth,男previewHeight);        HybridBinarizer hybBin =新HybridBinarizer(源);
        BinaryBitmap位=新BinaryBitmap(hybBin);        尝试{
            结果结果= MQR codeReader.de code(位图);            //通知我们发现了一个QR code
            如果(mOnQR codeReadListener!= NULL){
                    //变换resultPoints查看坐标
                    的PointF [] transformedPoints = transformToViewCoordinates(result.getResultPoints());
                    mOnQR codeReadListener.onQR codeREAD(result.getText(),transformedPoints);
            }        }赶上(ChecksumException E){
            Log.d(TAGChecksumException);
            e.printStackTrace();
        }赶上(NotFoundException E){
            //通知QR未找到
            如果(mOnQR codeReadListener!= NULL){
                mOnQR codeReadListener.QR(codeNotFoundOnCamImage);
            }
        }赶上(FormatException E){
            Log.d(TAGFormatException);
            e.printStackTrace();
        } {最后
            MQR codeReader.reset();
        }
    }    @覆盖
    公共无效surfaceChanged(SurfaceHolder架,INT格式,诠释的宽度,高度INT){
        Log.d(TAGsurfaceChanged);        如果(mHolder.getSurface()== NULL){
            Log.e(TAG,错误:preVIEW表面不存在);
            返回;
        }        // preview_width =宽度;
        // preview_height =高度;        米previewWidth = mCameraManager.get previewSize()×。
        米previewHeight = mCameraManager.get previewSize()Y。
        mCameraManager.stop preVIEW();
        mCameraManager.getCamera()设定previewCallback(本)。
        。mCameraManager.getCamera()setDisplayOrientation(90); //人像模式        mCameraManager.start preVIEW();
    }    / **
     *将结果surfaceView坐标
     *
     *需要使用此方法,因为坐标在景观摄像机坐标给出。
     *现在是工作,但变换操作都不是很说明
     *
     * TODO重新写这个方法解释每个单独的值
     *
     返回:与转化点新的PointF数组
     * /
    私人的PointF [] transformToViewCoordinates(ResultPoint [] resultPoints){        的PointF [] = transformedPoints新的PointF [resultPoints.length]
        INT索引= 0;
        如果(resultPoints!= NULL){
            浮previewX = mCameraManager.get previewSize()×。
            浮previewY = mCameraManager.get previewSize()Y。
            漂浮的scaleX = this.getWidth()/ previewY;
            漂浮的scaleY = this.getHeight()/ previewX;            对于(ResultPoint点:resultPoints){
                的PointF tmppoint =新的PointF((previewY- point.getY())*的scaleX,point.getX()*的scaleY);
                transformedPoints [指数] = tmppoint;
                指数++;
            }
        }
        返回transformedPoints;    }
    / **检查该设备有一个摄像头* /
    私人布尔checkCameraHardware(上下文的背景下){
        如果(context.getPackageManager()。hasSystemFeature(PackageManager.FEATURE_CAMERA)){
            //这个设备有一个摄像头
            返回true;
        }
        否则如果(context.getPackageManager()。hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)){
            //这个设备有一个前置摄像头
            返回true;
        }
        否则如果(context.getPackageManager()。hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)){
            //这个设备有任何相机
            返回true;
        }
        其他{
            //此设备上没有摄像头
            返回false;
        }
    }}


解决方案

A 表面是一个生产者 - 消费者缓冲队列安排的一部分。您的应用程序是在生产者结束,并为 SurfaceView 系统合成器(SurfaceFlinger的)是在消费终端。

A面可以在同一时间只有一个生产者。你已经建立了相机preVIEW作为制片人,所以它不可能也连接画布进行绘图。它不是 - 因为你使用新的Canvas 来创建一个画布在真空中,你看不到失败连接到任何东西。 (正常情况下你会使用表面#lockCanvas()来获得画布与地面联系。)

表面是一个完全独立的层,复合一切默认的背后,这意味着你可以与自定义视图它上面绘制。我不认为你需要一个额外的视图对象虽然 - 我相信你可以的视图部分做了 SurfaceView 本身,它应该有一个透明背景。请参阅自定义绘制文档。

如果你想获得看上你可以喂相机preVIEW到OpenGL ES的,但是这可能是你所需要的过度。 (一些例子这里。)另外,如果您想了解更多关于Android的图形架构,请参阅这个文件

Hi guys I was trying to make a QRCode reader so I used the used the QRCodeReaderView library provided by dlzaaro66 which provides easy implementation of Zxing library. The code is scanning the qrcode but i wanted to make sort of a reference box so as to indicate the whereabouts of where the code is being scanned from on the camera surface view I tried to use the normal draw technique. Its not giving any error but its not drawing either could you help me with where the problem might be occurring.

This my activity class.

import android.app.Activity;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.CompoundButton;
import android.widget.Switch;
import android.widget.Toast;

import com.dlazaro66.qrcodereaderview.QRCodeReaderView;
import com.dlazaro66.qrcodereaderview.QRCodeReaderView.OnQRCodeReadListener;


public class MyActivity extends Activity implements OnQRCodeReadListener{

    QRCodeReaderView decoder;
    Switch start_stop;
    Paint paint;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        decoder = (QRCodeReaderView) findViewById(R.id.view2);
        decoder.setOnQRCodeReadListener(this);
        start_stop=(Switch) findViewById(R.id.switch1);
        start_stop.setChecked(true);

        start_stop.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                if(b){
                    decoder.getCameraManager().startPreview();
                }
                else{
                    decoder.getCameraManager().stopPreview();
                }
            }
        });
        paint= new Paint();
        paint.setColor(Color.RED);
        paint.setStrokeWidth(100);
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.STROKE);

    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.my, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onQRCodeRead(String text, PointF[] points) {
        start_stop.setChecked(false);
        if(text.startsWith("http")){
            Toast.makeText(getApplicationContext(),text,Toast.LENGTH_SHORT).show();
            final Intent intent = new Intent(Intent.ACTION_VIEW).setData(Uri.parse(text));
            startActivity(intent);
        }
        else{
            Toast.makeText(getApplicationContext(),text,Toast.LENGTH_SHORT).show();
        }
        Canvas canvas=new Canvas();
        for(int i=0;i<points.length-1;i++){
            canvas.drawLine(points[i].x,points[i].y,points[i+1].x,points[i+1].y,paint);
        }

    }

    @Override
    public void cameraNotFound() {

    }

    @Override
    public void QRCodeNotFoundOnCamImage() {

    }

}

This is the library project class from where I am getting the methods and the custom surfaceview

public class QRCodeReaderView extends SurfaceView implements SurfaceHolder.Callback,Camera.PreviewCallback {

    public interface OnQRCodeReadListener {

        public void onQRCodeRead(String text, PointF[] points);
        public void cameraNotFound();
        public void QRCodeNotFoundOnCamImage();
    }

    private OnQRCodeReadListener mOnQRCodeReadListener;

    private static final String TAG = QRCodeReaderView.class.getName();

    private QRCodeReader mQRCodeReader;
    private int mPreviewWidth; 
    private int mPreviewHeight; 
    private SurfaceHolder mHolder;
    private CameraManager mCameraManager;

    public QRCodeReaderView(Context context) {
        super(context);
        init();
    }

    public QRCodeReaderView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public void setOnQRCodeReadListener(OnQRCodeReadListener onQRCodeReadListener) {
        mOnQRCodeReadListener = onQRCodeReadListener;
    }

    public CameraManager getCameraManager() {
        return mCameraManager;
    }

    @SuppressWarnings("deprecation")
    private void init() {
        if (checkCameraHardware(getContext())){
            mCameraManager = new CameraManager(getContext());

            mHolder = this.getHolder();
            mHolder.addCallback(this);
            mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  // Need to set this flag despite it's deprecated
        } else {
            Log.e(TAG, "Error: Camera not found");
            mOnQRCodeReadListener.cameraNotFound();
        }
    }



    /****************************************************
     * SurfaceHolder.Callback,Camera.PreviewCallback
     ****************************************************/

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            // Indicate camera, our View dimensions
            mCameraManager.openDriver(holder,this.getWidth(),this.getHeight());
        } catch (IOException e) {
            Log.w(TAG, "Can not openDriver: "+e.getMessage());
            mCameraManager.closeDriver();
        }

        try {
            mQRCodeReader = new QRCodeReader();
            mCameraManager.startPreview();
        } catch (Exception e) {
            Log.e(TAG, "Exception: " + e.getMessage());
            mCameraManager.closeDriver();
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        Log.d(TAG, "surfaceDestroyed");
        mCameraManager.getCamera().setPreviewCallback(null);
        mCameraManager.getCamera().stopPreview();
        mCameraManager.getCamera().release();
        mCameraManager.closeDriver();
    }

    // Called when camera take a frame 
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {

        PlanarYUVLuminanceSource source = mCameraManager.buildLuminanceSource(data, mPreviewWidth, mPreviewHeight);

        HybridBinarizer hybBin = new HybridBinarizer(source);
        BinaryBitmap bitmap = new BinaryBitmap(hybBin);

        try {
            Result result = mQRCodeReader.decode(bitmap);  

            // Notify We're found a QRCode
            if (mOnQRCodeReadListener != null) {
                    // Transform resultPoints to View coordinates
                    PointF[] transformedPoints = transformToViewCoordinates(result.getResultPoints());
                    mOnQRCodeReadListener.onQRCodeRead(result.getText(), transformedPoints);
            }

        } catch (ChecksumException e) {
            Log.d(TAG, "ChecksumException");
            e.printStackTrace();
        } catch (NotFoundException e) {
            // Notify QR not found
            if (mOnQRCodeReadListener != null) {
                mOnQRCodeReadListener.QRCodeNotFoundOnCamImage();
            }
        } catch (FormatException e) {
            Log.d(TAG, "FormatException");
            e.printStackTrace();
        } finally {
            mQRCodeReader.reset();
        }
    }



    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        Log.d(TAG, "surfaceChanged");

        if (mHolder.getSurface() == null){
            Log.e(TAG, "Error: preview surface does not exist");
            return;
        }

        //preview_width = width;
        //preview_height = height;

        mPreviewWidth = mCameraManager.getPreviewSize().x;
        mPreviewHeight = mCameraManager.getPreviewSize().y;


        mCameraManager.stopPreview();
        mCameraManager.getCamera().setPreviewCallback(this);
        mCameraManager.getCamera().setDisplayOrientation(90); // Portrait mode

        mCameraManager.startPreview();
    }

    /**
     * Transform result to surfaceView coordinates
     * 
     * This method is needed because coordinates are given in landscape camera coordinates.
     * Now is working but transform operations aren't very explained
     * 
     * TODO re-write this method explaining each single value    
     * 
     * @return a new PointF array with transformed points
     */
    private PointF[] transformToViewCoordinates(ResultPoint[] resultPoints) {

        PointF[] transformedPoints = new PointF[resultPoints.length];
        int index = 0;
        if (resultPoints != null){
            float previewX = mCameraManager.getPreviewSize().x;
            float previewY = mCameraManager.getPreviewSize().y;
            float scaleX = this.getWidth()/previewY;
            float scaleY = this.getHeight()/previewX;

            for (ResultPoint point :resultPoints){
                PointF tmppoint = new PointF((previewY- point.getY())*scaleX, point.getX()*scaleY);
                transformedPoints[index] = tmppoint;
                index++;
            }
        }
        return transformedPoints;

    }


    /** Check if this device has a camera */
    private boolean checkCameraHardware(Context context) {
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
            // this device has a camera
            return true;
        } 
        else if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)){
            // this device has a front camera
            return true;
        }
        else if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)){
            // this device has any camera
            return true;
        }
        else {
            // no camera on this device
            return false;
        }
    }

}

解决方案

A Surface is part of a producer-consumer buffer queue arrangement. Your application is on the producer end, and for a SurfaceView the system compositor (SurfaceFlinger) is on the consumer end.

A surface can have only one producer at a time. You've established the camera preview as the producer, so it's not possible to also connect a Canvas to perform drawing. You're not seeing failures because you're using new Canvas to create a Canvas in a vacuum -- it's not connected to anything. (Normally you'd use Surface#lockCanvas() to get the Canvas associated with the Surface.)

The surface is a completely separate layer, composited behind everything else by default, which means you can draw on top of it with a custom View. I don't think you need an additional view object though -- I believe you can do it with the 'view' part of the SurfaceView itself, which should have a transparent background. See the "custom drawing" documentation.

If you want to get fancy you can feed the camera preview to OpenGL ES, but that's probably excessive for what you need. (Some examples here.) Also, if you want to learn more about the Android graphics architecture, see this document.

这篇关于如何画上surfaceview?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆