ZXingのバージョンが上がったので使ってみます。 アンドロイドでバーコード読み取り では2.0でしたが、今回は2.1を使ってみます。

と言ってもそんなに違いがあるわけではないですが、何故か2.1の場合PlanarYUVLuminanceSource.javaの構成が変だったので、その辺も変更をかけながら使ってみます。

ZXing 2.1

2.0と同様、使用するファイルは3つ。

●coreフォルダーの中のcore.jar
●javaseフォルダーの中のjavase.jar

PlanarYUVLuminanceSource.javaは場所が変わっています。

●core/src/com/google/zxing/PlanarYUVLuminanceSource.java

でもPlanarYUVLuminanceSource.javaはこのままでは使えません。

以下、新規プロジェクトを作りながら変更をかけていきます。

新規プロジェクトではパッケージ名をcom.example.qrcode_zxingとしてみます。

Eclipseを起動してプロジェクトを作成。

libsフォルダー(無ければ作成)にcore.jar、javase.jarを移して、BuildPathをとおしておきます。

新しいパッケージを作成(com.google.zxing.client)し、PlanarYUVLuminanceSource.javaをここに移しますが、コードを少々変更します。

com.google.zxingのままだと、core.jarかjavase.jarのどちらか(or両方)とクラス名がかぶってしまいエラーになります。

PlanarYUVLuminanceSource.javaのpackage名をcom.google.zxing.clientに変更(clientでなくてもいいんですが)。

以下を追加。

import com.google.zxing.LuminanceSource;



後は、2.0と一緒。



【AndroidManifest.xml】

画面の向きをLandscapeにして、cameraを設定しておきます。



    <!-- 略 -->

<activity
            android:name=".MainActivity"
            android:label="@string/title_activity_main"
            android:screenOrientation="landscape" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
</activity>

    <!-- 略 -->

<uses-permission android:name="android.permission.CAMERA" />
    <!-- オートフォーカスを設定します -->
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />

    <!-- 略 -->


【activity_main.xml】

res/layoutフォルダーの中のxml。

ZXing2.1の中のandroid/res/layoutフォルダーの中のcapture.xmlを参考に。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
     
    <SurfaceView
        android:id="@+id/preview_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />
     
    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
         
        <View
            android:id="@+id/viewfinder_view"
            android:layout_width="400dip"
            android:layout_height="200dip"
            android:layout_centerVertical="true"
            android:layout_centerHorizontal="true"
            android:background="#55ff6666" />
         
    </RelativeLayout>

</FrameLayout>


【MainActivity.java】

package com.example.qrcode_zxing;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

import com.google.zxing.client.PlanarYUVLuminanceSource;
import java.io.IOException;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Point;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;

import android.view.KeyEvent;
import android.widget.ImageView;
import android.view.View;
import android.widget.LinearLayout;
import android.view.WindowManager.LayoutParams;
import android.view.Gravity;
import android.view.View.OnClickListener;

public class MainActivity extends Activity implements SurfaceHolder.Callback, Camera.PreviewCallback, Camera.AutoFocusCallback {

    private static final String TAG = "ZXingBase";

    private static final int MIN_PREVIEW_PIXCELS = 320 * 240;
    private static final int MAX_PREVIEW_PIXCELS = 800 * 480;
    private Camera myCamera;
    private SurfaceView surfaceView;
    
    private Boolean hasSurface;
    private Boolean initialized;
    
    private Point screenPoint;
    private Point previewPoint;
    
    private static final int DIALOG_EXIT = 0;
        
    
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
         
        Window window = getWindow();
        window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
         
        hasSurface = false;
        initialized = false;
         
        setContentView(R.layout.activity_main);
        
        
        LinearLayout linear_LayoutR = new LinearLayout(this);
        linear_LayoutR.setOrientation(LinearLayout.VERTICAL);
        linear_LayoutR.setGravity(Gravity.RIGHT|Gravity.TOP);
        addContentView(linear_LayoutR, new LayoutParams());

        ImageView iv = new ImageView(this);
        iv.setVisibility(View.VISIBLE);
        iv.setOnClickListener(new OnClickListener() {
             
            @Override
            public void onClick(View v) {
                // ボタンクリックの処理
                if (myCamera != null) {
                    
                    Camera.Parameters parameters = myCamera.getParameters();
                    if (!parameters.getFocusMode().equals(Camera.Parameters.FOCUS_MODE_FIXED)) {
                        myCamera.autoFocus(MainActivity.this);
                    }
                
            }
            }
        });
        iv.setImageResource(R.drawable.shutter);
        linear_LayoutR.addView(iv, new LinearLayout.LayoutParams(155,90));
        
        
        
    }
    
    @Override
    protected void onResume() {
        super.onResume();
         
        surfaceView = (SurfaceView)findViewById(R.id.preview_view);
        SurfaceHolder holder = surfaceView.getHolder();
        if (hasSurface) {
            initCamera(holder);
        } else {
            holder.addCallback(this);
            holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }
    }
    
    @Override
    protected void onPause() {
        closeCamera();
        if (!hasSurface) {
            SurfaceHolder holder = surfaceView.getHolder();
            holder.removeCallback(this);
        }
        super.onPause();
    }
    
    
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if (!hasSurface) {
            hasSurface = true;
            initCamera(holder);
        }
    }
    
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        hasSurface = false;
    }
    
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
 
    }
    
    @Override
    public void onAutoFocus(boolean success, Camera camera) {
        if (success)
            camera.setOneShotPreviewCallback(this);
    }
    
   
    
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent msg){
        
        switch(keyCode){
        
            case android.view.KeyEvent.KEYCODE_BACK :
                showDialog( DIALOG_EXIT );
                return true;
        }
        return false;
    }
    
    /** Camera.PreviewCallback */
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        View finderView = (View)findViewById(R.id.viewfinder_view);
         
        int left = finderView.getLeft() * previewPoint.x / screenPoint.x;
        int top = finderView.getTop() * previewPoint.y / screenPoint.y;
        int width = finderView.getWidth() * previewPoint.x / screenPoint.x;
        int height = finderView.getHeight() * previewPoint.y / screenPoint.y;
         
        PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data,previewPoint.x,previewPoint.y,left,top,width,height,false);
         
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        MultiFormatReader reader = new MultiFormatReader();
        try {
            Result result = reader.decode(bitmap);
            Toast.makeText(this, result.getText(), Toast.LENGTH_LONG).show();
            
        } catch (Exception e) {
            //Toast.makeText(this, "error: " + e.getMessage(), Toast.LENGTH_LONG).show();
            Toast.makeText(this, "読み取れませんでした: " + e.getMessage(), Toast.LENGTH_LONG).show();
        }
    }
    
    //---------------------------------------------------------------------------------

    private void initCamera(SurfaceHolder holder) {
        try {
            openCamera(holder);
        } catch (Exception e) {
            Log.w(TAG, e);
        }
    }
    
    private void openCamera(SurfaceHolder holder) throws IOException {
        if (myCamera == null) {
            myCamera = Camera.open();
            if (myCamera == null) {
                throw new IOException();
            }
        }
        myCamera.setPreviewDisplay(holder);
         
        if (!initialized) {
            initialized = true;
            initFromCameraParameters(myCamera);
        }
         
        setCameraParameters(myCamera);
        myCamera.startPreview();
    }
    
 
    private void closeCamera() {
        if (myCamera != null) {
            myCamera.stopPreview();
            myCamera.release();
            myCamera = null;
        }
    }
    

    private void setCameraParameters(Camera camera) {
        Camera.Parameters parameters = camera.getParameters();
         
        parameters.setPreviewSize(previewPoint.x, previewPoint.y);
        camera.setParameters(parameters);
    }

    private void initFromCameraParameters(Camera camera) {
        Camera.Parameters parameters = camera.getParameters();
        WindowManager manager = (WindowManager)getApplication().getSystemService(Context.WINDOW_SERVICE);
        Display display = manager.getDefaultDisplay();
        int width = display.getWidth();
        int height = display.getHeight();
         
        if (width < height) {
            int tmp = width;
            width = height;
            height = tmp;
        }
         
        screenPoint = new Point(width, height);
        Log.d(TAG, "screenPoint = " + screenPoint);
        previewPoint = findPreviewPoint(parameters, screenPoint, false);
        Log.d(TAG, "previewPoint = " + previewPoint);
    }
    
    
    private Point findPreviewPoint(Camera.Parameters parameters, Point screenPoint, boolean portrait) {
        Point previewPoint = null;
        int diff = Integer.MAX_VALUE;
         
        for (Camera.Size supportPreviewSize : parameters.getSupportedPreviewSizes()) {
            int pixels = supportPreviewSize.width * supportPreviewSize.height;
            if (pixels < MIN_PREVIEW_PIXCELS || pixels > MAX_PREVIEW_PIXCELS) {
                continue;
            }
             
            int supportedWidth = portrait ? supportPreviewSize.height : supportPreviewSize.width;
            int supportedHeight = portrait ? supportPreviewSize.width : supportPreviewSize.height;
            int newDiff = Math.abs(screenPoint.x * supportedHeight - supportedWidth * screenPoint.y);
             
            if (newDiff == 0) {
                previewPoint = new Point(supportedWidth, supportedHeight);
                break;
            }
             
            if (newDiff < diff) {
                previewPoint = new Point(supportedWidth, supportedHeight);
                diff = newDiff;
            }
        }
        if (previewPoint == null) {
            Camera.Size defaultPreviewSize = parameters.getPreviewSize();
            previewPoint = new Point(defaultPreviewSize.width, defaultPreviewSize.height);
        }
         
        return previewPoint;
    }
    
    //-----------------------------
    protected Dialog onCreateDialog(int id) {
        Dialog dialog;
        switch(id) {
            case DIALOG_EXIT:
            {
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setMessage(
                    "Really want to quit the application?"
                )
                .setCancelable(true)
                .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        finish();
                    }})
                    .setNegativeButton("No", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            dialog.cancel();
                        }});
                    dialog = builder.create();
                    break;
            }
            default:
            dialog = null;
        }
        return dialog;
    }

}




今回は画面上のボタンをタップしてリードします。









インストール

Target:Android 2.3.3 or later

動作確認実機:Xperia acro(docomo) Android 2.3.4



アプリをQRコードからインストールする方法はコチラを参照


タブレットの場合

QRコードでダウンロードすると、Downloadフォルダー内でzipファイルになってインストールできない状態の場合があります。

その場合は、拡張子のzipをapkに変更してファイル名をタップすればインストール用のダイアログが出ますので、そこからインストールしてください。