8 Ekim 2013 Salı

Android ile QR Kod ve Barkod Okuma

Mobil cihazların hayatımıza girmesiyle QR Kod ve Barkod okumak iş hayatında gereksinimler sıralamasında üst sıralara tırmanmaya devam ediyor. Bugün Play Store, Apple Store ve Windows Store'a baktığımız zaman birçok QR ve Barkod okuyabilen uygulamalara erişebilmemiz mümkün. Fakat bunlar sadece genel kullanımlarda işe yaramakta.

Kurumsal şirketler kendi mobil uygulamalarını yaptığı zaman özellikle stok takibi için barkod ve QR kod okumayı en hızlı ve pratik çözüm olarak görüyorlar. Böyle durumlarda QR kod ve barkod okuma spesifik istekler arasına giriyor ve internetten uygulama bulmak yerine biz yazılımcılara büyük iş düşüyor. Kurumsal şirketlerin mobil uygulamalarında kendi istekleri doğrultusunda çalışacak bir barkod okuyucu geliştirmek durumunda kalıyoruz.

QR kod ve barkod okuyabilmek için birçok implementasyon yapmamız gerekiyor. Öncelikle zbar, armeabi, armeabi-v7a, x86 gibi bir çok kütüphaneyi uygulamamıza entegre etmemiz gerekiyor. Bu kütüphanelerin uygulamanın libs klasöründe durması yeterli olacaktır. Blog sonunda örnek bir uygulamayı sizinle paylaşacağım.

Öncelikle AndroidManifest.xml dosyamızda kameranın açılması için gerekli izinleri vermemiz gerekiyor. Aşağıdaki permission'ı kopyalayıp yapıştıralım.



Şimdi gerekli implementasyonlara başlayabiliriz. Barkod okumak için kameranın açılacağı activity'nin xml'ini oluşturalım.




  

  

  


FrameLayout'ta kameramız açılacak. TextView'da da okuma başarılı olduğu takdirde okuduğu şeyi yazacak. Örneğin bir URL, bir yazı veya bir e-mail adresi, farketmez.

Şimdi kameramıza gerekli ayarları verip, FrameLayout'umuza yerleştirmek için CameraPreview.java dosyamızı oluşturuyoruz.

import java.io.IOException;

import android.content.Context;
import android.content.res.Configuration;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PreviewCallback;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder mHolder;
    private Camera mCamera;
    private PreviewCallback previewCallback;
    private AutoFocusCallback autoFocusCallback;

    public CameraPreview(Context context, Camera camera,
                         PreviewCallback previewCb,
                         AutoFocusCallback autoFocusCb) {
        super(context);
        mCamera = camera;
        previewCallback = previewCb;
        autoFocusCallback = autoFocusCb;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);

        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
        } catch (IOException e) {
            Log.d("DBG", "Error setting camera preview: " + e.getMessage());
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // Camera preview released in activity
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        /*
         * If your preview can change or rotate, take care of those events here.
         * Make sure to stop the preview before resizing or reformatting it.
         */
        if (mHolder.getSurface() == null){
          // preview surface does not exist
          return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
          // ignore: tried to stop a non-existent preview
        }

        try {
         if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
          mCamera.setDisplayOrientation(90);        
         }
         else if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
          mCamera.setDisplayOrientation(0);
         }

            mCamera.setPreviewDisplay(mHolder);
            mCamera.setPreviewCallback(previewCallback);
            mCamera.startPreview();
            mCamera.autoFocus(autoFocusCallback);
        } catch (Exception e){
            Log.d("DBG", "Error starting camera preview: " + e.getMessage());
        }
    }
}

Bu ayarlarla kameramızın bulunduğu oryantasyona göre görüntülenme açısı belirlenecek. Şimdi barkodun okutulacağı MainActivity.java'ımızın içini dolduralım.

import net.sourceforge.zbar.Config;
import net.sourceforge.zbar.Image;
import net.sourceforge.zbar.ImageScanner;
import net.sourceforge.zbar.Symbol;
import net.sourceforge.zbar.SymbolSet;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.os.Handler;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.TextView;

public class MainActivity extends Activity {

 private Camera mCamera;
    private CameraPreview mPreview;
    private Handler autoFocusHandler;

    TextView scanText;
    Button scanButton;

    ImageScanner scanner;

    private boolean barcodeScanned = false;
    private boolean previewing = true;

    static {
        System.loadLibrary("iconv");
    } 

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        autoFocusHandler = new Handler();
        mCamera = getCameraInstance();

        /* Instance barcode scanner */
        scanner = new ImageScanner();
        scanner.setConfig(0, Config.X_DENSITY, 3);
        scanner.setConfig(0, Config.Y_DENSITY, 3);

        mPreview = new CameraPreview(this, mCamera, previewCb, autoFocusCB);
        FrameLayout preview = (FrameLayout)findViewById(R.id.cameraPreview);
        preview.addView(mPreview);

        scanText = (TextView)findViewById(R.id.scanText);

    }

    public void onPause() {
        super.onPause();
        releaseCamera();
    }

    /** A safe way to get an instance of the Camera object. */
    public static Camera getCameraInstance(){
        Camera c = null;
        try {
            c = Camera.open();
        } catch (Exception e){
        }
        return c;
    }

    private void releaseCamera() {
        if (mCamera != null) {
            previewing = false;
            mCamera.setPreviewCallback(null);
            mCamera.release();
            mCamera = null;
        }
    }

    private Runnable doAutoFocus = new Runnable() {
            public void run() {
                if (previewing)
                    mCamera.autoFocus(autoFocusCB);
            }
        };

    PreviewCallback previewCb = new PreviewCallback() {
            public void onPreviewFrame(byte[] data, Camera camera) {
                Camera.Parameters parameters = camera.getParameters();
                Size size = parameters.getPreviewSize();

                Image barcode = new Image(size.width, size.height, "Y800");
                barcode.setData(data);

                int result = scanner.scanImage(barcode);
                
                if (result != 0) {
                    
                    SymbolSet syms = scanner.getResults();
                    for (Symbol sym : syms) {
                        scanText.setText("Barkod Sonucu: " + sym.getData());
                        scanText.setTextColor(Color.parseColor("#00AF03"));
                        barcodeScanned = true;
                        releaseCamera();
                        Intent intent = new Intent();
                        intent.putExtra("SCAN_RESULT", sym.getData());
                        setResult(RESULT_OK, intent);
                    }
                }
            }
        };

    // Mimic continuous auto-focusing
    AutoFocusCallback autoFocusCB = new AutoFocusCallback() {
            public void onAutoFocus(boolean success, Camera camera) {
                autoFocusHandler.postDelayed(doAutoFocus, 1000);
            }
        };

}

Barkod okuyucumuz hazır. Artık kameramızla hem barkod hem de kare barkod okuyabiliyor olacağız. Okuma işlemi başarılı olduğunda kameranın altında okunulan şeyi görebileceksiniz. Aşağıdaki linkten uygulamanın source kodunu paylaşıyorum. Siz okuyucuyu dilediğiniz şekle dönüştürebilirsiniz.

BarcodeReader'ı İndir

11 yorum:

  1. import net.sourceforge.zbar.Config; hocam burada sıkıntı var ne yaptıysam çözemedim nasıl halledebilirz

    YanıtlaSil
    Yanıtlar
    1. Zbar'ın kütüphanesini projenize entegre etmeniz gerekiyor.

      Sil
  2. Merhaba hocam. Ben java da market otomasyonu ödevi aldım. ve bu barkod okuyuculu olacak. Bunu nasıl yapabilirim acaba. Teşekürler

    YanıtlaSil
  3. programı çalıstırabilen varmı acaba?

    YanıtlaSil
  4. Merhaba hocam ben mesela eger qr kod da link varsa link i direk acmasini saglayaniliyor muyuz web tarayici uzerinden

    YanıtlaSil
  5. zbar kütüphanesini projemize nasıl entegre ediyoruz ?

    YanıtlaSil
    Yanıtlar
    1. Merhaba,

      Hocanın verdiği barcodeReader programını indirip. Oradaki libs klasörünün içeriğini kopyalıp kendi projende libs içine yapıştırıp. Daha sonrasında ise build.gradle dosyası içerisinde
      implementation files('libs/zbar.jar') yazınca çalışıyor

      Sil
  6. Güzel bilgiler. Teşekkürler. QR kodu ile kartsız para çekme işlemini merak edenler bağlantıya göz atabilir. Yapı Kredi QR kodu ile kartsız para çekme ve Garanti Bankası QR kodu ile kartsız para çekme işlemleri gibi birçok işlem bu bağlantılarda yer alıyor.

    YanıtlaSil
  7. Paylaşım için teşekkürler.

    YanıtlaSil
  8. kardeşim mesela qr kod okuttuktan sonra ekrana bir border gelsin olayı yapabiliyor muyuz ? Yani web sitesine gitmesinde bi ekran gelsin orada bir kaç bilgi yazsın gibi falan

    YanıtlaSil