mirror of
https://github.com/zxing/zxing.git
synced 2024-09-20 21:47:32 -07:00
Added some debugging features to the M3 Android client. You can now press 'C' to capture a photo, 'U' to decode only UPC/1D barcodes, and 'Q' to decode only QR Codes.
git-svn-id: https://zxing.googlecode.com/svn/trunk@332 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
4b0927626f
commit
14a200b546
|
@ -61,7 +61,7 @@ public final class BarcodeReaderCaptureActivity extends Activity {
|
|||
cameraManager = new CameraManager(getApplication());
|
||||
surfaceView = new CameraSurfaceView(getApplication(), cameraManager);
|
||||
setContentView(surfaceView);
|
||||
workerThread = new WorkerThread(surfaceView, cameraManager, messageHandler);
|
||||
workerThread = new WorkerThread(this, surfaceView, cameraManager, messageHandler);
|
||||
workerThread.requestPreviewLoop();
|
||||
workerThread.start();
|
||||
|
||||
|
@ -82,7 +82,7 @@ public final class BarcodeReaderCaptureActivity extends Activity {
|
|||
super.onResume();
|
||||
cameraManager.openDriver();
|
||||
if (workerThread == null) {
|
||||
workerThread = new WorkerThread(surfaceView, cameraManager, messageHandler);
|
||||
workerThread = new WorkerThread(this, surfaceView, cameraManager, messageHandler);
|
||||
workerThread.requestPreviewLoop();
|
||||
workerThread.start();
|
||||
}
|
||||
|
@ -102,10 +102,16 @@ public final class BarcodeReaderCaptureActivity extends Activity {
|
|||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
|
||||
workerThread.requestStillAndDecode();
|
||||
return true;
|
||||
} else if (keyCode == KeyEvent.KEYCODE_Q) {
|
||||
workerThread.requestStillAndDecodeQR();
|
||||
} else if (keyCode == KeyEvent.KEYCODE_U) {
|
||||
workerThread.requestStillAndDecode1D();
|
||||
} else if (keyCode == KeyEvent.KEYCODE_C) {
|
||||
workerThread.requestStillAndSave();
|
||||
} else {
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,14 +16,25 @@
|
|||
|
||||
package com.google.zxing.client.android;
|
||||
|
||||
import android.app.Application;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.DecodeHintType;
|
||||
import com.google.zxing.MonochromeBitmapSource;
|
||||
import com.google.zxing.MultiFormatReader;
|
||||
import com.google.zxing.ReaderException;
|
||||
import com.google.zxing.Result;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* This thread does all the heavy lifting, both during preview and for the final capture and
|
||||
* decoding. That leaves the main thread free to handle UI tasks.
|
||||
|
@ -32,6 +43,7 @@ import com.google.zxing.Result;
|
|||
*/
|
||||
final class WorkerThread extends Thread {
|
||||
|
||||
private final BarcodeReaderCaptureActivity activity;
|
||||
private final CameraSurfaceView surfaceView;
|
||||
private final CameraManager cameraManager;
|
||||
private final Handler handler;
|
||||
|
@ -42,10 +54,15 @@ final class WorkerThread extends Thread {
|
|||
IDLE,
|
||||
PREVIEW_LOOP,
|
||||
STILL_AND_DECODE,
|
||||
STILL_AND_DECODE_1D,
|
||||
STILL_AND_DECODE_QR,
|
||||
STILL_AND_SAVE,
|
||||
DONE
|
||||
}
|
||||
|
||||
WorkerThread(CameraSurfaceView surfaceView, CameraManager cameraManager, Handler handler) {
|
||||
WorkerThread(BarcodeReaderCaptureActivity activity, CameraSurfaceView surfaceView,
|
||||
CameraManager cameraManager, Handler handler) {
|
||||
this.activity = activity;
|
||||
this.surfaceView = surfaceView;
|
||||
this.cameraManager = cameraManager;
|
||||
this.handler = handler;
|
||||
|
@ -64,20 +81,33 @@ final class WorkerThread extends Thread {
|
|||
surfaceView.capturePreviewAndDraw();
|
||||
break;
|
||||
case STILL_AND_DECODE:
|
||||
Bitmap bitmap = cameraManager.captureStill();
|
||||
Result rawResult;
|
||||
try {
|
||||
MonochromeBitmapSource source = new RGBMonochromeBitmapSource(bitmap);
|
||||
rawResult = new MultiFormatReader().decode(source);
|
||||
} catch (ReaderException e) {
|
||||
Message message = Message.obtain(handler, R.id.decoding_failed_message);
|
||||
message.sendToTarget();
|
||||
state = State.PREVIEW_LOOP;
|
||||
break;
|
||||
}
|
||||
Message message = Message.obtain(handler, R.id.decoding_succeeded_message, rawResult);
|
||||
message.sendToTarget();
|
||||
state = State.IDLE;
|
||||
takeStillAndDecode(null);
|
||||
break;
|
||||
case STILL_AND_DECODE_1D: {
|
||||
Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(3);
|
||||
// TODO: This is fragile in case we add new formats. It would be better to have a new enum
|
||||
// value which represented all 1D formats.
|
||||
Vector vector = new Vector();
|
||||
vector.addElement(BarcodeFormat.UPC_A);
|
||||
vector.addElement(BarcodeFormat.UPC_E);
|
||||
vector.addElement(BarcodeFormat.EAN_13);
|
||||
vector.addElement(BarcodeFormat.EAN_8);
|
||||
vector.addElement(BarcodeFormat.CODE_39);
|
||||
vector.addElement(BarcodeFormat.CODE_128);
|
||||
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
||||
takeStillAndDecode(hints);
|
||||
break;
|
||||
}
|
||||
case STILL_AND_DECODE_QR: {
|
||||
Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(3);
|
||||
Vector vector = new Vector();
|
||||
vector.addElement(BarcodeFormat.QR_CODE);
|
||||
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
|
||||
takeStillAndDecode(hints);
|
||||
break;
|
||||
}
|
||||
case STILL_AND_SAVE:
|
||||
takeStillAndSave();
|
||||
break;
|
||||
case DONE:
|
||||
return;
|
||||
|
@ -95,6 +125,21 @@ final class WorkerThread extends Thread {
|
|||
wakeFromIdle();
|
||||
}
|
||||
|
||||
public void requestStillAndDecode1D() {
|
||||
state = State.STILL_AND_DECODE_1D;
|
||||
wakeFromIdle();
|
||||
}
|
||||
|
||||
public void requestStillAndDecodeQR() {
|
||||
state = State.STILL_AND_DECODE_QR;
|
||||
wakeFromIdle();
|
||||
}
|
||||
|
||||
public void requestStillAndSave() {
|
||||
state = State.STILL_AND_SAVE;
|
||||
wakeFromIdle();
|
||||
}
|
||||
|
||||
public void requestExitAndWait() {
|
||||
state = State.DONE;
|
||||
wakeFromIdle();
|
||||
|
@ -109,8 +154,8 @@ final class WorkerThread extends Thread {
|
|||
synchronized (idleLock) {
|
||||
idleLock.wait();
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
// continue
|
||||
} catch (InterruptedException e) {
|
||||
// Continue
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,4 +165,74 @@ final class WorkerThread extends Thread {
|
|||
}
|
||||
}
|
||||
|
||||
private void takeStillAndDecode(Hashtable<DecodeHintType, Object> hints) {
|
||||
Bitmap bitmap = cameraManager.captureStill();
|
||||
Result rawResult;
|
||||
try {
|
||||
MonochromeBitmapSource source = new RGBMonochromeBitmapSource(bitmap);
|
||||
rawResult = new MultiFormatReader().decode(source, hints);
|
||||
} catch (ReaderException e) {
|
||||
Message message = Message.obtain(handler, R.id.decoding_failed_message);
|
||||
message.sendToTarget();
|
||||
state = State.PREVIEW_LOOP;
|
||||
return;
|
||||
}
|
||||
Message message = Message.obtain(handler, R.id.decoding_succeeded_message, rawResult);
|
||||
message.sendToTarget();
|
||||
state = State.IDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a debugging feature used to take photos and save them as JPEGs using the exact camera
|
||||
* setup as in normal decoding. This is useful for building up a library of test images.
|
||||
*/
|
||||
private void takeStillAndSave() {
|
||||
Bitmap bitmap = cameraManager.captureStill();
|
||||
OutputStream outStream = getNewPhotoOutputStream();
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, outStream);
|
||||
try {
|
||||
outStream.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
state = State.PREVIEW_LOOP;
|
||||
}
|
||||
|
||||
/**
|
||||
* We prefer to write to the SD Card because it has more space, and is automatically mounted as a
|
||||
* drive over USB. If it's not present, fall back to the package's private file area here:
|
||||
*
|
||||
* /data/data/com.google.zxing.client.android/files
|
||||
*
|
||||
* @return A stream which represents the new file where the photo will be saved.
|
||||
*/
|
||||
private OutputStream getNewPhotoOutputStream() {
|
||||
File sdcard = new File("/sdcard");
|
||||
if (sdcard.exists()) {
|
||||
File barcodes = new File(sdcard, "barcodes");
|
||||
if (!barcodes.exists()) {
|
||||
if (!barcodes.mkdir()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
String fileName = getNewPhotoName(barcodes.list());
|
||||
try {
|
||||
return new FileOutputStream(new File(barcodes, fileName));
|
||||
} catch (FileNotFoundException e) {
|
||||
}
|
||||
} else {
|
||||
Application application = activity.getApplication();
|
||||
String fileName = getNewPhotoName(application.fileList());
|
||||
try {
|
||||
return application.openFileOutput(fileName, 0);
|
||||
} catch (FileNotFoundException e) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getNewPhotoName(String[] listOfFiles) {
|
||||
int existingFileCount = (listOfFiles != null) ? listOfFiles.length : 0;
|
||||
return "capture" + existingFileCount + ".jpg";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue