2013-05-01 64 views
4

我是android开发中的新手。我的应用程序应激活相机扫描QR码并将其解码为字符串。这工作正常,但我有一个更多的要求:在相框中呈现相机视图,并在其中一个角落放置徽标。我没有在zbar sdk中找到合适的API来制作框架并附上徽标。这是我的代码:使用zbar为Android定制摄像头视图

ZBarScannerActivity.java:

package com.myCompany.android; 

import android.app.Activity; 
import android.content.Intent; 
import android.content.pm.PackageManager; 
import android.hardware.Camera; 
import android.media.MediaPlayer; 
import android.media.MediaPlayer.OnCompletionListener; 
import android.os.Bundle; 
import android.os.Handler; 
import android.text.TextUtils; 
import android.util.Log; 
import android.view.Menu; 
import android.view.View; 
import android.view.Window; 
import android.view.WindowManager; 
import android.widget.Toast; 
import net.sourceforge.zbar.Config; 
import net.sourceforge.zbar.Image; 
import net.sourceforge.zbar.ImageScanner; 
import net.sourceforge.zbar.Symbol; 
import net.sourceforge.zbar.SymbolSet; 

public class ZBarScannerActivity extends Activity implements Camera.PreviewCallback, ZBarConstants { 

    private static final String TAG = "ZBarScannerActivity"; 
    private CameraPreview mPreview; 
    private Camera mCamera; 
    private ImageScanner mScanner; 
    private Handler mAutoFocusHandler; 
    private boolean mPreviewing = true; 

    static { 
     System.loadLibrary("iconv"); 
    } 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     // Hide the window title. 
     requestWindowFeature(Window.FEATURE_NO_TITLE); 
     getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 

     mAutoFocusHandler = new Handler(); 

     // Create and configure the ImageScanner; 
     setupScanner(); 

     // Create a RelativeLayout container that will hold a SurfaceView, 
     // and set it as the content of our activity. 
     mPreview = new CameraPreview(this, this, autoFocusCB); 

     setContentView(mPreview); 
    } 

    public void setupScanner() { 
     mScanner = new ImageScanner(); 
     mScanner.setConfig(0, Config.X_DENSITY, 3); 
     mScanner.setConfig(0, Config.Y_DENSITY, 3); 

     int[] symbols = getIntent().getIntArrayExtra(SCAN_MODES); 
     if (symbols != null) { 
      mScanner.setConfig(Symbol.NONE, Config.ENABLE, 0); 
      for (int symbol : symbols) { 
       mScanner.setConfig(symbol, Config.ENABLE, 1); 
      } 
      //test customization 
     } 
    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 

     // Open the default i.e. the first rear facing camera. 
     mCamera = Camera.open(); 
     mPreviewing = true; 
     mPreview.setCamera(mCamera); 
    } 

    @Override 
    protected void onPause() { 
     super.onPause(); 

     // Because the Camera object is a shared resource, it's very 
     // important to release it when the activity is paused. 
     if (mCamera != null) { 
      mPreview.setCamera(null); 
      mCamera.cancelAutoFocus(); 
      mCamera.setPreviewCallback(null); 
      mCamera.stopPreview(); 
      mCamera.release(); 
      mPreviewing = false; 
      mCamera = null; 
     } 
    } 

    public void onPreviewFrame(byte[] data, Camera camera) { 
     Camera.Parameters parameters = camera.getParameters(); 
     Camera.Size size = parameters.getPreviewSize(); 

     Image barcode = new Image(size.width, size.height, "Y800"); 
     barcode.setData(data); 

     int result = mScanner.scanImage(barcode); 

     if (result != 0) { 
      mCamera.cancelAutoFocus(); 
      mCamera.setPreviewCallback(null); 
      mCamera.stopPreview(); 
      mPreviewing = false; 
      SymbolSet syms = mScanner.getResults(); 
      for (Symbol sym : syms) { 
       String symData = sym.getData(); 
       if (!TextUtils.isEmpty(symData)) { 
        Intent dataIntent = new Intent(); 
        dataIntent.putExtra(SCAN_RESULT, symData); 
        dataIntent.putExtra(SCAN_RESULT_TYPE, sym.getType()); 
        setResult(Activity.RESULT_OK, dataIntent); 
        finish(); 
        break; 
       } 
      } 
     } 
    } 
    private Runnable doAutoFocus = new Runnable() { 
     public void run() { 
      if(mCamera != null && mPreviewing) { 
       mCamera.autoFocus(autoFocusCB); 
      } 
     } 
    }; 

    // Mimic continuous auto-focusing 
    Camera.AutoFocusCallback autoFocusCB = new Camera.AutoFocusCallback() { 
     public void onAutoFocus(boolean success, Camera camera) { 
      mAutoFocusHandler.postDelayed(doAutoFocus, 1000); 
     } 
    }; 

    public void launchQRScanner(View v) { 
     if (isCameraAvailable()) { 

      //Toast.makeText(this, "Analyzing Image", Toast.LENGTH_LONG).show(); 

      Intent intent = new Intent(this, ZBarScannerActivity.class); 
      intent.putExtra(ZBarConstants.SCAN_MODES, new int[]{Symbol.QRCODE}); 
      startActivityForResult(intent, ZBAR_QR_SCANNER_REQUEST); 
     } else { 
      Toast.makeText(this, "Camera Unavailable", Toast.LENGTH_SHORT).show(); 
     } 
    } 

    public boolean isCameraAvailable() { 
     PackageManager pm = getPackageManager(); 
     return pm.hasSystemFeature(PackageManager.FEATURE_CAMERA); 
    } 

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

    /* @Override 
    protected void onActivityResult(int requestCode, int resultCode, Intent data) 
    { 
     switch (requestCode) { 
      case ZBAR_SCANNER_REQUEST: 
       Toast.makeText(this, data.getStringExtra(ZBarConstants.SCAN_RESULT), Toast.LENGTH_LONG).show(); 
       break; 
      case ZBAR_QR_SCANNER_REQUEST: 

       playSound(); 

       if (resultCode == RESULT_OK) { 
        Toast.makeText(this, data.getStringExtra(ZBarConstants.SCAN_RESULT), Toast.LENGTH_LONG).show(); 
        Toast.makeText(this, "Scan Result = " + data.getStringExtra(ZBarConstants.SCAN_RESULT), Toast.LENGTH_SHORT).show(); 

        // put whatever you want to do with the code here 
        //TextView tv = new TextView(this); 
        //tv.setText(data.getStringExtra(ZBarConstants.SCAN_RESULT)); 
        Log.d("Data",""+data.getStringExtra(ZBarConstants.SCAN_RESULT)); 
        //setContentView(tv); 
       } 
       break; 
     } 
    }*/ 

    /*private void playSound() 
    { 
     MediaPlayer mp = MediaPlayer.create(getBaseContext(), R.raw.camera_shutter); 
     mp.start();    

     mp.setOnCompletionListener(new OnCompletionListener() 
     {      
      @Override     
      public void onCompletion(MediaPlayer mp) 
      {      
       mp.release();  
      }    
     }); 

    }*/ 
} 

CameraPreview.java:

package com.myCompany.android; 

import android.content.Context; 
import android.hardware.Camera; 
import android.hardware.Camera.AutoFocusCallback; 
import android.hardware.Camera.PreviewCallback; 
import android.hardware.Camera.Size; 
import android.util.Log; 
import android.view.SurfaceHolder; 
import android.view.SurfaceView; 
import android.view.View; 
import android.view.ViewGroup; 
import java.io.IOException; 
import java.util.List; 

class CameraPreview extends ViewGroup implements SurfaceHolder.Callback { 
    private final String TAG = "CameraPreview"; 

    SurfaceView mSurfaceView; 
    SurfaceHolder mHolder; 
    Size mPreviewSize; 
    List<Size> mSupportedPreviewSizes; 
    Camera mCamera; 
    PreviewCallback mPreviewCallback; 
    AutoFocusCallback mAutoFocusCallback; 

    CameraPreview(Context context, PreviewCallback previewCallback, AutoFocusCallback autoFocusCb) { 
     super(context); 

     mPreviewCallback = previewCallback; 
     mAutoFocusCallback = autoFocusCb; 
     mSurfaceView = new SurfaceView(context); 
     addView(mSurfaceView); 

     // Install a SurfaceHolder.Callback so we get notified when the 
     // underlying surface is created and destroyed. 
     mHolder = mSurfaceView.getHolder(); 
     mHolder.addCallback(this); 
     mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
    } 

    public void setCamera(Camera camera) { 
     mCamera = camera; 
     if (mCamera != null) { 
      mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes(); 
      requestLayout(); 
     } 
    } 

    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     // We purposely disregard child measurements because act as a 
     // wrapper to a SurfaceView that centers the camera preview instead 
     // of stretching it. 
     final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec); 
     final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec); 
     setMeasuredDimension(width, height); 

     if (mSupportedPreviewSizes != null) { 
      mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height); 
     } 
    } 

    @Override 
    protected void onLayout(boolean changed, int l, int t, int r, int b) { 
     if (changed && getChildCount() > 0) { 
      final View child = getChildAt(0); 

      final int width = r - l; 
      final int height = b - t; 

      int previewWidth = width; 
      int previewHeight = height; 
      if (mPreviewSize != null) { 
       previewWidth = mPreviewSize.width; 
       previewHeight = mPreviewSize.height; 
      } 

      // Center the child SurfaceView within the parent. 
      if (width * previewHeight > height * previewWidth) { 
       final int scaledChildWidth = previewWidth * height/previewHeight; 
       child.layout((width - scaledChildWidth)/2, 0, 
         (width + scaledChildWidth)/2, height); 
      } else { 
       final int scaledChildHeight = previewHeight * width/previewWidth; 
       child.layout(0, (height - scaledChildHeight)/2, 
         width, (height + scaledChildHeight)/2); 
      } 
     } 
    } 

    public void surfaceCreated(SurfaceHolder holder) { 
     // The Surface has been created, acquire the camera and tell it where 
     // to draw. 
     try { 
      if (mCamera != null) { 
       mCamera.setPreviewDisplay(holder); 
      } 
     } catch (IOException exception) { 
      Log.e(TAG, "IOException caused by setPreviewDisplay()", exception); 
     } 
    } 

    public void surfaceDestroyed(SurfaceHolder holder) { 
     // Surface will be destroyed when we return, so stop the preview. 
     if (mCamera != null) { 
      mCamera.cancelAutoFocus(); 
      mCamera.stopPreview(); 
     } 
    } 


    private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) { 
     final double ASPECT_TOLERANCE = 0.1; 
     double targetRatio = (double) w/h; 
     if (sizes == null) return null; 

     Size optimalSize = null; 
     double minDiff = Double.MAX_VALUE; 

     int targetHeight = h; 

     // Try to find an size match aspect ratio and size 
     for (Size size : sizes) { 
      double ratio = (double) size.width/size.height; 
      if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; 
      if (Math.abs(size.height - targetHeight) < minDiff) { 
       optimalSize = size; 
       minDiff = Math.abs(size.height - targetHeight); 
      } 
     } 

     // Cannot find the one match the aspect ratio, ignore the requirement 
     if (optimalSize == null) { 
      minDiff = Double.MAX_VALUE; 
      for (Size size : sizes) { 
       if (Math.abs(size.height - targetHeight) < minDiff) { 
        optimalSize = size; 
        minDiff = Math.abs(size.height - targetHeight); 
       } 
      } 
     } 
     return optimalSize; 
    } 

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 
     if (holder.getSurface() == null){ 
      // preview surface does not exist 
      return; 
     } 

     // Now that the size is known, set up the camera parameters and begin 
     // the preview. 
     Camera.Parameters parameters = mCamera.getParameters(); 
     parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); 
     requestLayout(); 

     mCamera.setParameters(parameters); 
     mCamera.setPreviewCallback(mPreviewCallback); 
     mCamera.startPreview(); 
     mCamera.autoFocus(mAutoFocusCallback); 
    } 

} 

如何自定义的Android相机的看法?我看到了一些针对iPhone的建议解决方案,但适用于Android的zbar API完全不同且体积更小。我将不胜感激得到任何想法/提示...

回答

2

我觉得它更容易然后你想:

在由zbar和人提供的示例代码中有这两条线在onCreate()方法:

FrameLayout preview = (FrameLayout) findViewById(R.id.cameraPreview); 
preview.addView(mPreview); 

其负责添加“预览视图”到camerPreview布局。

查找在代码中提到的线条,创建一个新的ImageView,也把它添加到预览 -layout这样的:

ImageView v = new ImageView(this); 
v.setImageResource(R.drawable.icon); 
preview.addView(v); 

调整大小和你的看法V的位置和你完成了!

+2

不幸的是,它不起作用。相机抓住整个屏幕,并且我的图像不出现在屏幕上。 – user2336535 2013-05-02 19:41:47

+0

你可以发布你的活动吗? – Elias 2013-05-04 16:21:47

0

我面临同样的问题。解决的办法是简单地在您的xml中将CameraPrevie添加到frameLayout中,然后在其后面放置图像。

例如:

<FrameLayout 
    android:id="@+id/captionFrame" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_gravity="center" 
    android:layout_marginBottom="20dp" 
    android:layout_marginTop="50dp" > 

    <FrameLayout 
     android:id="@+id/cameraPreview" 
     android:layout_width="300dp" 
     android:layout_height="200dp" 
     android:layout_gravity="center" 
     android:paddingLeft="-5dp" > 

    </FrameLayout> 

    <ImageView 
     android:id="@+id/watermark" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="right|bottom" 
     android:src="@drawable/watermark" /> 

</FrameLayout> 

,并从你的活动来填充它:

Camera mCamera = getCameraInstance(); 

ImageScanner scanner = new ImageScanner(); 
scanner.setConfig(0, Config.X_DENSITY, 3); 
scanner.setConfig(0, Config.Y_DENSITY, 3); 

CameraPreview mPreview = new CameraPreview(this, mCamera, null, autoFocusCallB); 
FrameLayout preview = (FrameLayout)findViewById(R.id.cameraPreview); 
preview.addView(mPreview); 
4

要cameraview呈现帧,在main.xml中的FrameLayout里(camerapreview)添加ImageView的。

<FrameLayout 
    android:id="@+id/cameraPreview" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:layout_weight="1" > 
    <ImageView 
     android:id="@+id/imageView1" 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" 
     android:alpha="0.6" 
     android:src="@drawable/overlay" /> 
    </FrameLayout> 

使用此代码可以使框架(imageview)可见。由于frame(imageview)已经存在于main.xml中的framelayout中,因此我们需要先删除它。

FrameLayout preview = (FrameLayout)findViewById(R.id.cameraPreview); 
    ImageView iv=(ImageView) findViewById(R.id.imageView1); 
    preview.addView(mPreview); 
    preview.removeView(iv); 
    preview.addView(iv); 

如果只从你的框架,您需要使用setCrop()。根据框架调整camerapreview的尺寸扫描camerapreview。

barcode.setData(data); 
    //this is in portrait mode 
    //barcode.setCrop(left,top,width,height). 
    barcode.setCrop(100,230,600,10); 

这对我有用,并希望它也能解决您的问题。请原谅我的语法错误。谢谢。

+0

你的'ImageView',bro的src'如何? 'android:src =“@ drawable/overlay”' – 2015-08-14 08:25:45

+0

@MrNeo我用photoshop制作了它。一个简单的png,其中一个小透明盒子被切割成不透明的中心线。这与我们在预制条码扫描仪中看到的类似。 – Victor 2015-08-14 17:27:26

+0

但是屏幕分辨率不同,它可以填满所有屏幕还是左右两侧有空间 – 2015-08-15 01:10:44

相关问题