As you followed my blog, I also had 2 posts about this topic:
- Developing a simple Barcode Scanner by get scanned result from ZXing application.
- Embedding the Barcode/QR code scanner to your own application, not depend on the third-party application.
In this tutorial, I am going to help you get started with it.
Project configurations
dependencies scope of your app-level build.gradle:
compile 'com.google.android.gms:play-services:9.6.1'
Add this meta-data to <application> tag in your AndroidManifest.xml:
<meta-data
android:name="com.google.android.gms.vision.DEPENDENCIES"
android:value="barcode" />
Reading barcode/QR code from a photo
assets folder. I’m going to name the photo qr_code.png:Firstly, you must decode your photo to a
Bitmap by using BitmapFactory, this Bitmap is needed to Vison API as input:
Bitmap myQRCode = BitmapFactory.decodeStream(getAssets().open("qr_code.png"));
To detect QR codes(and other types of barcodes), you should use an instance of the BarcodeDetector class. The following code shows you how to create one using BarcodeDetector.Builder:
BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(PhotoActivity.this)
.setBarcodeFormats(Barcode.QR_CODE) // set QR code as the format type
.build();
Create a Frame using the Bitmap you created:
Frame frame = new Frame.Builder().setBitmap(myQRCode).build();
Call the detect() method of the BarcodeDetector to generate a SparseArray containing all the QR codes the BarcodeDetector detected in your photo:
SparseArray barcodes = barcodeDetector.detect(frame);
Okey, after detecting some Barcode objects, you can get their values by call displayValue field:
// Check if at least one barcode was detected
if (barcodes.size() != 0) {
// Display the QR code's message
textView.setText("QR CODE Data: " + barcodes.valueAt(0).displayValue);
//Display QR code image to ImageView
imageView.setImageBitmap(myQRCode);
} else {
textView.setText("No QR Code found!");
textView.setTextColor(Color.RED);
}
And this is full code for this activity:
PhotoActivity.java
Running this package info.devexchanges.barcodescannermobilevisionapi;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.SparseArray;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.google.android.gms.vision.Frame;
import com.google.android.gms.vision.barcode.Barcode;
import com.google.android.gms.vision.barcode.BarcodeDetector;
public class PhotoActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_photo);
View btnPhotoScan = findViewById(R.id.photo_scan);
final ImageView imageView = (ImageView) findViewById(R.id.image);
final TextView textView = (TextView) findViewById(R.id.qr_code_content);
btnPhotoScan.setOnClickListener(new View.OnClickListener() {
@SuppressLint("SetTextI18n")
@Override
public void onClick(View view) {
try {
Bitmap myQRCode = BitmapFactory.decodeStream(getAssets().open("qr_code.png"));
BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(PhotoActivity.this)
.setBarcodeFormats(Barcode.QR_CODE)
.build();
Frame frame = new Frame.Builder().setBitmap(myQRCode).build();
SparseArray barcodes = barcodeDetector.detect(frame);
// Check if at least one barcode was detected
if (barcodes.size() != 0) {
// Display the QR code's message
textView.setText("QR CODE Data: " + barcodes.valueAt(0).displayValue);
//Display QR code image to ImageView
imageView.setImageBitmap(myQRCode);
} else {
textView.setText("No QR Code found!");
textView.setTextColor(Color.RED);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
Activity, you can get this output:
Reading a barcode Using the Camera
Activity that does just that.
Firstly, you must request CAMERA permission in your AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
Creating a layout file (xml) for this Activity. I will use a SurfaceView to display the preview frames captured by the camera and a TextView to display the content barcode value:
activity_main.xml
In the activity Java code, to "stream" the camera preview scene to the <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<SurfaceView
android:id="@+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true" />
<TextView
android:id="@+id/barcode_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:text="No Barcode"
android:textColor="@android:color/white"
android:textSize="20sp" />
</RelativeLayout>
SurfaceView, we'll use an instance of CameraSource, initializing it with a BarcodeDetector object:
barcodeDetector = new BarcodeDetector.Builder(this)
.setBarcodeFormats(Barcode.ALL_FORMATS)
.build();
cameraSource = new CameraSource.Builder(this, barcodeDetector)
.setRequestedPreviewSize(1600, 1024)
.setAutoFocusEnabled(true) //you should add this feature
.build();
As noted in code, you should use setAutoFocusEnabled(true) when creating the CameraSource instance, your "camera preview" will be auto focused, not be blurry!Next, add a callback to the
SurfaceHolder of the SurfaceView so that you know when you can start drawing the preview frames. The callback should implement the SurfaceHolder.Callback interface. Inside the surfaceCreated() method, call the start() method of the CameraSource to start drawing the preview frames:
cameraView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
//noinspection MissingPermission
cameraSource.start(cameraView.getHolder());
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
cameraSource.stop();
}
});
The remaining work is displaying detected barcode content to TextView. We will use setProcessor() method of BarcodeDetector with the parameter is Detector.Processor:
barcodeDetector.setProcessor(new Detector.Processor() {
@Override
public void release() {
}
@Override
public void receiveDetections(Detector.Detections detections) {
final SparseArray barcodes = detections.getDetectedItems();
if (barcodes.size() != 0) {
barcodeValue.post(new Runnable() {
@Override
public void run() {
//Update barcode value to TextView
barcodeValue.setText(barcodes.valueAt(0).displayValue);
}
});
}
}
});
Moreover, you should override onDestroy() method of your Activity to release the CameraSource to stop drawing the preview frame. Finally, this is full code:
MainActivity.java
Running this activity and scanning a barcode, you may get result like this:
package info.devexchanges.barcodescannermobilevisionapi;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.SparseArray;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.TextView;
import com.google.android.gms.vision.CameraSource;
import com.google.android.gms.vision.Detector;
import com.google.android.gms.vision.barcode.Barcode;
import com.google.android.gms.vision.barcode.BarcodeDetector;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
private BarcodeDetector barcodeDetector;
private CameraSource cameraSource;
private SurfaceView cameraView;
private TextView barcodeValue;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.activity_main);
cameraView = (SurfaceView) findViewById(R.id.surface_view);
barcodeValue = (TextView) findViewById(R.id.barcode_value);
barcodeDetector = new BarcodeDetector.Builder(this)
.setBarcodeFormats(Barcode.ALL_FORMATS)
.build();
cameraSource = new CameraSource.Builder(this, barcodeDetector)
.setRequestedPreviewSize(1600, 1024)
.setAutoFocusEnabled(true) //you should add this feature
.build();
cameraView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
//noinspection MissingPermission
cameraSource.start(cameraView.getHolder());
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
cameraSource.stop();
}
});
barcodeDetector.setProcessor(new Detector.Processor() {
@Override
public void release() {
}
@Override
public void receiveDetections(Detector.Detections detections) {
final SparseArray barcodes = detections.getDetectedItems();
if (barcodes.size() != 0) {
barcodeValue.post(new Runnable() {
@Override
public void run() {
//Update barcode value to TextView
barcodeValue.setText(barcodes.valueAt(0).displayValue);
}
});
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
cameraSource.release();
barcodeDetector.release();
}
}
Conclusions
These are posts about Mobile Vision API on my blog:
- Faces detection on photo
- Text recognition by device's camera



