JavaFXと銘打ってはいるが、Zxingライブラリ自体はwebアプリケーションでもスマートフォン(Android)でもJava環境上であれば動作する。
■ Zxingライブラリ
ZxingライブラリはGoogleが公開しているバーコード作成・読取ライブラリである。ライセンスは『Apache License 2.0』であるため、商用利用も可能である。ライブラリは以下で公開されている。
表:ライブラリの公開場所
JavaFXで利用する場合に必要となるライブラリ・ファイルは以下の2つである。利用する際にはクラスパスを通すことを忘れてはいけない(別記事『
クラスパスの通し方』)。
- core-○○.jar
- javase-○○.jar
バーコードにもいろいろな規格が存在し、zxingではよく使われるバーコードの作成・読込が可能となっている(
*1)。スーパーなどで利用されている規格「EAN-13(JAN-13)」やQRコードにも対応している。
■ サンプル・プログラム(バーコード作成)
以下にEAN-13バーコードとQRコードを生成するサンプルプログラムを示す。
◇サンプルコード
package application;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.oned.EAN13Writer;
import com.google.zxing.qrcode.QRCodeWriter;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TestZxing extends Application
{
public static void main(String[] args)
{
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception
{
// フォント色がおかしくなることへの対処
System.setProperty( "prism.lcdtext" , "false" );
// シーングラフの作成
VBox root = new VBox();
root.getChildren().add( createBarcode( "1234567890128" , 200 , 40 ) ); // 1次元バーコードの作成
root.getChildren().add( createQRcode( "http://krr.blog.shinobi.jp/" , 100 , 100) ); // QRコード(2次元バーコード)の作成
// シーンの作成
Scene scene = new Scene( root , 250 , 200 );
// ウィンドウ表示
primaryStage.setScene( scene );
primaryStage.show();
}
/**
* 1次元バーコードの作成
*
* @param str QRコード化する文字列
* @param width QRコードの横幅
* @param height QRコードの高さ
* @return QRコードイメージ
* @throws Exception
*/
protected Node createBarcode( String str, int width , int height ) throws Exception
{
// ルートノードの作成
VBox root = new VBox();
// バーコード作成
EAN13Writer writer = new EAN13Writer();
BitMatrix mat = writer.encode( str , BarcodeFormat.EAN_13, width, height);
// ビット情報からJavaFXのImageクラスに変換
Image img = SwingFXUtils.toFXImage( MatrixToImageWriter.toBufferedImage( mat ) , null );
// シーングラフ用ノードに登録
ImageView view = new ImageView( img );
Label label = new Label( str );
root.getChildren().addAll( view , label );
return root;
}
/**
* QRコードの作成
*
* @param str QRコード化する文字列
* @param width QRコードの横幅
* @param height QRコードの高さ
* @return QRコードイメージ
* @throws Exception
*/
protected Node createQRcode( String str , int width , int height ) throws Exception
{
// QRコード作成
QRCodeWriter writer = new QRCodeWriter();
BitMatrix mat = writer.encode( str , BarcodeFormat.QR_CODE , width , height );
// ビット情報からJavaFXのImageクラスに変換
Image img = SwingFXUtils.toFXImage( MatrixToImageWriter.toBufferedImage( mat ) , null );
// シーングラフ用ノードに登録
ImageView view = new ImageView( img );
return view;
}
}
◇実行結果
◇解説
EAN-13バーコードの作成はcreateBarcode関数(37行目)、QRコードの作成はcreateQRcode関数(38行目)で行っている。バーコードの生成は作成したい規格のWriterを作成し、Writer::encode関数を呼び出せばよい(65行目~66行目、91行目~92行目)。zxingライブラリはSwing時代に作られたものなので、作成された画像はSwingのImageクラスである。このため、画像イメージはSwingFXUtils::toFXImage関数で変換する必要がある(69行目、95行目)。
注意が必要な点としては、EAN-13バーコードの13桁目の数字はチェック・ディジットになっている点である。適当な13桁の数字を入力とするとエラーになるため、チェック・ディジット計算用のサイト(
*5)などで値を計算する必要がある。
■ サンプル・プログラム(バーコード読取)
以下にEAN-13バーコードとQRコードを読み込むサンプルプログラムを示す。サンプルでは、読取に成功するもの「multiple1.png」「ean13.pn」と失敗するもの「multiple2.png」の例を確認している。バーコード画像は手元にあるものを利用しても問題ないが、バーコード画像はバーコードの周辺がある程度の余白で囲まれている必要がある(
*8)。
◇リソース
ファイル名 |
リソース |
multiple1.png |
|
multiple2.png |
|
ean13.png |
|
◇サンプルコード
package application;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Hashtable;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.Reader;
import com.google.zxing.Result;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.multi.GenericMultipleBarcodeReader;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TestZxingDecode extends Application
{
public static void main(String[] args)
{
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception
{
// フォント色がおかしくなることへの対処
System.setProperty( "prism.lcdtext" , "false" );
// シーングラフの作成
VBox root = new VBox();
// バーコードを取り込み、結果を画面に表示
// 正常に読み込める場合1
File file1 = new File( "img/multiple1.png" );
Image img1 = new Image( file1.toURI().toString() );
root.getChildren().add( readBarcode( img1 ) );
// 正常に読み込める場合2
File file2 = new File( "img/ean13.png" );
Image img2 = new Image( file2.toURI().toString() );
root.getChildren().add( readBarcode( img2 ) );
// 失敗する場合
File file3 = new File( "img/multiple2.png" );
Image img3 = new Image( file3.toURI().toString() );
root.getChildren().add( readBarcode( img3 ) );
// シーンの作成
Scene scene = new Scene( root , 500 , 300 );
// ウィンドウ表示
primaryStage.setScene( scene );
primaryStage.show();
}
/**
* バーコードの取込
* @param img
* @return
* @throws Exception
*/
protected Node readBarcode( Image fxImg ) throws Exception
{
// ルートノードの作成
HBox root = new HBox();
// 画像フォーマット変換
// JavaFXのImageクラス→SwingのImageクラス→Zxing用の画像クラス
BufferedImage swImg = SwingFXUtils.fromFXImage( fxImg , null );
LuminanceSource source = new BufferedImageLuminanceSource( swImg );
BinaryBitmap bitmap = new BinaryBitmap( new HybridBinarizer( source ) );
// バーコード読込
String str = "";
try {
// デコード準備
Reader reader = new MultiFormatReader();
GenericMultipleBarcodeReader mr = new GenericMultipleBarcodeReader( reader );
Hashtable<DecodeHintType, Object> decodeHints = new Hashtable<DecodeHintType, Object>();
decodeHints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
// デコード
Result[] result = mr.decodeMultiple( bitmap , decodeHints );
if( result == null ){ throw new Exception( "バーコードを認識できませんでした" ); }
// 結果取得
for( Result r : result )
{
// 文字列を取得
BarcodeFormat format = r.getBarcodeFormat();
str += format.name() + " : " + r.getText() + ";\n";
}
} catch (Exception e1) {
e1.printStackTrace();
str = "失敗";
}
// シーングラフ用ノードに登録
ImageView view = new ImageView( fxImg );
Label label = new Label( str );
root.getChildren().addAll( view , label );
return root;
}
}
◇実行結果
◇解説
実行結果を見るとバーコードの回転には対応していない模様である。コードを見てみると、バーコードの読取はreadBarcode関数で行っている(50行目、55行目、60行目)。
readBarcode関数内(78行目~121行目)では、画像フォーマットの変換(85行目~87行目)の後にデコードを行っている。デコードにはMultiFormatReaderクラスを利用する(93行目)MultiFormat::decode関数でもバーコードの読み込みはできるが、複数のバーコードにも対応するためにGenericMultipleBarcodeReaderクラスを利用している。GenericMultipleBarcodeReader::decodeMultiple関数で読取を実行し、バーコードが読み取れない場合はNotFoundExceptionが発生する(99行目)。
注意点として、読取画像内にバーコードが複数存在する場合に、zxingがバーコードと認識したオブジェクトが1つでも読み込めなかった場合にはNotFoundExceptionが発生することがあげられる。このため、3つ目の実行結果では読み込みに成功する2つのバーコード情報の取得もできなくなっている。
■ 参照
- バーコード講座 「JAN/EAN/UPC」
- 承認これくしょん 「Nashorn + JavaFXでQRコードを表示する」
- JavaDoc 「Class EAN13Writer」
- JavaDoc 「Class QRCodeWriter」
- 一般財団法人 流通システム開発センター 「JANコード、集合包装用商品コード(ITF)コードのチェックデジット計算方法」
- JavaDoc 「Class MultiFormatReader」
- JavaDoc 「Class GenericMultipleBarcodeReader」
- Stack Overflow 「ZXing 2.1: com.google.zxing.NotFoundException」