Не удается получить zxing 2.3 для декодирования штрих-кода, используя только библиотеки Android
Я нашел несколько хороших примеров кода (например, этот: http://www.codepool.biz/ocr-barcode-twain/how-to-implement-a-simple-barcode-scan-application-on-android.html), которые описывают, как использовать библиотеку ZXing для декодирования QR-кодов в приложении для Android.
Однако в файле ZXing 2.3 core.jar отсутствуют классы, такие как BufferedImageLuminanceSource
который используется в большей части кода, который я нашел. В этом случае я решил попытаться перепроектировать части приложения сканера штрих-кода, чтобы соответствовать, и придумал следующее:
Переменная Result rawResult
в onPreviewFrame()
Метод всегда нулевой. Что я делаю неправильно?
РЕДАКТИРОВАТЬ: Интеграция ZXing с использованием Intents невозможна для этого проекта, только к вашему сведению.
Планировка:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:drawable/btn_default"
tools:context=".RedactedFragment" >
<SurfaceView
android:id="@+id/cameraViewfinder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true" />
</FrameLayout>
RedactedFragment.java:
import java.util.Map;
import java.util.TreeMap;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.PlanarYUVLuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import android.graphics.Rect;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.os.Bundle;
import android.app.Activity;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLayoutChangeListener;
import android.view.ViewGroup;
import android.widget.Toast;
/**
* An {@link android.app.Fragment} subclass for the ###{@link RedactedActivity}### which will serve as the fourth {@link Fragment} to be displayed inside the ###{@link RedactedActivity}###.
*/
public class RedactedFragment extends Fragment implements Callback,
PreviewCallback, OnClickListener, OnLayoutChangeListener {
FragmentSwapperIFace act;
Camera cam;
boolean cameraReady = false;
SurfaceView cameraViewfinder;
SurfaceHolder surfaceHolder;
int wx, hy;
public RedactedFragment() {
// Required empty public constructor
}
/**
* The {@link Fragment#onPause()} method is overridden to ensure that the camera is released cleanly by this {@link Fragment}
* @see android.app.Fragment#onPause()
*/
@Override
public void onPause() {
// TODO Auto-generated method stub
super.onPause();
cam.setPreviewCallback(null);
cam.release();
}
/**
* The {@link Fragment#onResume()} method is overridden to ensure that the camera is properly setup and that the {@link PreviewCallback} is added to it.
* @see android.app.Fragment#onResume()
*/
@Override
public void onResume() {
// TODO Auto-generated method stub
super.onResume();
cam = Camera.open();
cam.setPreviewCallback(this);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_qrscan, container, false);
cameraViewfinder = (SurfaceView) v.findViewById(R.id.cameraViewfinder);
surfaceHolder = cameraViewfinder.getHolder();
surfaceHolder.addCallback(this);
cameraViewfinder.addOnLayoutChangeListener(this);
cameraViewfinder.setOnClickListener(this);
return v;
}
/**
* This method is overridden to add the {@link FragmentSwapperIFace} for requesting that the parent {@link Activity} swap this part of the UI for a different {@link Fragment}
* @see android.app.Fragment#onAttach(android.app.Activity)
*/
@Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
try {
act = (FragmentSwapperIFace) activity;
} catch (Exception e) {
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Camera.Parameters parameters = cam.getParameters();
Camera.Size size = getBestPreviewSize(width, height, parameters);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
cam.setParameters(parameters);
cam.startPreview();
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
cam.setPreviewDisplay(holder);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
// TODO Auto-generated method stub
}
@Override
public void onClick(View v) {
act.swap(this, new ResultFragment(), R.id.layoutFragment_qr_fragment);
}
/**
* Method borrowed from the ZXing team's barcode scanner app
* @return {@link Camera.Size}
*/
private Camera.Size getBestPreviewSize(int width, int height,
Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) {
result = size;
}
}
}
}
return (result);
}
@Override
public void onPreviewFrame(final byte[] data, Camera camera) {
if (!cameraReady)
return;
Rect rect = getFramingRect();
PlanarYUVLuminanceSource src = new PlanarYUVLuminanceSource(data, camera.getParameters().getPictureSize().width, camera.getParameters().getPictureSize().height, rect.left, rect.top, camera.getParameters().getPictureSize().width, camera.getParameters().getPictureSize().height, true);
Result rawResult = null;
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(src));
Map<DecodeHintType, String> hints = new TreeMap<DecodeHintType, String>();
hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
try {
rawResult = new QRCodeReader().decode(bitmap);
} catch (Exception e) {
e.printStackTrace();
}
if(rawResult == null){
Toast.makeText(getActivity(), "rawResult is null", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getActivity(), rawResult.getText(), Toast.LENGTH_SHORT).show();
}
}
/**
* This method determines the size of the {@link SurfaceView} that the camera preview will be displayed on
* @return {@link Rect} a rectangle of the dimensions of the {@link SurfaceView}
* @author Original method by the ZXing team
*/
public Rect getFramingRect() {
Rect framingRect;
if (cam == null)
return null;
framingRect = new Rect(0, 0, wx, hy);
return framingRect;
}
@Override
public void onLayoutChange(View v, int left, int top, int right,
int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
if (v.getId() == cameraViewfinder.getId()) {
wx = v.getWidth();
hy = v.getHeight();
cameraReady = true;
}
}
}
ОБНОВЛЕНИЕ: теперь я скопировал этот фрагмент в его собственное тестовое приложение с теми же условиями работы, и он работает в тестовом приложении. На тестовом устройстве доступно много памяти, и фрагмент создается точно так же, как в тестовом приложении и реальном приложении. Почему new QRCodeReader.decode(bitmap)
метод всегда возвращает ноль в реальном приложении, используя один и тот же код?
1 ответ
Вы должны скопировать исходный код библиотеки Zxing в свой проект. Два пакета, которые вам понадобятся для сканирования QR-кода:
com.google.zxing.client.android
com.google.zxing.client.android.camera
После того, как вы скопировали эти пакеты, вы можете вызвать сканер QR-кода из вашей активности.
private static final int LOGIN_SCAN_REQUEST = 0;
/**
* Call this method from anywhere in the activity
*/
private void startScannerActivity()
{
Intent qrScannerIntent = new Intent(LoginActivity.this,
CaptureActivity.class);
startActivityForResult(qrScannerIntent,
LOGIN_SCAN_REQUEST);
}
/**
* Result is returned in this method after QR code scanning is complete
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == LOGIN_SCAN_REQUEST) {
if (resultCode == RESULT_OK) {
String qrcodeString = data.getStringExtra(
Intents.Scan.RESULT).trim();
Log.i("QR String", qrcodeString);
//Do what you want with QR Code here
}
}
}