Не удается получить 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
        }

    }
}
Другие вопросы по тегам