[C言語] QRコードエンコードをしてみる

# はじめに
今回QRコードをC言語でも扱ってみたいと考え様々なライブラリを探してきたが、便利なライブラリを見つけるのにくろうしたため、ここに記載をしていきたいと思う。

他のライブラリでは、openCVなどで画像まで作成してくれるが、今回は画像は作成しないで、自分で表示の処理をするところも記載していきたいと考える

![スクリーンショット 2022-07-24 23.54.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209385/fcb95e89-7006-0cc1-e303-3acf0cb6a204.png)


# 使用ライブラリ
今回ProjectNAYUKI様のQRコードエンコードライブラリを用いて開発をおこないました

https://www.nayuki.io/page/qr-code-generator-library#c


# ソースコード

出力方法としてはqr0をライブラリの関数に入れてFor文を回すことによって表示をすることができる。

```c:qrencode.c

#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "qrcodegen.h"

//文字を設置する関数
void putWhite(){
    printf("\x1b[47m");     /* 背景色を白色に */
    printf("　");
    printf("\x1b[49m");     /* 背景色をデフォルトに戻す */
}

void putBlack(){
    printf("\x1b[40m");     /* 背景色を黒色に */
    printf("　");
    printf("\x1b[49m");     /* 背景色をデフォルトに戻す */
}

int main()
{
    //QRコード化する文字列を入力
    char str[1024];
    printf("\n> QRコード化したい文字を入力してください\n");
    scanf("%s", str);

    //QRコードの作成
    uint8_t qr0[qrcodegen_BUFFER_LEN_MAX];
    uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
    //第一引数に変換したい文字列を入れることによって配列を返すことができる
    //ｑｒ0によってデータを返してくれる。
    bool ok = qrcodegen_encodeText(str,
                                    tempBuffer, qr0, qrcodegen_Ecc_MEDIUM,
                                    qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX,
                                    qrcodegen_Mask_AUTO, true);
    if (!ok)
        return 0;



    //QRコードの大きさを取得
    int size = qrcodegen_getSize(qr0);

    //実際の出力の部分
    for (int y = 0; y < size; y++){

        for (int x = 0; x < size; x++){
            if (qrcodegen_getModule(qr0, x, y)){
					putBlack();
			}else{
					putWhite();
			}

        }
        printf("\n");
    }
   
}
```




# 使用方法
今回細かい調査は行っていないが、こうすればQRコードかした配列を取得できたという方法をまとめる。

### ファイル構造
ファイル構造として、今回はこのような形になっている。
- Makefile 
- 出力されたバイナリデータ
- 実際に書いたコード
- QRコードのライブラリ
- QRコードのライブラリのヘッダファイル
![スクリーンショット 2022-07-24 23.29.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209385/b52f5b63-9813-1461-5825-76f5d50d3c51.png)


### エンコード方法
```c:qrencode.c
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "qrcodegen.h"



int main()
{
    //QRコード化する文字列を入力
    char str[1024];
    printf("\n> QRコード化したい文字を入力してください\n");
    scanf("%s", str);

    //QRコードの作成
    uint8_t qr0[qrcodegen_BUFFER_LEN_MAX];
    uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
    //第一引数に変換したい文字列を入れることによって配列を返すことができる
    //ｑｒ0によってデータを返してくれる。
    bool ok = qrcodegen_encodeText(str,
                                    tempBuffer, qr0, qrcodegen_Ecc_MEDIUM,
                                    qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX,
                                    qrcodegen_Mask_AUTO, true);
    if (!ok)
        return 0;

   
}
```

### 出力方法
今回は文字列で "□" と "■" を表示する方法を使わないでコンソールの背景色を直接触ることによって作成することにした。
そうしないとうまくQRコードを表示できないためである。

### コンソールの背景色を表示方法
```c:consoleColer.c
#include <stdio.h>

//文字を設置する関数
void putWhite(){
    printf("\x1b[47m");     /* 背景色を白色に */
    printf("　");
    printf("\x1b[49m");     /* 背景色をデフォルトに戻す */
}

void putBlack(){
    printf("\x1b[40m");     /* 背景色を黒色に */
    printf("　");
    printf("\x1b[49m");     /* 背景色をデフォルトに戻す */
}

int main(){
    putWhite();
    printf("\n");

    putBlack();
    printf("\n");
}

```
出力結果としてはこのようなイメージになる
![スクリーンショット 2022-07-24 23.43.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209385/7a1c8f58-9cac-09c4-6785-1e1b86c5df8e.png)

より詳しい内容は下記URLよりご確認ください

https://www.serendip.ws/archives/4635

### コンパイル方法
今回はライブラリを用いて開発をしているため、一緒にライブラリもコンパイルする必要があるため、gccの記述を変える必要がある。

```:コマンドライン
> gcc qrencode.c qrcodegen.c
```
こうしないとうまくコンパイルされないで、関数が読み取れないエラーが発生してします。

また、いちいちこのような記載をするのはめんどくさいため、makefileを作成することとする

```makefile:Makefile
CC=gcc
CFLAGS=-O

myqrencode: myqrencode.c
	$(CC) $(CFLAGS) -o myqrencode myqrencode.c qrcodegen.c -lncurses
```

こうすることによって、
```:コマンドライン
> make
```
とするだけでコンパイルができてしまうのである。
とても便利なため、ぜひ使ってみてほしい。

### 出力部分
出力する方法としては、[qrcodegen_getModule(qr0, x, y)]にxとy座標を与えると、その場所を黒に表示するか0,1で返されるので、あとはforとifを用いて表示をしていく

```c:ｑrencode.c
//QRコードの大きさを取得
    int size = qrcodegen_getSize(qr0);

    for (int y = 0; y < size; y++){

        for (int x = 0; x < size; x++){
            if (qrcodegen_getModule(qr0, x, y)){
					putBlack();
			}else{
					putWhite();
			}

        }
        printf("\n");
    }
```

# リリースについて
今回簡単にbrweにて配信をしたのでぜひダウンロードしてみてください。

```
> brew tap harutiro/myqrencode
> brew install myqrencode
> myqrencode
```

brewの公開方法をまとめたのでもしよければ見てみてください

https://zenn.dev/harutiro/articles/bf66acd8fabf63

# Github

https://github.com/harutiro/myqrencode

# 参考文献

## QRコード関係
https://www.nayuki.io/page/qr-code-generator-library#c

https://fukuchi.org/works/qrencode/manual/index.html

https://blog.emattsan.org/entry/20160505/1462453473

## コンソールの色について

https://www.serendip.ws/archives/4635