QRコードジェネレーター・QRコード作成するアプリを作りたい

スポンサーリンク
スポンサーリンク

QRコードリーダーを作る前に、ジェネレーターを作りたい

今日びQRコードなんてそこら中にあるわけだけど、せっかくなら自分で作ったQRコードを読んでみたい。なのでまず入力した文字列をQRコードに変換するようなアプリを作りたい。Howtoではないです。やった後に見つけたんだけど、こっち

QRコードの読取、生成をする [Android] - Qiita
開発環境OS: macOS HighSierraAndroid Studio: 3.0.1・APIレベルの設定build.gradleandroid { compileSdkVersion 26 ...
GitHub - journeyapps/zxing-android-embedded: Barcode scanner library for Android, based on the ZXing decoder
Barcode scanner library for Android, based on the ZXing decoder - GitHub - journeyapps/zxing-android-embedded: Barcode scanner library for Android, based on the...

のがいいと思いました。くそぅ。

スポンサーリンク

QRコードの仕様を見て実装する

のは無理、死ぬ。なので出来合いのもの、ライブラリを探す。最初からやりたい人は、こういう

QRコード規格化・標準化|QRコードドットコム|株式会社デンソーウェーブ
QRコードは国家規格や国際規格で規格化されており、誰でも安心して仕様を入手することができます。
QRコードをつくってみる その1
QRコードのエンコード方法についてのドキュメントです。簡単なデータ列を例にして、実際にエンコード(計算)する手順をステップをおいて説明しています。

のを見ながら作っていけばよいみたいです。すごいよなぁ、こういう人たち。

スポンサーリンク

QR-Code-generatorライブラリを使いたい

使いたい。Githubを検索してたら、

GitHub - nayuki/QR-Code-generator: High-quality QR Code generator library in Java, TypeScript/JavaScript, Python, Rust, C++, C.
High-quality QR Code generator library in Java, TypeScript/JavaScript, Python, Rust, C++, C. - GitHub - nayuki/QR-Code-generator: High-quality QR Code generator...
QR Code generator library

こちらを見つけた。Javaってなってるし、いけんだろと思った。この時は。

Gradleに追記する

implementation 'io.nayuki:qrcodegen:1.4.0'

mavencentralでjarが公開されてたので、こう書いてSyncしたら自動でやってくれた。mavenでの書き方が分からんかったけど、versionクリックして右の方にgradleでの書き方が載ってて助かった。

参考

Maven Central Repository Search
Official search by the maintainers of Maven Central Repository
android studioでmavenの使い方が分かりません。
android studioでmavenの使い方が分かりません。 これを使いたくて ソースに repositories

サンプルコードを書いてみる→失敗

あっるぇー?いつもどおりAlt+Enterを押しまくったのだけど、赤いのが消えてくれない。なんでやろーと思ったら、AndroidではBufferedImageは使えないみたい。なんということでしょう。あれ?ていうことはこのライブラリ利用できないの?じゃあどうしてるの?と、ちょっこし調べてみると、先駆者はBufferedImageを書き換えてBitmapというものを利用しているようだ。似たようなもんだろうし、俺にもできんだろーと思ったのが沼の始まりであった。

参考

Androidjavaで画素についてAndroidStudioで開発しています.こちらのURLを参考にして,プログラムを書いたので... - Yahoo!知恵袋
Androidjavaで画素についてAndroidStudioで開発しています.こちらのURLを参考にして,プログラムを書いたのですが, 等がimportできずBufferedImageが使えない状態です.java.awt.fontはあるのですが,他はサジェストされません....
How can I import java.awt.image.BufferedImage in Android Studio
I need my android app to recognize BufferedImage and I am using Android Studio.I've seen that there is a way to import JRE library system in Eclipse but I am ha...
PinMarch: QRコードを作ってみる
java.awt.BufferedImage から android.graphics.Bitmap へ - Android でいろいろやるよ!
ここのコードを参考にして、android に移植してみた。元記事のコードで使われている java.awt.BufferedImag..
スポンサーリンク

QR-Code-generatorライブラリをAndroid用に書き換えたい

BufferedImageで受けてるんだから、ライブラリの中にBufferedImageを使ってる部分があるんだろーなーと思い、中を見てみることに。

QR-Code-generatorの中を見る

左上をProjectにして、ExternalLibraries→Gradle:io.nayuki:qrcodegen:[email protected]→qrcodegen-1.4.0.jar→io.nayuki.qrcodegenと進んでいき、中に入ってるclassファイルを開いてみると…、赤いとこあった!ここをAndroidのBitmapにしてけばいいんだろーなーと、書き換えようと思ったら

File is read-only

File is not Writable

の表示ががが…。あ、まじでこれできないやつだ、と思ったのだけれど、ソース公開されてんのに書き換えできないってどういうことだよと思ったら、自分で生のjavaファイルからjarを作成すればいけるっぽい。なんかどんどんやること増えてないか。ぐるぐる調べているうちに、このライブラリを速くしたぜ!ってなライブラリを見つけた。それもJavaオンリーやで。

GitHub - nayuki/Fast-QR-Code-generator: This project moved
This project moved. Contribute to nayuki/Fast-QR-Code-generator development by creating an account on GitHub.
Fast QR Code generator library

どうせなので、こっちを書き換えてみたい。みたいって、できるのかな。

参考

JAR (ファイルフォーマット) - Wikipedia
Android Studioでライブラリを取り込む3つの方法 - メモ2ブログ
以下の3種類があります。 A. libs配下にjarを配置 B. ライブラリのprojectフォルダを読み込む C. 外部のリポジトリからローカルに取り込む それぞれの具体的な手順と、長所と短所を上げていきます。 A. libs配下にjarを配置 広告のSDKなどを組み込む際によく用いる。 手順 jarのファイル名はa...

java.awt.BufferedImageをandroid.graphics.Bitmapに置き換えたい

BufferedImageの方が何をやっているのかを見てきながら、Bitmapにそれっぽいのがないか探していく。

public BufferedImage toImage(int scale, int border) {
   if (scale <= 0 || border < 0)
      throw new IllegalArgumentException("Value out of range");
   if (border > Integer.MAX_VALUE / 2 || size + border * 2L > Integer.MAX_VALUE / scale)
      throw new IllegalArgumentException("Scale or border too large");
   
   BufferedImage result = new BufferedImage((size + border * 2) * scale, (size + border * 2) * scale, BufferedImage.TYPE_INT_RGB);
   for (int y = 0; y < result.getHeight(); y++) {
      for (int x = 0; x < result.getWidth(); x++) {
         boolean color = getModule(x / scale - border, y / scale - border);
         result.setRGB(x, y, color ? 0x000000 : 0xFFFFFF);
      }
   }
   return result;
}

1行目

BufferedImageは、まぁ赤い。戻り値をBitmapにしたいから、ここはBitmapにする。

2-5行目

scaleとborderってなんだろうと思ったら、scaleは各セル(黒い点・白い点)を何個のピクセルで構成するかみたい。例えばscale=1だと、1セル=1ピクセルだし、scale=2だと、1セル=4ピクセルになる。じゃあborderはというと、外側の余白部分をどれくらい取るか、という値みたい。で、この行ではそれぞれについて、オーバーだったり足りなかったりしたときにエラーになるようにしてるようだ。ここは変えなくてもよさそう。多分。

7行目

BufferedImageのコンストラクタを読んでみる。引数が3つだから多分これだろう。縦横とカラースペースを指定してるのかな。Androidの方でいうと、BitmapFactoryかな?使ったことあるし。て、思ったんだけど違うみたい。これはリソースから読み込む用で、無から作り出すにはcreateBitmapというメソッドがあるようだ。引数3つでそれっぽいやつといったらこれかなぁと思ったので、書いてみる。

Bitmap result = Bitmap.createBitmap((size + border * 2) * scale, (size + border * 2) * scale, Bitmap.Config.ARGB_8888);

x,yはそのままで、問題はBitmap.Configなのだけど、元のTYPE_INT_RGBはアルファ無しの8ビットRGBのようでBitmap.Configにはそんなものは無い。アルファ付きで近いやつがARGB_8888なので、これでいってみよう。アルファっつーのは透明度のことらしい。

8-9行目

getHeight,getWidthはBitmapの方にもあった(getHeight,getWidth)。戻り値もintだし大丈夫だと思う。この行で全ピクセルを走査してるんだろうなぁ。多分。

11行目

setRGBは引数3つだから多分これだ。x,y座標のピクセルに第3引数のRGB値の色を設定しているんだろう。この書き方がよく分かんなくてググりまくった。3項演算子というらしい。Bitmapの方に無いぞ…、あった。setPixelって名前なのね。書いてみる。

result.setPixel(x, y, color ? Color.argb(255, 0, 0, 0) : Color.argb(255, 255, 255, 255));

Bitmapの方に

The color must be a non-premultiplied ARGB value in the sRGB color space.

とあり、BufferedImageの方は6桁16進数なのだけど、アルファをプラスして8桁16進数にしなきゃみたい。ただ書き方分かんねぇなと思ってたらColorにこう書け、という記述があったので、こうしてみた。0x表記のほうが速いのかな。まぁそうだよな、いちいち計算するより結果が書いてあったほうが早そうだもんな。いやでもそこらへんコンパイラが最適化とかしてくんないかな。してくれることを祈ろう。

書き換え後

import android.graphics.Bitmap;
import android.graphics.Color;
public Bitmap toImage(int scale, int border) {
    if (scale <= 0 || border < 0)
        throw new IllegalArgumentException("Value out of range");
    if (border > Integer.MAX_VALUE / 2 || size + border * 2L > Integer.MAX_VALUE / scale)
        throw new IllegalArgumentException("Scale or border too large");

    Bitmap result = Bitmap.createBitmap((size + border * 2) * scale, (size + border * 2) * scale, Bitmap.Config.ARGB_8888);
    for (int y = 0; y < result.getHeight(); y++) {
        for (int x = 0; x < result.getWidth(); x++) {
            boolean color = getModule(x / scale - border, y / scale - border);
            result.setPixel(x, y, color ? Color.argb(255, 0, 0, 0) : Color.argb(255, 255, 255, 255));
        }
    }
    return result;
}

不思議な点

これでなんでQRコードの画像の白黒ができるんだろ?と疑問が湧いてきて、10行目のgetModuleが怪しいと感じて見に行ったら

public boolean getModule(int x, int y) {
   return 0 <= x && x < size && 0 <= y && y < size && modules[y][x];
}

こんな感じだった。多分最後のmodules[y][x]に白黒どっちにするかのデータが入ってるのかな…。とにかく一応書き換えられたので、これでいってみよう。jarを作るのです。

スポンサーリンク

書き換えたjavaファイルを元にjarファイルを作りたい→無理

書き換え終わったのでjarファイルを作りたい。流れとしてはjavaファイルをclassファイルにして、それをjarファイルにまとめるって感じみたい。コマンドプロンプトでやればいいみたい。意気揚々と

javac -encoding UTF-8 *.java

とやってみると、

QrCode.java:26: エラー: パッケージandroid.graphicsは存在しません
import android.graphics.Bitmap;
^
QrCode.java:27: エラー: パッケージandroid.graphicsは存在しません
import android.graphics.Color;
^
QrCode.java:294: エラー: シンボルを見つけられません
public Bitmap toImage(int scale, int border) {
^
シンボル: クラス Bitmap
場所: クラス QrCode
QrCode.java:300: エラー: シンボルを見つけられません
Bitmap result = Bitmap.createBitmap((size + border * 2)
* scale, (size + border * 2) * scale, Bitmap.Config.ARGB_8888);
^
シンボル: クラス Bitmap
場所: クラス QrCode
QrCode.java:300: エラー: パッケージBitmapは存在しません
Bitmap result = Bitmap.createBitmap((size + border * 2)
* scale, (size + border * 2) * scale, Bitmap.Config.ARGB_8888);

^
QrCode.java:300: エラー: シンボルを見つけられません
Bitmap result = Bitmap.createBitmap((size + border * 2)
* scale, (size + border * 2) * scale, Bitmap.Config.ARGB_8888);
^
シンボル: 変数 Bitmap
場所: クラス QrCode
QrCode.java:304: エラー: シンボルを見つけられません
result.setPixel(x, y, color ? Color.argb(255, 0,
0, 0) : Color.argb(255, 255, 255, 255));
^
シンボル: 変数 Color
場所: クラス QrCode
QrCode.java:304: エラー: シンボルを見つけられません
result.setPixel(x, y, color ? Color.argb(255, 0,
0, 0) : Color.argb(255, 255, 255, 255));

^
シンボル: 変数 Color
場所: クラス QrCode
エラー8個

なん…だと…。どうもandroid.graphics.Bitmapとandroid.graphics.Colorが存在してないからコンパイルできないみたい。classファイルができないまま、

jar -cvf fastqrcodegen.jar *.java
implementation files('libs/fastqrcodegen.jar')

とかやっても ちゃんとできない。おいマジか、ここまできて無理なのかーいとがっかりしたところ、Android用のライブラリとして書けばいいみたいな感じの記事を発見した。ただ全部ソースをコピペだ。

参考

【Java入門】jarファイルの作成、解凍、実行について解説 | 侍エンジニアブログ
この記事では「 【Java入門】jarファイルの作成、解凍、実行について解説 」といった内容について、誰でも理解できるように解説します。この記事を読めば、あなたの悩みが解決するだけじゃなく、新たな気付きも発見できることでしょう。お悩みの方はぜひご一読ください。
JARファイル入門 - Qiita
本文では初学者用(自分用)に、JARファイルの作成から使用までをまとめていきたいと思います。JARファイルは複数のJavaのクラスやパッケージを一つのファイルにまとめたものです。これを作成するには、jarコマンドを用いるのが良い...
Java コンパイルエラー エンコーディングwindows-31jにマップできません - Qiita
とにかくJavaに触れてみる①続くか分からないけど続きものっぽいタイトルにしてみました。今まで経験出来なかったJava。ちょっと憧れのあるJava。今回やっとチャレンジ出来ると思ったら、目の前で別の人に持っていかれちゃ...
スポンサーリンク

書き換えたjavaファイルを元にAndroidライブラリを作りたい

ここを参考に新しくModuleを作り、そこのjavaフォルダ内に元のjavaファイルと同じ名前のJavaClassを作り内容をコピペしていく。果たしてそんなことが許されるのか、ライセンス的にどうなんだという思いを置き去りに、作業を進めていった。

こうなりました。QrCodeGeneratorDemo.javaとpackage-info.javaは無くても大丈夫そうだったので、コピペしなかった。あとQrSegmentAdvanced.javaも、Call requires API level…が出てしまい、赤字の消し方が分からんかったのでコピペしなかった。最後にGradleに

implementation project(path: ':fastqrcodegen')

と追記してSyncすると使えるようになった。ただ、なんか、罪悪感があるんだけど、それはもうしょうがないよね。他のやり方がわからんし…。

スポンサーリンク

Fast-QR-Code-generatorを試してみる

適当にImageViewを設置し、onCreateに

imageView = findViewById(R.id.imageView);

QrCode qr0 = QrCode.encodeText("Hello, world!", QrCode.Ecc.MEDIUM);
Bitmap img = qr0.toImage(4, 10);

imageView.setImageBitmap(img);

結果がこちら

で、できた…、できたぞー!!感慨もひとしおである。ただ、アライメントがなーいのね。あら、そうなの。そうなのね。そっかー。ついてた。早とちり。データ量多くなると付くっぽい。ごめんなさい。

参考

Android | 表示するBitmapの指定
表示するBitmapの指定
スポンサーリンク

ZXing Android Embeddedを使ってみる

いやー、これ見つけた時はショックだったね。今までの俺の苦労はなんだったんだ、つって。

implementation 'com.journeyapps:zxing-android-embedded:3.6.0'

をgradleに追記。

<application android:hardwareAccelerated="true">

をAndroidManifest.xmlに追記。生成の場合はいらんようだ。

try {
    imageView = findViewById(R.id.imageView);
    BarcodeEncoder barcodeEncoder = new BarcodeEncoder();
    Bitmap bitmap = barcodeEncoder.encodeBitmap("Hello, world!", BarcodeFormat.QR_CODE, 400, 400);
    imageView.setImageBitmap(bitmap);
} catch (WriterException e) {
    e.printStackTrace();
}

Githubのサンプルほぼまんま。

はいっ、できましたー。アライメントもついてまーす。上のにも付いてた。

スポンサーリンク

所感

もっとちゃんとググる。

さぁ次はリーダーを作るぞー!

コメント

タイトルとURLをコピーしました