package jjil.android;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.os.Handler;
import android.util.Log;
import android.widget.CheckBox;
import android.widget.TextView;
public class ReadBarcode implements android.hardware.Camera.PreviewCallback,
android.hardware.Camera.AutoFocusCallback {
private static final String TAG = "ReadBarcode";
private Handler handler = new Handler();
public ReadBarcode(double dPerpPos, TextView tv, CheckBox ck, CrosshairOverlay co) {
me13b = new Ean13Barcode1D();
mdBarcodePerpPos = dPerpPos;
mTextViewResult = tv;
mCheckBoxResult = ck;
mCrosshairOverlay = co;
}
@Override
public void onAutoFocus(boolean success, Camera camera) {
Log.d(TAG, "on auto focus " + success);
if (!success) {
// try again
//code in the book was:
// camera.autoFocus(this);
autoFocusLater(camera);
} else {
Log.d(TAG, "reset mnFocus");
mnFocused = 15;
}
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
Parameters cameraParameters = camera.getParameters();
String focusMode = camera.getParameters().getFocusMode();
boolean bUseAutoFocus = focusMode.equals(Camera.Parameters.FOCUS_MODE_AUTO) ||
focusMode.equals(Camera.Parameters.FOCUS_MODE_MACRO);
if (bUseAutoFocus && (mnFocused == 0 || mbFoundBarcode)) {
Log.d(TAG, "exit, mnFocused is 0 or mbFoundBarcode is "
+ mbFoundBarcode + " use auto " + bUseAutoFocus);
return;
}
try {
int imageFormat = cameraParameters.getPreviewFormat();
// we only know how to process NV21 format (the default format)
if (imageFormat == ImageFormat.NV21) {
/**
* NV21 consists of an 8-bit Y (intensity) plane followed by an
* interleaved subsampled U/V (hue) plane. We don't care about
* color in this app so we just read the intensity plane
*/
Size size = camera.getParameters().getPreviewSize();
/**
* for debugging purposes, allow the current image to be saved
* and reused
*/
boolean bWrite = false, bRead = false;
Integer width = size.width, height = size.height;
if (bWrite) {
DebugImage.writeGrayImage(data, width, height,
"barcode.png");
}
if (bRead) {
DebugImage.Nv21Image nv21Image = DebugImage.readGrayImage("barcode.png");
data = nv21Image.getData();
width = nv21Image.getWidth();
height = nv21Image.getHeight();
}
int[] nValues;
int nRow, nCol;
// First search for the barcode columnwise
nRow = (int) (mdBarcodePerpPos * height);
int nStartCol = 0;
int nEndCol = width;
nValues = new int[nEndCol - nStartCol];
int nRowOffset = width * nRow;
/**
* Byte values run from -128 (0x80) to + 127 (0x7f) but image
* values run from 0x00 to 0xff. It will be easier to do the
* math if we convert to integer. We also compute the max and
* min value to use in thresholding
*/
int i = 0;
for (nCol = nStartCol; nCol < nEndCol; nCol++) {
int nValue = 0xff & (int) data[nRowOffset + nCol];
nValues[i++] = nValue;
}
String szBarcode = me13b.searchForBarcode(nValues, mCrosshairOverlay, true);
// show the barcode and exit
if (szBarcode != null && mTextViewResult != null) {
mTextViewResult.setText(szBarcode);
mbFoundBarcode = Ean13Barcode1D.verifyCheckDigit(szBarcode);
mCheckBoxResult.setChecked(mbFoundBarcode);
return;
}
// now search rowwsize
nCol = (int) (mdBarcodePerpPos * width);
int nStartRow = 0;
int nEndRow = height;
nValues = new int[nEndRow - nStartRow];
int nColOffset = nCol;
/**
* Byte values run from -128 (0x80) to + 127 (0x7f) but image
* values run from 0x00 to 0xff. It will be easier to do the
* math if we convert to integer. We also compute the max and
* min value to use in thresholding
*/
i = 0;
for (nRow = nStartRow; nRow < nEndRow; nRow++) {
int nValue = 0xff & (int) data[nColOffset + nRow
* width];
nValues[i++] = nValue;
}
szBarcode = me13b.searchForBarcode(nValues, mCrosshairOverlay, false);
if (mTextViewResult != null && szBarcode != null) {
mTextViewResult.setText(szBarcode);
mbFoundBarcode = Ean13Barcode1D.verifyCheckDigit(szBarcode);
mCheckBoxResult.setChecked(mbFoundBarcode);
Log.d(TAG, "bar code");
return;
}
else
{
Log.d(TAG, "no bar code");
}
}
} finally {
if (bUseAutoFocus && (--mnFocused == 0 && !mbFoundBarcode)) {
Log.d(TAG, "refocusing");
//code in the book was:
//camera.autoFocus(this);
autoFocusLater(camera);
}
}
}
/**
* useful method for starting auto focus not too soon
*/
public void autoFocusLater(final Camera camera)
{
final ReadBarcode finalContext = this;
handler.postDelayed(new Runnable()
{
@Override
public void run()
{
try
{
camera.autoFocus(finalContext);
}
catch (RuntimeException e)
{
Log.d(TAG, "error focusing, camera may be closing");
}
}
}, 100);
}
/**
* mbFocused is true when the camera has successfully autofocused
*/
int mnFocused = 0;
/**
* 1D Barcode decoder
*/
Ean13Barcode1D me13b;
/**
* The expected position of the barcode, measured perpendicular
* to the orientation of the barcode, from 0-1
*/
double mdBarcodePerpPos;
private boolean mbFoundBarcode;
private TextView mTextViewResult;
private CheckBox mCheckBoxResult;
private CrosshairOverlay mCrosshairOverlay;
}