﻿# 如何使用 .NET 的 QRCoder 套件產生 QRCode 圖片

[QRCoder](https://github.com/codebude/QRCoder/) 是一套 .NET 知名的 QRCode 產生器，從 .NET Framework 的年代就存在，支援多種 QRCode 輸出格式，並且可以輸出成 `Bitmap` 或 `PNG` 等圖片類型。不過我最近發現他的最新版 v1.4.3 在 .NET 6.0 出現了[一些問題](https://github.com/codebude/QRCoder/issues/361#issuecomment-992152570)，所以我在這裡紀錄一下正確的 QRCoder 使用方法。

![QRCode](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/f77188724dceb58fa6c4-fce94862-dd83-4697-a619-f2ab0652e50f.webp)

## 安裝 QRCoder 套件

無論你用 .NET Framework 或 .NET Core，都可以透過 NuGet 安裝 [QRCoder](https://www.nuget.org/packages/QRCoder) 套件，它支援[多目標架構](https://www.nuget.org/packages/QRCoder#dependencies-body-tab)，其中只有 `net6.0` 架構是 `No dependencies.` 的！

-   PMC (Package Manager Console)
    
    ```powershell
    Install-Package QRCoder
    ```
    
-   .NET CLI
    
    ```powershell
    dotnet add package QRCoder
    ```
    

雖然 `net6.0` 架構下是 `No dependencies.` (無相依套件) 的，但這個版本開始卻會導致有些早期常用的 `QRCode` 類別完全遺失，你在開發 .NET 6.0+ 的時候將會完全找不到該類別。詳細的原因可以從 [Base64QRCode does not exist in 1.4.3 · Issue #361 · codebude/QRCoder](https://github.com/codebude/QRCoder/issues/361#issuecomment-992152570) 這個議題中找到。

### 在 .NET Framework 使用 QRCoder

在 .NET Framework 中，你可以透過幾種不同的方式產生 QRCode 圖片：

1.  透過 `QRCodeHelper` 這個靜態類別提供的輔助方法來產生圖片
    
    ```csharp
    var url = "https://blog.miniasp.com";
    Bitmap image = QRCodeHelper.GetQRCode(url, 10, Color.Black, Color.White, QRCodeGenerator.ECCLevel.Q);
    ```
    
    > 上述魔幻數字 `10` 是每個**模組**的像素大小，這個數字越大，產生的 QR Code 圖片就越大。
    
2.  透過 `QRCodeGenerator`, `QRCodeData` 和 `QRCode` 這三個類別來產生圖片
    
    ```csharp
    Bitmap image = null;
    
    using (QRCodeGenerator qRCodeGenerator = new QRCodeGenerator())
    {
        using (QRCodeData data = qRCodeGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.Q))
        {
            using (QRCode qRCode = new QRCode(data))
            {
                image = qRCode.GetGraphic(10);
            }
        }
    };
    ```
    
    如果你想要變更 QRCode 圖片的顏色，可以透過 `QRCode` 類別的 `GetGraphic()` 方法來傳入 [Color](https://learn.microsoft.com/zh-tw/dotnet/api/system.drawing.color?view=net-7.0&WT.mc_id=DT-MVP-4015686) 結構：
    
    ```csharp
    Bitmap image = null;
    
    using (QRCodeGenerator qRCodeGenerator = new QRCodeGenerator())
    {
        using (QRCodeData data = qRCodeGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.Q))
        {
            using (QRCode qRCode = new QRCode(data))
            {
                image = qRCode.GetGraphic(10, Color.Green, Color.White, drawQuietZones: true);
            }
        }
    };
    ```
    

### 在 .NET 6.0+ 使用 QRCoder

由於 .NET 移除掉大多數 `System.Drawing` 命名空間中的類別，其中當然包含了 `Bitmap` 類別，也就是上述程式的 `GetGraphic()` 方法就無法使用了，甚至你連 `QRCode` 類別都找不到，如下圖示：

![image](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/063414ad01499803995e-6a8201ee-a747-4ca8-ae76-54a8ca49dba6.webp)

解決方法有兩種：

1.  改用 `PngByteQRCode` 類別來產生圖片
    
    ```csharp
    var url = "https://blog.miniasp.com";
    
    using QRCodeGenerator qRCodeGenerator = new QRCodeGenerator();
    using QRCodeData data = qRCodeGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.Q);
    using PngByteQRCode qRCode = new PngByteQRCode(data);
    byte[] image = qRCode.GetGraphic(10);
    ```
    
    如果你想要變更 QRCode 圖片的顏色，由於 .NET 可以透過 `qRCode.GetGraphic()` 類別的 `CreateQrCode()` 方法來指定，但指定的方法跟 .NET Framework 的寫法不太一樣，你不傳入 `Color` 型別，反而要輸入一個 `byte[]` 才行，其內容則為 `R`, `G`, `B` 三原色的色碼：
    
    ```csharp
    var url = "https://blog.miniasp.com";
    
    using QRCodeGenerator qRCodeGenerator = new QRCodeGenerator();
    using QRCodeData data = qRCodeGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.Q);
    using PngByteQRCode qRCode = new PngByteQRCode(data);
    byte[] image = qRCode.GetGraphic(10,
                      darkColorRgba: new byte[] { 0, 90, 0 }, // RGB
                      lightColorRgba: new byte[] { 255, 255, 255 }); // RGB
    ```
    
2.  改用 `PngByteQRCodeHelper` 這個靜態類別提供的輔助方法來產生圖片
    
    這邊與 .NET Framework 的用法最主要的差異，就是 `PngByteQRCodeHelper` 類別的 `GetQRCode()` 方法，回傳的型別是 `byte[]`，而不是 `Bitmap`：
    
    ```csharp
    var url = "https://blog.miniasp.com";
    byte[] image = PngByteQRCodeHelper.GetQRCode(url, QRCodeGenerator.ECCLevel.Q, 10);
    ```
    

### 什麼是 ECCLevel

ECC Level 是 Error Correction Code Level 的縮寫，中文意思是「錯誤更正等級」，這個等級越高，可以容許的錯誤越多！

這個容錯更正等級代表著 QR Code 圖片當有破損或變形時，QR Code 閱讀器可以容錯的程度，從 L (Lowest) 到 H (Highest) 共分成 4 種等級：

1.  ECC Level `L`: 此等級可以忍受 QR Code 圖片有最多 `7%` 的破損或變形 ( L = Lowest )
2.  ECC Level `M`: 此等級可以忍受 QR Code 圖片有最多 `15%` 的破損或變形 ( M = Medium )
3.  ECC Level `Q`: 此等級可以忍受 QR Code 圖片有最多 `25%` 的破損或變形 ( Q = Quarter )
4.  ECC Level `H`: 此等級可以忍受 QR Code 圖片有最多 `30%` 的破損或變形 ( H = Highest )

一般而言，大多數人都會選擇 `Q` 這個容錯等級，因為他可以容許 `25%` (1/4) 的錯誤，而且圖片大小也不會太大。

### 產生文字格式的 QRCode 圖片

如果你想在 Console 模式下輸出一份 QRCode，那就可以使用 `AsciiQRCodeHelper` 這個靜態類別提供的 `GetQRCode()` 輔助方法來產生文字格式的圖片，他的用法跟 `PngByteQRCodeHelper` 類似，只是他的回傳型別是 `string` 而已：

```csharp
string txt = AsciiQRCodeHelper.GetQRCode(url,
    pixelsPerModule: 1,
    darkColorString: "██",
    whiteSpaceString: "  ",
    eccLevel: QRCodeGenerator.ECCLevel.Q);
Console.WriteLine(txt);
```

> 這裡的 `darkColorString` 參數，要放入兩個 `U+2588` 字元 ([全滿的方塊](https://zh.wikipedia.org/wiki/%E6%96%B9%E5%A1%8A%E5%85%83%E7%B4%A0))，而 `whiteSpaceString` 參數，則是放入兩個空白字元，輸出顯示的時候要注意字型要選用等寬字體。

### 相關連結

-   [codebude/QRCoder](https://github.com/codebude/QRCoder): A pure C# Open Source QR Code implementation
-   [codebude/QRCoder Wiki](https://github.com/codebude/QRCoder/wiki)
    -   [Advanced usage QR Code renderers · codebude/QRCoder Wiki](https://github.com/codebude/QRCoder/wiki/Advanced-usage---QR-Code-renderers)
    -   [Advanced usage Payload generators](https://github.com/codebude/QRCoder/wiki/Advanced-usage---Payload-generators)
-   JavaScript Libraries
    -   [educastellano/qr-code](https://github.com/educastellano/qr-code): Web Component for generating QR codes
    -   [nimiq/qr-creator](https://github.com/nimiq/qr-creator): Lightweight library for stylish QR codes
