之前对于Zbar的二位码扫描,到项目上线以后才发现扫描过于灵敏,导致有时候扫描到半截就启动了。
后来翻看ZXING的源码,没有想象的复杂,复杂的地方在于zxing自带的demo项目过于复杂导致初学者对其理解不很明白,修改源码相对麻烦
于是试图简化代码重写了一个demo相对简单。
功能包含
1.扫描区自定义
2.利用线程池并行解析
3.支持横屏/竖屏无缝切换
4.支持条形码,二维码..具体查看zxing库
---文件解释
com.xiaoqiang.zxing.DecodeData.java 自定义解析数据包
com.xiaoqiang.zxing.DecodeRunable.java 解析线程
com.xiaoqiang.zxing.FinderView.java 自定义查找框--支持横屏
com.xiaoqiang.zxing.ZxingTools.java 抽取的zxing工具
com.xiaoqiang.zxing.ZxingBarCodeActivity.java 扫描页面,在SurfaceHolder回调中启动关闭线程池
---主要方法解析
--解析数据包
public class DecodeData {
private byte[] data;
private Size sourceSize;
private Rect preRect;
...get/set
}
--解析线程
public class DecodeRunable implements Runnable {
public static final String TAG = "DecodeRunable";
public SoftReference<WeakHandler<ZxingBarCodeActivity>> handlerReference;
public DecodeData decodeData;
public boolean roate90;
public DecodeRunable(WeakHandler<ZxingBarCodeActivity> handler, DecodeData decodeData, boolean roate90) {
handlerReference = new SoftReference<WeakHandler<ZxingBarCodeActivity>>(handler);
this.decodeData = decodeData;
this.roate90 = roate90;
}
@Override
public void run() {
Result result = ZxingTools.decodeDecodeData(decodeData, roate90);
if (null != result) {
WeakHandler<ZxingBarCodeActivity> weakHandler = handlerReference.get();
if (null != weakHandler) {
ZxingBarCodeActivity qrFinderActivity = weakHandler.activiceReference.get();
if (null == qrFinderActivity || qrFinderActivity.isReciveReuslt()) {
return;
}
//通知扫描页面已经扫描到结果了
qrFinderActivity.setReciveReuslt(true);
Message obtainMessage = weakHandler.obtainMessage(0);
BarcodeFormat barcodeFormat = result.getBarcodeFormat();
String text = result.getText();
Bundle data = new Bundle();
data.putSerializable("BarcodeFormat", barcodeFormat);
data.putString("text", text);
obtainMessage.setData(data);
obtainMessage.sendToTarget();
LogUtils.d(TAG, "BarcodeFormat:" + barcodeFormat.toString() + " 内容:" + text);
}
}
}
}
---自定义查找框--支持横屏---主要方法
/**
* 矫正矩形框
* @param w
* @param h
* @return
*/
public Rect getScanImageRect(Size cameraPreviewSize) {
Rect reusltRect = null;
if (measureedWidth < measureedHeight) {
//图片宽度被拉伸的比例
float temp = (float) cameraPreviewSize.height / (float) measureedWidth;
//图片在高度被拉伸的比例
float tempH = (float) cameraPreviewSize.width / (float) measureedHeight;
reusltRect = new Rect(middleRect.top, middleRect.left, middleRect.bottom, middleRect.right);
reusltRect.left = (int) (reusltRect.left * tempH);
reusltRect.top = (int) (reusltRect.top * temp);
reusltRect.right = (int) (reusltRect.right * tempH);
reusltRect.bottom = (int) (reusltRect.bottom * temp);
} else {
//图片在宽度被拉伸的比例
float tempW = (float) cameraPreviewSize.width / (float) measureedWidth;
//图片高度被拉伸的比例
float tempH = (float) cameraPreviewSize.height / (float) measureedHeight;
reusltRect = new Rect(middleRect);
reusltRect.left = (int) (reusltRect.left * tempW);
reusltRect.top = (int) (reusltRect.top * tempH);
reusltRect.right = (int) (reusltRect.right * tempW);
reusltRect.bottom = (int) (reusltRect.bottom * tempH);
}
return reusltRect;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
measureedWidth = MeasureSpec.getSize(widthMeasureSpec);
measureedHeight = MeasureSpec.getSize(heightMeasureSpec);
//处理横屏
int borderWidth = (measureedWidth < measureedHeight ? measureedWidth : measureedHeight) / 2;
middleRect.set((measureedWidth - borderWidth) / 2, (measureedHeight - borderWidth) / 2, (measureedWidth - borderWidth) / 2 + borderWidth, (measureedHeight - borderWidth) / 2 + borderWidth);
lineRect.set(middleRect);
lineRect.bottom = lineRect.top + lineHeight;
leftRect.set(0, middleRect.top, middleRect.left, middleRect.bottom);
topRect.set(0, 0, measureedWidth, middleRect.top);
rightRect.set(middleRect.right, middleRect.top, measureedWidth, middleRect.bottom);
bottomRect.set(0, middleRect.bottom, measureedWidth, measureedHeight);
}
----抽取的zxing工具
public class ZxingTools {
private static Hashtable<DecodeHintType, Object> decodeConfig = new Hashtable<DecodeHintType, Object>();
static {
List<BarcodeFormat> allFormats = new ArrayList<BarcodeFormat>();
allFormats.add(BarcodeFormat.CODABAR);
allFormats.add(BarcodeFormat.CODE_39);
allFormats.add(BarcodeFormat.CODE_93);
allFormats.add(BarcodeFormat.CODE_128);
allFormats.add(BarcodeFormat.DATA_MATRIX);
allFormats.add(BarcodeFormat.EAN_8);
allFormats.add(BarcodeFormat.EAN_13);
allFormats.add(BarcodeFormat.ITF);
allFormats.add(BarcodeFormat.QR_CODE);
allFormats.add(BarcodeFormat.RSS_14);
allFormats.add(BarcodeFormat.EAN_13);
allFormats.add(BarcodeFormat.RSS_EXPANDED);
allFormats.add(BarcodeFormat.UPC_A);
allFormats.add(BarcodeFormat.UPC_E);
decodeConfig.put(DecodeHintType.POSSIBLE_FORMATS, allFormats);
}
/**
* 解析DecodeData
* @param decodeData
* @param roate90
* @return
*/
public static Result decodeDecodeData(DecodeData decodeData, boolean roate90) {
Bitmap barCodeBitMap = getBarCodeBitMap(decodeData, roate90);
Rect previewRect = new Rect(0, 0, barCodeBitMap.getWidth(), barCodeBitMap.getHeight());
return decodeBitmap(barCodeBitMap, previewRect);
}
/**
* 从PlanarYUVLuminanceSource获取Bitmap
* @param source
* @param roate90
* @return
*/
public static Bitmap getBarCodeBitMap(PlanarYUVLuminanceSource source, boolean roate90) {
int[] pixels = source.renderThumbnail();
int width = source.getThumbnailWidth();
int height = source.getThumbnailHeight();
Bitmap sourceBitmap = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_4444);
if (roate90) {
return roate90Bitmap(sourceBitmap);
} else {
return sourceBitmap;
}
}
/**
* 根据DecodeData获取Bitmap
* @param decodeData
* @param roate90
* @return
*/
public static Bitmap getBarCodeBitMap(DecodeData decodeData, boolean roate90) {
byte[] data = decodeData.getData();
Size size = decodeData.getSourceSize();
Rect preRect = decodeData.getPreRect();
PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data, size.width, size.height, preRect.left, preRect.top, preRect.width(), preRect.height(), false);
return getBarCodeBitMap(source, roate90);
}
/**
* 将Bitmap旋转90
* @param sourceBitmap
* @return
*/
public static Bitmap roate90Bitmap(Bitmap sourceBitmap) {
Matrix matrix = new Matrix();
matrix.reset();
matrix.setRotate(90);
Bitmap resultBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, sourceBitmap.getWidth(), sourceBitmap.getHeight(), matrix, true);
if (!sourceBitmap.isRecycled())
sourceBitmap.recycle();
return resultBitmap;
}
/**
* 解析PlanarYUVData
* @param data
* @param width
* @param height
* @param previewRect
* @param roate90
* @return
*/
public static Result decodePlanarYUVData(byte[] yuvData, Size size, Rect previewRect, boolean roate90) {
if (roate90) {
yuvData = roate90YUVdata(yuvData, size);
}
PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(yuvData, size.width, size.height, previewRect.left, previewRect.top, previewRect.width(), previewRect.height(), false);
BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source));
return decodeBinaryBitmap(binaryBitmap);
}
/**
* 将yuvData旋转90度
* @param yuvData
* @param size
* @return
*/
public static byte[] roate90YUVdata(byte[] yuvData, Size size) {
byte[] rotatedData = new byte[yuvData.length];
for (int y = 0; y < size.height; y++) {
for (int x = 0; x < size.width; x++)
rotatedData[x * size.height + size.height - y - 1] = yuvData[x + y * size.width];
}
int tmp = size.width;
size.width = size.height;
size.height = tmp;
return rotatedData;
}
/**
* 解析Bitmap
* @param bitmap
* @param previewRect
* @param needResultBitmap
* @return
*/
private static Result decodeBitmap(Bitmap bitmap, Rect previewRect) {
int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
bitmap.getPixels(pixels, 0, bitmap.getWidth(), previewRect.left, previewRect.top, previewRect.right, previewRect.bottom);
RGBLuminanceSource source = new RGBLuminanceSource(bitmap.getWidth(), bitmap.getHeight(), pixels);
BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source));
return decodeBinaryBitmap(binaryBitmap);
}
/**
* 解析BinaryBitmap
* @param binaryBitmap
* @return
*/
private static Result decodeBinaryBitmap(BinaryBitmap binaryBitmap) {
MultiFormatReader multiFormatReader = new MultiFormatReader();
multiFormatReader.setHints(decodeConfig);
Result decode = null;
try {
decode = multiFormatReader.decode(binaryBitmap);
} catch (NotFoundException e) {
} finally {
multiFormatReader.reset();
}
return decode;
}
//////////////////////////////////////////////////////
//////////////////// 生成 /////////////////////
//////////////////////////////////////////////////////
/**
* 生成二维码
* @param content
* @param needWidth
* @param needHeight
* @return
* @throws Exception
*/
public static Bitmap encodeQr(String content, int needWidth, int needHeight) throws Exception {
Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
MultiFormatWriter writer = new MultiFormatWriter();
BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, needWidth, needHeight);
return convertBitMatrix2BitMap(bitMatrix);
}
/**
* 生成一维码(128)
* @param content
* @param needWidth
* @param needHeight
* @return
* @throws Exception
*/
public static Bitmap encodeBarcode(String content, int needWidth, int needHeight) throws Exception {
Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
MultiFormatWriter writer = new MultiFormatWriter();
BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.CODE_128, needWidth, needHeight);
return convertBitMatrix2BitMap(bitMatrix);
}
/**
* 将BitMatrix转化为Bitmap
* @param bitMatrix
* @return
*/
private static Bitmap convertBitMatrix2BitMap(BitMatrix bitMatrix) {
int bitmapWidth = bitMatrix.getWidth();
int bitmapHeight = bitMatrix.getHeight();
int[] pixels = new int[bitmapWidth * bitmapHeight];
for (int x = 0; x < bitmapWidth; x++) {
for (int y = 0; y < bitmapHeight; y++) {
if (bitMatrix.get(x, y)) {
pixels[y * bitmapWidth + x] = 0xff000000; // black pixel
} else {
pixels[y * bitmapWidth + x] = 0xffffffff; // white pixel
}
}
}
Bitmap createBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_4444);
createBitmap.setPixels(pixels, 0, bitmapWidth, 0, 0, bitmapWidth, bitmapHeight);
return createBitmap;
}
}
---扫描页面
public class ZxingBarCodeActivity extends Activity implements SurfaceHolder.Callback {
public static final String TAG = "ZbarFinderActivity";
public static final String ResultType = "ResultType";
public static final String ResultContent = "ResultContent";
private Camera mCamera;
private SurfaceHolder mHolder;
protected SurfaceView surface_view;
protected FinderView finder_view;
private ImageView imageView;
private Handler autoFocusHandler;
private ThreadPoolExecutor fixPool;
private LinkedBlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>();
private boolean reciveReuslt = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ac_zbar_finder);
//打开返回
init();
}
@SuppressWarnings("deprecation")
private void init() {
imageView = (ImageView) findViewById(R.id.imageView);
surface_view = (SurfaceView) findViewById(R.id.surface_view);
finder_view = (FinderView) findViewById(R.id.finder_view);
//扫描
mHolder = surface_view.getHolder();
//在2.3的系统中需要
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mHolder.addCallback(this);
autoFocusHandler = new Handler();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
private boolean roate90 = false;
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mHolder.getSurface() == null) {
return;
}
try {
mCamera.stopPreview();
} catch (Exception e) {
}
try {
if (width < height) {
roate90 = true;
mCamera.setDisplayOrientation(90);
} else {
roate90 = false;
mCamera.setDisplayOrientation(0);
}
mCamera.setPreviewDisplay(mHolder);
mCamera.setPreviewCallback(previewCallback);
mCamera.startPreview();
mCamera.autoFocus(autoFocusCallback);
} catch (Exception e) {
}
}
public boolean isReciveReuslt() {
return reciveReuslt;
}
public void setReciveReuslt(boolean reciveReuslt) {
this.reciveReuslt = reciveReuslt;
}
/**
* 结果
*/
private QrActivityHandler handler = new QrActivityHandler(this) {
@Override
public void handleMessage(Message msg) {
if (activiceReference.get() != null) {
if (msg.what == 0) {
if (!fixPool.isShutdown()) {
fixPool.shutdownNow();
}
Intent intent = new Intent(MainActivity.ACTION_SAO_RESULT);
intent.putExtras(msg.getData());
startActivity(intent);
finish();
}
}
}
};
/**
* 预览数据
*/
private PreviewCallback previewCallback = new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
if (!reciveReuslt && !fixPool.isShutdown() && fixPool.getActiveCount() < 5) {
Camera.Parameters parameters = camera.getParameters();
Size size = parameters.getPreviewSize();
//获取预览图的大小
Rect preRect = finder_view.getScanImageRect(size);
DecodeData decodeData = new DecodeData(data, size, preRect);
imageView.setImageBitmap(ZxingTools.getBarCodeBitMap(decodeData, roate90));
Runnable command = new DecodeRunable(handler, decodeData, roate90);
fixPool.execute(command);
}
}
};
private static class QrActivityHandler extends WeakHandler<ZxingBarCodeActivity> {
public QrActivityHandler(ZxingBarCodeActivity qrFinderActivity) {
super(qrFinderActivity);
}
}
/**
* 自动对焦回调
*/
AutoFocusCallback autoFocusCallback = new AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
autoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
//自动对焦
private Runnable doAutoFocus = new Runnable() {
public void run() {
if (null == mCamera || null == autoFocusCallback) {
return;
}
mCamera.autoFocus(autoFocusCallback);
}
};
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera = Camera.open();
fixPool = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, workQueue);
} catch (Exception e) {
mCamera = null;
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
if (null != fixPool && !fixPool.isShutdown()) {
fixPool.shutdownNow();
}
}
}