コマンドラインで バーコード画像認識 ZBarImg

必要に迫られ、画像ファイルからのバーコード認識ライブラリを探してました。

アプリケーションがJavaでWEBなので、AndroidでないJavaSE の API がふさわしいかと思い、

Zxing を調べてましたが、日本語情報少なく、StaackOverflowの投稿も、Android + QRコードが主、JavaのImageI/Oの記述がややこしく、Java8でエラー多発、未解決のとらうまもあり、

Zxing : https://github.com/zxing/zxing

ImageMagick のようにコマンド1行で目的達成したいので、さらに調べた結果、

ずばりなの見つけて、早速、組み込みました。

ZBarImg で出来ました。

ZBarImg 本家Home : http://zbar.sourceforge.net/

< 利用例 >

オプションなしで EAN13 が読めました。

< Windows >

c:\ZBar\bin>zbarimg R:\#ZBarImgTest\1.png
EAN-13:2400014821369
scanned 1 barcode symbols from 1 images

c:\ZBar\bin>zbarimg R:\#ZBarImgTest\2.png
EAN-13:4582298330770
scanned 1 barcode symbols from 1 images

c:\ZBar\bin>zbarimg R:\#ZBarImgTest\2.jpg
EAN-13:4582298330770
scanned 1 barcode symbols from 1 images


< Linux >

[root@???? zbarimg]# zbarimg 1.png
EAN-13:2400014821369
scanned 1 barcode symbols from 1 images in 0 seconds

[root@???? zbarimg]# zbarimg 1.png
EAN-13:2400014821369
scanned 1 barcode symbols from 1 images in 0 seconds

[root@???? zbarimg]# zbarimg 2.png
EAN-13:4582298330770
scanned 1 barcode symbols from 1 images in 0 seconds

[root@???? zbarimg]# zbarimg 2.jpg
EAN-13:4582298330770
scanned 1 barcode symbols from 1 images in 0 seconds

< 対象画像 >

Cancvsで切り抜き => Base64にエンコードしてアップロード => サーバーで保存

< コード例 >

JavaScript


        // @@ バーコード認識ボタンを押した時 @@ //
        $("#execbarcd").on("click", function (e) {

          // 切り抜き画像 //
          var canvasData = $("#RecCanvas").get(0).toDataURL("");

          // 不要な情報を取り除く
          canvasData = canvasData.replace(/^data:image\/png;base64,/, "");

          var data = {};
          data.file = canvasData;

          // アップロード //
          $.ajax({
            url: 'BarcodeRecog${LW}',
            type: 'POST',
            data: data,
            dataType: 'text',
            success: function (txt) {
              simpleDialog2($("#alertdialog"), "Result", txt, "Close");
              $("#ocrres").val(txt);
            },
            error(jqXHR, textStatus, errorThrown) {
              simpleDialog2($("#alertdialog"), "ERROR", textStatus, "Close");
            },

          });

        });

Javaサーブレット


    String b64txt = request.getParameter("file");

    StringBuffer buf = new StringBuffer();
    try {

      // 時刻文字列 //
      String nowTMSeqStr
              = DateFormatUtils.format(new Date(), "yyyyMMdd_HHmmssSSS");

      // 画像ファイルを保存 //
      byte[] decode = Base64.getDecoder().decode(b64txt);
      String fnm = fileLocationPath + nowTMSeqStr + ".jpg";
      Path path = Paths.get(fnm);
      Files.write(path, decode);
      
      // zbarimgでバーコード取得 //
      String cmd = "c:\\ZBar\\bin\\zbarimg " + fnm;      
      System.out.println(cmd);
      RuntimeExec RE = new RuntimeExec(cmd, 500);
      RE.exec();
      
      // 別クラスにあるRuntimeexecで実行 //
      String restxt = RE.getRestxt();
      String resjan = restxt.substring(restxt.indexOf(":") + 1);
      buf.append(resjan);

    }
    catch (Exception e) {
      e.printStackTrace();
      buf.append(this.FAIL_MESSAGE);
    }

MySQL || で SELECT列の連結

他のデータベースからの移行で、MySQLのSELECT列連結で || が使えないものかと思い、調べてると方法がわかりました。

sql_mode に、PIPES_AS_CONCAT を加えると出来ます。

[ my.cnf 例 ]

sql_mode='NO_ENGINE_SUBSTITUTION,PIPES_AS_CONCAT'

[ SELECT結果例 ]

mysql> select concat(host,user,plugin) from mysql.user where user = 'root' and host = 'localhost';
+------------------------------------+
| concat(host,user,plugin)           |
+------------------------------------+
| localhostrootmysql_native_password |
+------------------------------------+
1 row in set (0.00 sec)

mysql> select host || user || plugin from mysql.user where user = 'root' and host = 'localhost';
+------------------------------------+
| host || user || plugin             |
+------------------------------------+
| localhostrootmysql_native_password |
+------------------------------------+
1 row in set (0.00 sec)

ここで教えていただきました : http://proengineer.internous.co.jp/content/columnfeature/6836#section200

PHP GD 画像ファイル合成

[ コード例 ]


<?php

/**
 * GD 合成位置指定画像ファイル合成 
 * argv : 1:ファイル名A(背景), 2:ファイル名B(パネル), 3:生成ファイル名, 
 *        4:合成位置 (N, NE, E, SE, S, SW, W, NW, C), 5:パッディング (オプション) 
 */

// 引数取得 //
$fnm_a = $argv[1];
$fnm_b = $argv[2];
$fnm_new = $argv[3];
$mrglocation = $argv[4];
$PADDING = isset($argv[5]) ? $argv[5] : 12;   // 指定がない場合は12ピクセル

// Linux 引数の" が認識されてない対策 //
$fnm_a = str_replace("^", " ", $fnm_a);
$fnm_b = str_replace("^", " ", $fnm_b);
$fnm_new = str_replace("^", " ", $fnm_new);

// A, B画像サイズ, 画像タイプ取得 //
list($a_width, $a_height, $type_a) = getimagesize($fnm_a);
list($b_width, $b_height, $type_b) = getimagesize($fnm_b);

// 対象イメージ格納 //
switch ($type_a) {
  case IMAGETYPE_JPEG:    // 2
    $image_a = imagecreatefromjpeg($fnm_a);
    break;
  case IMAGETYPE_PNG:     // 3
    $image_a = imagecreatefrompng($fnm_a);
    break;
  case IMAGETYPE_GIF:     // 1
    $image_a = imagecreatefromgif($fnm_a);
    break;
}
switch ($type_b) {
  case IMAGETYPE_JPEG:    // 2
    $image_b = imagecreatefromjpeg($fnm_b);
    break;
  case IMAGETYPE_PNG:     // 3
    $image_b = imagecreatefrompng($fnm_b);
    break;
  case IMAGETYPE_GIF:     // 1
    $image_b = imagecreatefromgif($fnm_b);
    break;
}

// コピー先の画像,コピー元の画像,コピー先のx座標,コピー先のy座標,コピー元のx座標,コピー元のy座標,コピー元の幅,コピー元の高さ //
// 合成する //
switch ($mrglocation) {
  case "NW":   // 左上
    imagecopy($image_a, $image_b, $PADDING, $PADDING, 0, 0, $b_width, $b_height);
    break;
  case "NE":   // 右上
    imagecopy($image_a, $image_b, $a_width - $b_width - $PADDING, $PADDING, 0, 0, $b_width, $b_height);
    break;
  case "SE":   // 右下
    imagecopy($image_a, $image_b, $a_width - $b_width - $PADDING, $a_height - $b_height - $PADDING, 0, 0, $b_width, $b_height);
    break;
  case "SW":   // 左下
    imagecopy($image_a, $image_b, 12, $a_height - $b_height - $PADDING, 0, 0, $b_width, $b_height);
    break;

  case "N":    // 上中央
    imagecopy($image_a, $image_b, $a_width / 2 - $b_width / 2, $PADDING, 0, 0, $b_width, $b_height);
    break;
  case "S":    // 下中央
    imagecopy($image_a, $image_b, $a_width / 2 - $b_width / 2, $a_height - $b_height - $PADDING, 0, 0, $b_width, $b_height);
    break;
  case "E":    // 右中央
    imagecopy($image_a, $image_b, $a_width - $b_width - $PADDING, $a_height / 2 - $PADDING / 2, 0, 0, $b_width, $b_height);
    break;
  case "W":    // 左中央
    imagecopy($image_a, $image_b, $PADDING, $a_height / 2 - $PADDING / 2, 0, 0, $b_width, $b_height);
    break;
  case "C":    // 中央中央
    imagecopy($image_a, $image_b, $a_width / 2 - $b_width / 2, $a_height / 2 - $b_height / 2, 0, 0, $b_width, $b_height);
    break;
  }


// 結果ファイルに出力 //
$filepath = pathinfo($fnm_new);
$ext = mb_strtolower($filepath['extension']);
$res = 1;
try {
  if ($ext === "jpg" || $ext === "jpeg") {
    imagejpeg($image_a, $fnm_new, 100);
  }
  else if ($ext === "png") {
    imagepng($image_a, $fnm_new, 9);
  }
  else if ($ext === "gif") {
    imagegif($$image_a, $fnm_new, 100);
  }
}
catch (Exception $ex) {
  $res = 0;
}

// 解放 //
imagedestroy($image_a);
imagedestroy($image_b);

// 連想配列に格納 //
$responce = [];
$responce["Result"] = $res;

// JSONに変換して結果出力 //
//echo json_encode($responce, JSON_PRETTY_PRINT);
echo json_encode($responce);

?>


[ 利用例 ]

Aファイル (背景)

Bファイル (パネル)

合成結果 NE パディング指定あり

合成結果 SE

合成結果 SW

合成結果 NW

合成結果 S

プログラミング あるある話

  1. Java を使った後、PHP, JavaScript を使うと、リテラルのシングルコーテーションが許せなくなり、ダブルコーテーションに統一しようと思う。
  2. Delphi を使った後、他を使うと、ついつい、 = が =: になってしまう。(昔のこと)
  3. xml の <![CDATA[ は覚えてないので、いつもコピペ
  4. Java を使った後、PHP の型推論が、あいまいでいけないと思い、数値は必ずキャストする。
  5. やっぱり、bash shell が一番短く最優先して使うつもりになって、明日は忘れる。
  6. #!/bin/sh も覚えてないので、いつもコピペ
  7. CSS を使うか、JavaScript で設定するか、どっちでもいいことに、何時も時間かかってしまう。
  8. 今日もこっそり、バグフィックス
  9. SQLの標準が大事なので、。。。。。
  10. DOMを見れば何でも出来るが、独自functionと比べて、どちらを使うかを決める。
  11. 細かい不具合修正、元は誰のせいでもなく、全部、構造的解決不能問題にしてやることで、気楽になる。
  12. foo hoge か hello word か あほぼけにすべきかで悩んでしまう。
  13. 英語で困ったことはない。相手が困ったかどうかは不明。
  14. 片仮名英語は思考停止を誘発するので日本語基本で行こうと思う。
  15. vimとviの使い分けがよいのか、vimのカスタマイズがよいのか迷う。

 

MySQL 8 CTE を試す

VirtualBox の CentOS7 に入れた MySQL 8 で CTE を試してみました。

あまり参考にはならず、利用効果少ないですが、

[ 利用例 ]

貼ってから気づいたのですが、プラグインの Simple Code Highlighter が対応してなく、with が太字になってないです。


with cnttbl (ld, dc, cnt)
as (
select
	d, dc, count(id) as cnt
from
	sch_export_source
group by
	ld, dc
)

select
	dc,
	pp.CD_CNTRY,
	c.CD_REGION,

	sum(Tomakomai) as Tomakomai,
	sum(Sendai) as Sendai,
	sum(Tokyo) as Tokyo,
	sum(Chiba) as Chiba,
	sum(Yokohama) as Yokohama,
	sum(Shimizu) as Shimizu,

	sum(Niigata) as Niigata,
	sum(Toyama) as Toyama,

	sum(Nagoya) as Nagoya,
	sum(Yokkaichi) as Yokkaichi,
	sum(Osaka) as Osaka,
	sum(Kobe) as Kobe,

	sum(Mizushima) as Mizushima,
	sum(Hiroshima) as Hiroshima,
	sum(Matsuyama) as Matsuyama,

	sum(Moji) as Moji,
	sum(Hakata) as Hakata,

	sum(Kagoshima) as Kagoshima,
	sum(Naha) as Naha

from
	(
	select
		dc,

		case when (ld = 'Tomakomai') then cnt else 0 end as Tomakomai,
		case when (ld = 'Sendai') then cnt else 0 end as Sendai,
		case when (ld = 'Tokyo') then cnt else 0 end as Tokyo,
		case when (ld = 'Chiba') then cnt else 0 end as Chiba,
		case when (ld = 'Yokohama') then cnt else 0 end as Yokohama,
		case when (ld = 'Shimizu') then cnt else 0 end as Shimizu,

		case when (ld = 'Niigata') then cnt else 0 end as Niigata,
		case when (ld = 'Toyama Shinko') then cnt else 0 end as Toyama,

		case when (ld = 'Nagoya') then cnt else 0 end as Nagoya,
		case when (ld = 'Yokkaichi') then cnt else 0 end as Yokkaichi,
		case when (ld = 'Osaka') then cnt else 0 end as Osaka,
		case when (ld = 'Kobe') then cnt else 0 end as Kobe,

		case when (ld = 'Mizushima') then cnt else 0 end as Mizushima,
		case when (ld = 'Hiroshima') then cnt else 0 end as Hiroshima,
		case when (ld = 'Matsuyama') then cnt else 0 end as Matsuyama,

		case when (ld = 'Moji') then cnt else 0 end as Moji,
		case when (ld = 'Hakata') then cnt else 0 end as Hakata,

		case when (ld = 'Kagoshima') then cnt else 0 end as Kagoshima,
		case when (ld = 'Naha') then cnt else 0 end as Naha

	from
		/*  この部分を CTE にしてみる */
		/*(
		select
			ld, dc, count(id) as cnt
		from
			sch_export_source
		group by
			ld, dc
		)a*/
		cnttbl a	
	) b
	left outer join mst_ppcnv pp on (b.dc = pp.NM)
	left outer join mst_cntry c on (pp.CD_CNTRY = c.CD_CNTRY) 
group by
	dc, CD_CNTRY,
	CD_REGION
order by
  CD_CNTRY, dc;