ZXing (Zebra Crossing) is an open-source Java library designed for processing 1D and 2D barcode images. It supports a wide range of formats, including UPC-A, UPC-E, EAN-8, EAN-13, Code 39, Code 93, and QR Code. This library facilitates barcode scanning and decoding using a device's camera, making it a staple choice for Android barcode applications.
Core Components of ZXing
The library architecture revolves around several key classes:
- CaptureActivity: The primary Activity controlling the scanning interface.
- CaptureActivityHandler: Coordinates the decoding process, managing messages between threads.
- DecodeThread: A background worker thread responsible for the CPU-intensive decoding operations to prevent UI freezing.
- CameraManager: Manages camera hardware interactions, such as opening the camera and setting parameters.
- ViewfinderView: A custom View that draws the scanning frame overlay.
Generating QR Codes
To generate a QR code, the input string must be encoded into a matrix of binary data and then rendered as a Bitmap. The following method demonstrates how to create a QR code image:
public Bitmap generateQRCode(String content, int width, int height) {
if (content == null || content.isEmpty()) {
return null;
}
try {
Map<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
QRCodeWriter writer = new QRCodeWriter();
BitMatrix matrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
int[] pixels = new int[width * height];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
pixels[y * width + x] = matrix.get(x, y) ? Color.BLACK : Color.WHITE;
}
}
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
} catch (WriterException e) {
e.printStackTrace();
}
return null;
}
Scanning and Decoding QR Codes
The scanning process is more complex as it involves camera management and asynchronous processing. The camera preview must be continuously captured and analyzed. To avoid Application Not Responding (ANR) errors, decoding is handled in a separate thread using a Handler.
The decoding logic typically involves managing states (PREVIEW, SUCCESS) and handling auto-focus callbacks. Below is an example of a handler processing decoding results:
@Override
public void handleMessage(Message message) {
switch (message.what) {
case R.id.decode_succeeded:
state = State.SUCCESS;
Bundle data = message.getData();
Bitmap barcodeImage = data.getParcelable(DecodeThread.BARCODE_BITMAP);
Result rawResult = (Result) message.obj;
handleScanResult(rawResult, barcodeImage);
break;
case R.id.decode_failed:
state = State.PREVIEW;
cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
break;
case R.id.auto_focus:
if (state == State.PREVIEW) {
cameraManager.requestAutoFocus(this, R.id.auto_focus);
}
break;
}
}
Once the decoding succeeds, the result can be processed. For instnace, if the QR code contains a URL, the application can open it in a browser:
private void handleScanResult(Result result, Bitmap barcode) {
String content = result.getText();
if (content.startsWith("http")) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(content));
startActivity(browserIntent);
} else {
new AlertDialog.Builder(this)
.setTitle("Scan Result")
.setMessage(content)
.setPositiveButton("OK", null)
.show();
}
}
Required Permissions
To utilize camera hardware for scanning, the following permissions must be declared in the AndroidManifest.xml file:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />