今回はビットマップの作成で一番重要な画像データを作成する関数 xBMP_MakePictureData を作成します。少し長い関数になりますので、ポイントとなる点を順にまとめます。最後に関数全体を掲載していますので、そちらを参照しながら読み進めてください。
関数の機能
この関数の機能は QR コードの論理データからビットマップファイルに設定する画像データブロックを作成することですが、データブロックのサイズ(バイト数)を事前に把握する役割もあります。前回 記載しましたが、ビットマップを出力する際に、画像データブロックより先に、ヘッダブロック出力が必要だったためです。
そこで関数のインターフェースは次のように定義します。
◇ 引数
| 1 | vabQR | Variant | QR コードの論理データ (Boolean 型の 2 次元配列) |
| 2 | ravBitMap | Variant | (戻り値)画像データ(Variant 型の配列) 1要素に1行分の画像データを保持 |
ravBitMap で渡される変数は、前回 紹介したメインルーチンで行数分の配列として宣言されていました。
|
ReDim avBitMap(UBound(vabQR, 2)) '保存エリア確保 Call xBMP_MakePictureData(vabQR, avBitMap) |
この変数の各要素に 1 行ごとの画像データを格納します。1行分の画像データは1行を構成する Byte 型配列とします。保持仕様を図式化すると次のようになります。
1行分のバイト数
白黒ビットマップの場合、横幅のピクセル数が必要なビット数となります。これをバイトに変換するのですが、エンコード仕様により、4 バイト単位に調整する必要がありました。
具体的には、以下の演算でバイト数を算出して、保存エリアを確保しています。
|
'初期化(1行分の保存に必要なエリアを確保) iByte = UBound(vabQR, 1) + 1 '画像の幅 iByte = (iByte + 7) \ 8 '必要なビット数(バイト単位) iByte = ((iByte + 3) \ 4) * 4 '1行は4バイト単位 ReDim abyLine(iByte - 1) |
1行分のデータ作成
ビットマップは画像の下から上にエンコードする仕様でした。これを実現しているのが以下の For ループで、Step が -1 となっています。
| For iY = UBound(vabQR, 2) To 0 Step -1 '行は下から上 |
ループ内ではまず、1 行分のワークエリアである abyLine を初期化しています。初期化で全要素をいったん 0 にしておき、必要な要素だけ値をセットしようという算段です。
| '1行分のワークエリアの初期化 iByte = 0 ReDim abyLine(UBound(abyLine)) '配列内初期化 |
コード内のコメントの ① の部分は、1 行分のQR コード論理データを順に処理しています。処理はサブルーチン SetBit で行い、8 ビット分たまったら、WriteByte サブルーチンでバイトに変換して、1 行分のワークエリアに格納しています。
画像の幅が 8 の倍数ではないとき、余ったビットを格納するために ② の処理を実行しています。
関数全体
最後に関数 xBMP_MakePictureData の全体を掲載します。
|
%REM QR コードの論理データ(Boolean 型の 2 次元配列)から画像データブロックを作成します。 ◆ 引数 vabQR Boolean QR コードの論理データ(Boolean 型の 2 次元配列) ravBitMap Variant 画像データ(配列の各要素は1行分の画像データ(Byte 配列)) %END REM Private Function xBMP_MakePictureData(vabQR As Variant, ravBitMap As Variant) As Boolean Dim iY As Integer Dim iX As Integer Dim iB As Integer 'ビットカウンタ Dim abBit() As Boolean '1バイト分を保存するワークエリア Dim bBit As Boolean Dim byByte As Byte Dim iByte As Integer '1行のバイト数(カウンタ) Dim abyLine() As Byte '1行分のワークエリア(バイト数分の配列) Dim iLine As Integer '初期化(1行分の保存に必要なエリアを確保) iByte = UBound(vabQR, 1) + 1 '画像の幅 iByte = (iByte + 7) \ 8 '必要なビット数(バイト単位) iByte = ((iByte + 3) \ 4) * 4 '1行は4バイト単位 ReDim abyLine(iByte - 1) '1行ずつ順に処理 iLine = 0 ReDim abBit(7) '1バイト分のビット格納エリアのリセット iB = 0 For iY = UBound(vabQR, 2) To 0 Step -1 '行は下から上 '1行分のワークエリアの初期化 iByte = 0 ReDim abyLine(UBound(abyLine)) '配列内初期化 '① 画像の出力(1ピクセル毎) For iX = 0 To UBound(vabQR, 1) bBit = vabQR(iX, iY) GoSub SetBit Next '② 1バイトに満たないビットがあればバイトに変換 If iB > 0 Then GoSub WriteByte '戻り値配列にセット ravBitMap(iLine) = abyLine iLine = iLine + 1 Next Exit Function SetBit: '1ビットを格納 abBit(iB) = bBit iB = iB + 1 '1バイト分たまったら格納 If iB = 8 Then GoSub WriteByte Return WriteByte: '1バイトを格納 byByte = 0 For iB = 0 To 7 If abBit(iB) = False Then '白黒反転 byByte = byByte + 2 ^ (7-iB) End If Next '1バイト書き込み abyLine(iByte) = byByte iByte = iByte + 1 '1バイト分のビット格納エリアのリセット ReDim abBit(7) iB = 0 Return End Function |
次回の予定
これでビットマップ作製に必要な情報がそろいました。次回は、バイナリファイルに出力する部分を作成します。
| 前回 | QR コードの作画 | 前回 |

















































