ZXing.Netを使用してC#でQRコードを作成する

　C#でQRコードを作成するにはZXing.Netを使うと良いらしい。ただ、軽くググった感じではバージョン0.16.6以前のサンプルが多く、0.16.7以降(最新の0.16.9を含む)ではコンパイルができなかったので、新しい書き方のサンプルのメモ。
　新しいバージョンではBitmap以外にSVGの出力がサポートされ、それによって互換性が破壊されている。

## SVG

```C#
BarcodeWriter<SvgRenderer.SvgImage> qr = new()
{
    Format = BarcodeFormat.QR_CODE,
    Options = new QrCodeEncodingOptions
    {
        ErrorCorrection = ErrorCorrectionLevel.H,
        CharacterSet = "UTF-8",
        Width = 512,
        Height = 512,
    },
    Renderer = new SvgRenderer(),
};

File.WriteAllText("log.svg", qr.Write("hello world").Content);
```

　レンダリングの結果はstringで得られるので、File.WriteAllTextでファイルに書き出している。適当なSVGビューア(Webブラウザとか)で開けばQRコードを確認できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264452/1fee89ce-0a30-a3c2-5069-dda0256ddf90.png)

## Bitmap

```C#
BarcodeWriter<PixelData> qr = new()
{
    Format = BarcodeFormat.QR_CODE,
    Options = new QrCodeEncodingOptions
    {
        ErrorCorrection = ErrorCorrectionLevel.H,
        CharacterSet = "UTF-8",
        Width = 512,
        Height = 512,

    },
    Renderer = new PixelDataRenderer()
};

var pixelData = qr.Write("hello world");

using var bmp = ConvertToBitmapFrom32bppArgb(
    pixelData.Width, pixelData.Height, pixelData.Pixels);

bmp.Save("log.png");

static Bitmap ConvertToBitmapFrom32bppArgb(int width, int height, byte[] data)
{
    if (width * height * 4 != data.Length) { throw new ArgumentException(); }

    var gcHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
    try
    {
        return new(
            width, height, width * 4,
            PixelFormat.Format32bppArgb,
            gcHandle.AddrOfPinnedObject());
    }
    finally
    {
        gcHandle.Free();
    }
}
```

　ピクセルデータで出力する場合、ARGBの生データで出力されるので、Bitmapのインスタンスを作成して画像ファイルとして保存している。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264452/78b352ef-ea69-9f6a-486f-daa51dc65025.png)

## その他

### 色

　コードの色を変えたい場合はRendererのオプションで指定する。

```C#
Renderer = new PixelDataRenderer
{
    Foreground = new(Color.Black.ToArgb()),
    Background = new(Color.White.ToArgb()),
},
```

　色は独自の構造体(A, R, G, Bをbyteで保持)で管理しているので、コンストラクタでSystem.Drawing.Color.ToArgb()を渡すと楽。

## 自分でレンダーを作る

　0.16.7以降はレンダーをオプションに与える形式になったので、この部分を自作すれば色々加工できる。

　例えば

```C#
class MyRender : IBarcodeRenderer<string>
{
    public string Render(BitMatrix matrix, BarcodeFormat format, string content)
        => throw new NotImplementedException();

    public string Render(BitMatrix matrix, BarcodeFormat format, string content, EncodingOptions options)
    {
        StringBuilder sb = new();

        for (int y = 0; y < matrix.Height; y++)
        {
            for (int x = 0; x < matrix.Width; x++)
            {
                sb.Append(matrix[x, y] ? "●" : "□");
            }
            sb.AppendLine();
        }

        return sb.ToString();
    }
}
```

　のようなレンダーを作り

```C#
BarcodeWriter<string> qr = new()
{
    Format = BarcodeFormat.QR_CODE,
    Options = new QrCodeEncodingOptions
    {
        ErrorCorrection = ErrorCorrectionLevel.H,
        CharacterSet = "UTF-8",
    },
    Renderer = new MyRender(),
};

File.WriteAllText("log.txt", qr.Write("hello world"));
```

　のように使えば

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264452/eb54306a-9509-d598-d486-4520913b8536.png)

　というような結果が得られる。

　BitMatrixはある点の色をboolで得られるから、好きに加工すれば自由にQRコードを作成できる(正しく読めるQRコードかは各自の責任)。