前回に引き続き DXL を使って QR コードを作画に挑戦する話の後編です。今回はメインの部分である作画ルーチンを紹介します。
画像の準備
まず、作画に利用する画像を準備します。
QR コードの 1 マスは白か黒で構成されています。それぞれの画像をリッチテキストに並べれば QR コードができます。ただそれだとプログラミングとして芸がないので、2 x 2 マスのパターン 16 種の画像を準備します。
ファイル名は、左上、右上、左下、右下の順で 2進数としてつなぎ、16 進数に変換しています。例えば次のような感じです。
作成した画像はイメージリソースに登録しておきます。
作画ルーチンのサンプル
前回紹介できなかった xSetDXL_QR の全体像を先に紹介します。作画ルーチンはこの関数だけで構成されています。ポイントとなる点は後述のセクションで解説します。
Function xSetDXL_QR(vddn As NotesDOMDocumentNode, vdenPar As NotesDOMElementNode, vabQR() As Boolean) Dim denPic As NotesDOMElementNode Dim den As NotesDOMElementNode Dim x As Integer Dim y As Integer Dim by As Byte 'QR コードをイメージリソースに変換 For y = 0 To Int(UBound(vabQR, 2)/2) For x = 0 To Int(UBound(vabQR, 1)/2) '2 x 2 エリアのリソース番号を算出 by = 0 On Error Resume Next If vabQR(x*2, y*2) Then by = by + (2^0) If vabQR(x*2+1, y*2) Then by = by + (2^1) If vabQR(x*2, y*2+1) Then by = by + (2^2) If vabQR(x*2+1, y*2+1) Then by = by + (2^3) On Error GoTo 0 '画像の作成 Set den = vddn.CreateElementNode("picture") Set denPic = vdenPar.AppendChild(den) 'イメージリソースの指定 Set den = vddn.CreateElementNode("imageref") Call den.SetAttribute("name", Hex$(by) & ".png") Call denPic.AppendChild(den) Next '改行の追加 Set den = vddn.CreateElementNode("break") Set denPic = vdenPar.AppendChild(den) Next End Function |
ループの決定
事前に作成した画像の通り、QR コードの配列を 2 x 2 で抽出しながら処理しています。よってループ数は QR コードのサイズの半分となります。これを実現しているのか以下の For ループです。
For y = 0 To Int(UBound(vabQR, 2)/2) For x = 0 To Int(UBound(vabQR, 1)/2) |
UBound の 2 つ目の引数は多次元配列の次元数を指定します。それを利用して、縦と横の要素数の半分でループを回しています。半分にしているのは 2 x 2 単位で処理するからですね。また、端数をなくすために Int 関数を使用して整数部だけを取得しています。
配列 vabQR 要素数が 6 x 4 だったとすると、ループ変数 x と y は以下のようになるということです(実際の QR コードではもっと大きなサイズとなります)。
リソース番号の算出
2 x 2 のエリアに該当するリソース番号を算出しているのは以下の部分です。
'2 x 2 エリアのリソース番号を算出 by = 0 On Error Resume Next If vabQR(x*2, y*2) Then by = by + (2^0) If vabQR(x*2+1, y*2) Then by = by + (2^1) If vabQR(x*2, y*2+1) Then by = by + (2^2) If vabQR(x*2+1, y*2+1) Then by = by + (2^3) On Error GoTo 0 |
ループ変数 x と y を使用して vabQR の要素にアクセスします。2 倍して 1 を加算するかどうかで、上下左右の要素にアクセスしています(オレンジ)。その結果が True の場合、その位置に応じた値を加算しています(紫(青))。
ところで、If 文に "=" がないので、不自然に感じる方がいるかもしれません。
If vabQR(x*2, y*2) Then by = by + (2^0) |
これは配列 vabQR が Boolean 型であるからです。要素の値が True の場合 True = True のような判定をしても意味がありません。要素の値そのものが判定結果として使えるので、省略しています。
また、今回の演算の範囲に限り On Error Resume Next でエラーを無視するようにしています。これは、配列 vabQR の要素数が奇数だった時の対策で、範囲外の要素にアクセスしたエラーを無視するためです。QR コードの場合ではありえないパターンかもしれませんが...
イメージリソースの配置
イメージリソースの配置自体は単純です。picture ノードを作成し、その下に imageref ノードを追加し、リソース名を name 属性で設定します。リソース名は、事前に計算したリソース番号を 16 進数に変換して決定しています。
'画像の作成 Set den = vddn.CreateElementNode("picture") Set denPic = vdenPar.AppendChild(den) 'イメージリソースの指定 Set den = vddn.CreateElementNode("imageref") Call den.SetAttribute("name", Hex$(by) & ".png") Call denPic.AppendChild(den) |
ループ変数 x のループが終わると break ノードを追加しています。このノードは段落内での改行を表します。これで 2 回目のループ以降も行を変え左端から画像が配置されることになります。
Set den = vddn.CreateElementNode("break") Set denPic = vdenPar.AppendChild(den) |
生成される DXL
今回のサンプルで生成される DXLは次の通りです(リッチテキスト部分のみ抜粋し一部省略)。
段落 par の下にイメージリソースのノードが並びます。このような構造にすることで、イメージが連続して配置され、左から右に順に表示されます。また、1行分の出力が終わると break ノードが出力されています。これで次の行の画像を表示する準備をしているということですね。
実行結果
今回のサンプルと連載『ノーツで QR コード』のプログラムで出力した結果を比較してみました。課題だったセル間の隙間がなくなりずいぶん QR コードらしくなりました。また、サイズが小さくなったので、より大きな QR コードにも対応できそうですね。
ちなみに、今回はセルのサイズは 5 x 5 ピクセルの画像を使用しました。まだまだ小さくできる余地はありそうです...
前回 | DXL Step-by-Step | 次回 |
0 件のコメント:
コメントを投稿