如何画上surfaceview? [英] How to draw on a 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屋!