LoginSignup
11
12

More than 1 year has passed since last update.

ライブラリを使わずにC#でQRコードを生成してみる

Last updated at Posted at 2021-08-20

はじめに

「QRコードを手計算&手書きで書けたらかっこいいのでは?」と思い立ち、QRコードの仕組みを勉強しました。
しかしその仕組みは想定の1億倍難しく、到底手計算できるものではありませんでした。
ではせめて…ということで、ライブラリに頼りがちなQRコード生成を1から自分でやってみることにしました。

前提

C#のコンソールで入出力を行います。
QR バージョン1、エラー訂正レベルはH、英数字モード、マスクパターンは011で固定とします。
 バージョン1、エラー訂正レベルHの場合はデータコード数9、エラー訂正コード数17です。
 バージョン1では21×21マス。下のような構造になっています。数字はビット番号を示します。
スクリーンショット 2021-08-20 121011.png

生成の流れ

データ領域に入れるデータの作成
データをコンソールで入力
データコード語の作成
誤り訂正コード語の作成
QRコード配列の作成
固定領域
データ領域
マスク処理
形式情報
コンソールで出力

コード全体
QR.cs
using System;
using System.Collections.Generic;

namespace QRCodeMaker
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("データを英数字で入力して!");
            var input = Console.ReadLine();
            var QRCode = new QRCode(input);
        }
    }

    class QRCode
    {
        public QRCode(string input)
        {
            //モード指示子 英数字固定
            string modeIndicator = "0010";
            //文字数指示子
            string lenIndicator = Convert.ToString((input.Length), 2);
            while (lenIndicator.Length < 9) { lenIndicator = "0" + lenIndicator; }
            //データ
            string data = "";
            for (int i = 0; i <= (input.Length - 1) / 2; i++)
            {
                int H, L, deciInt;
                string deciStr = "";
                if (i * 2 + 1 < input.Length)
                {
                    H = (int)input[i * 2];
                    L = (int)input[i * 2 + 1];
                    deciInt = AscTo45(H) * 45 + AscTo45(L);
                    deciStr = Convert.ToString((deciInt), 2);
                    while (deciStr.Length < 11) { deciStr = "0" + deciStr; }
                }
                else
                {
                    L = input[i * 2];
                    deciInt = AscTo45(L);
                    deciStr = Convert.ToString((deciInt), 2);
                    while (deciStr.Length < 6) { deciStr = "0" + deciStr; }
                }
                data += deciStr;
            }
            //終端パターン
            string terminator = "0000";

            string dataraw = modeIndicator + lenIndicator + data + terminator;
            List<int> dataList = new List<int>();
            while (dataraw.Length >= 8)
            {
                string codeLang = dataraw.Substring(0, 8);
                dataList.Add(Convert.ToInt32(codeLang, 2));
                dataraw = dataraw.Substring(8);
            }
            if (dataraw.Length > 0)
            {
                while (dataraw.Length < 8) { dataraw += "0"; }
                string codeLang = dataraw.Substring(0, 8);
                dataList.Add(Convert.ToInt32(codeLang, 2));
            }
            while (dataList.Count < 9)
            {
                bool addflg = true;
                if (addflg) { dataList.Add(236); }
                else { dataList.Add(17); }
                addflg = !addflg;
            }

            //リードソロモン誤り訂正方式で誤り訂正コード語作成
            List<int> exponent = new List<int>() { 1 };
            List<int> integer = new List<int>() { 0 };
            for (int i = 0; i < 255; i++)
            {
                exponent.Add(exponent[i] * 2);
                if (exponent[i + 1] >= 256)
                {
                    exponent[i + 1] = exponent[i + 1] - 256;
                    exponent[i + 1] = exponent[i + 1] ^ 29;
                }
                integer.Add(0);
            }
            for (int i = 0; i <= 255; i++)
            {
                for (int j = 0; j < 255; j++)
                    if (exponent[j] == i) { integer[i] = j; }
            }

            List<int> fx = new List<int>() { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
            for (int i = 8; i >= 0; i--) { fx.Add(dataList[i]); }
            List<int> gx = new List<int>() { 79, 99, 125, 53, 85, 134, 143, 41, 249, 83, 197, 22, 119, 120, 83, 66, 119, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
            while (GetMaxDegree(fx) >= 17)
            {
                int DeltaDegree = GetMaxDegree(fx) - GetMaxDegree(gx);
                List<int> gxBuf = new List<int>() { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
                for (int i = 0; i <= 17; i++) { gxBuf[i + DeltaDegree] = gx[i]; }

                int DeltaAlpha = integer[fx[GetMaxDegree(fx)]];
                for (int i = 0; i <= 25; i++)
                {
                    int gxInt = gxBuf[i];
                    if (gxInt == 0) { gxBuf[i] = 0; }
                    else
                    {
                        int gxAlpha = integer[gxInt];
                        gxAlpha += DeltaAlpha;
                        if (gxAlpha > 255) { gxAlpha -= 255; }
                        gxBuf[i] = exponent[gxAlpha];
                    }
                }
                for (int i = 0; i <= 25; i++) { fx[i] = fx[i] ^ gxBuf[i]; }
            }

            for (int i = 16; i >= 0; i--) { dataList.Add(fx[i]); }
            string dataWithErrorStr = "";
            for (int i = 0; i <= 25; i++)
            {
                int num = dataList[i];
                string str = Convert.ToString(num, 2);
                while (str.Length < 8) { str = "0" + str; }
                dataWithErrorStr += str;
            }



            //QRコード生成
            int QRsize = 21;
            int[,] bitAry = new int[QRsize, QRsize];

            //初期化
            for (int i = 0; i < QRsize; ++i)
            {
                for (int j = 0; j < QRsize; ++j)
                {
                    bitAry[i,j] = 0;
                }
            }

            //タイミングパターン
            for (int i = 0; i < QRsize; ++i)
            {
                if(i % 2 ==0)
                {
                    bitAry[i, 6] = 1;
                    bitAry[6, i] = 1;
                } 
            }
            bitAry[13, 8] = 1;

            //位置検出パターン
            int startrow, startcol;
            startrow=0;
            startcol=0;
            for (int i = 0; i <= 6; ++i)
            {
                for (int j = 0; j <= 6; ++j)
                {                    
                    if ((i == 0) || (j == 0) || (i == 6) || (j == 6)) { bitAry[startrow + i, startcol + j] = 1; }
                    if ((i != 1) && (j != 1) && (i != 5) && (j != 5)) { bitAry[startrow + i, startcol + j] = 1; }
                }
            }
            startrow = 0;
            startcol = 14;
            for (int i = 0; i <= 6; ++i)
            {
                for (int j = 0; j <= 6; ++j)
                {
                    if ((i == 0) || (j == 0) || (i == 6) || (j == 6)) { bitAry[startrow + i, startcol + j] = 1; }
                    if ((i != 1) && (j != 1) && (i != 5) && (j != 5)) { bitAry[startrow + i, startcol + j] = 1; }
                }
            }
            startrow = 14;
            startcol = 0;
            for (int i = 0; i <= 6; ++i)
            {
                for (int j = 0; j <= 6; ++j)
                {
                    if ((i == 0) || (j == 0) || (i == 6) || (j == 6)) { bitAry[startrow + i, startcol + j] = 1; }
                    if ((i != 1) && (j != 1) && (i != 5) && (j != 5)) { bitAry[startrow + i, startcol + j] = 1; }
                }
            }

            //データを埋めていく
            int row = QRsize-1;
            int col = QRsize-1;
            bool UpFlag = true;
            for (int i = 0; i <= 103; ++i)
            {
                bitAry[row, col] = (int)Char.GetNumericValue(dataWithErrorStr[i*2]);
                bitAry[row, col-1] = (int)Char.GetNumericValue(dataWithErrorStr[i*2+1]);

                if (UpFlag)
                {
                    if (IsDataArea(row - 1, col)){row += -1;}
                    else
                    {
                        if (IsTimingArea(row - 1, col)){row += -2;}
                        else
                        {
                            col += -2;
                            UpFlag = !UpFlag;
                            if (IsTimingArea(row, col)) { col += -1;}
                        }
                    }
                }
                else
                {
                    if (IsDataArea(row + 1, col)){row += 1;}
                    else
                    {
                        if (IsTimingArea(row + 1, col)){row += 2;}
                        else
                        {
                            col += -2;
                            UpFlag = !UpFlag;
                            if (IsTimingArea(row, col)){col += -1;}
                            else
                            {
                                if (IsFormatArea(row, col)){row += -8;}
                            }

                        }
                    }
                }
            }

            //マスク処理
            for (int i = 0; i <= 20; ++i)
            {
                for (int j = 0; j <= 20; ++j)
                {
                    if ((IsDataArea(i,j))&& ((i + j) % 3 == 0))
                    {
                        if(bitAry[i, j] == 1)
                        {
                            bitAry[i, j] = 0;
                        }
                        else
                        {
                            bitAry[i, j] = 1;
                        }
                    }
                }
            }

            //string formatStr = "001100111010000";
            string formatStr = "000010111001100";
            int index = 0;
            int Celindex = 0;
            while (index < 15)
            {
                bitAry[Celindex, 8] = (int)Char.GetNumericValue(formatStr[index]);
                Celindex += 1;
                while (!IsFormatArea(Celindex, 8)){ Celindex += 1;}
                index += 1;
            }

            index = 0;
            Celindex = 20;
            while (index < 15)
            {
                bitAry[8,Celindex] = (int)Char.GetNumericValue(formatStr[index]);
                Celindex += -1;
                while (!IsFormatArea(8, Celindex))
                {
                    Celindex += -1;
                }
                if (Celindex==8) { Celindex += -1; }
                index += 1;
            }

            //コンソールでQRコード出力
            Console.WriteLine("");
            Console.WriteLine("");
            Console.Write("  ");
            for (int i = 0; i < QRsize; ++i)
            {for (int j = 0; j < QRsize; ++j)
                {
                    if (bitAry[i, j] == 1){Console.Write("■");}
                    else{Console.Write(" ");}
                }
                Console.WriteLine("");
                Console.Write("  ");
            }
            Console.ReadKey();
        }
        Boolean IsPositionArea(int i, int j)
        {
            if ((i - 0 <= 7) && (j - 0 <= 7)){ return true; }
            if((i - 0 <= 7) && (j - 13 <= 7) && (j >= 13)) { return true; }
            if((j - 0 <= 7) && (i - 13 <= 7) && (i >= 13)) { return true; }
            return false;
        }
        Boolean IsTimingArea(int i, int j)
        {
            if ((i ==6)|| (j == 6)) { return true; }
            if ((i == 13) && (j == 8)) { return true; }
            return false;
        }
        Boolean IsFormatArea(int i, int j)
        {
            if ((i == 8) && ((j < 6) || (j == 7)||(j == 8) || (j > 12))) { return true; }
            if ((j == 8) && ((i < 6) || (i == 7) || (i == 8) || (i > 13))) { return true; }
            return false;
        }
        Boolean IsDataArea(int i, int j)
        {
            if (IsPositionArea(i,j)) { return false; }
            if (IsTimingArea(i, j)) { return false; }
            if (IsFormatArea(i, j)) { return false; }
            if((i > 20) || (j > 20)) { return false; }
            if ((i < 0) || (j < 0)) { return false; }
            return true;
        }

        int GetMaxDegree(List<int> function)
        {
            for (int i = 25; i >= 0; i--) { if (function[i] > 0) { return i; } }
            return 0;
        }
        int AscTo45(int asc)
        {
            if((asc >=48)&&(asc <= 57)){ return asc - 48; }
            if ((asc >= 65) && (asc <= 90)) { return asc - 65 + 10; }
            if ((asc >= 97) && (asc <= 122)) { return asc - 97 + 10; }
            if (asc == 32) { return 36; }
            if (asc == 36) { return 37; }
            if (asc == 37) { return 38; }
            if (asc == 42) { return 39; }
            if (asc == 43) { return 40; }
            if (asc == 45) { return 41; }
            if (asc == 46) { return 42; }
            if (asc == 47) { return 43; }
            if (asc == 58) { return 45; }
            return 0;
        }
    }
}

データ領域に入れるデータの作成

データをコンソールで入力

QR.cs
class Program
{
   static void Main(string[] args)
   {
       Console.WriteLine("データを英数字で入力して!");
       var input = Console.ReadLine();
       var QRCode = new QRCode(input);
   }
}

データコード語の作成

モード指示子:4bit 英数字なら”0010”
文字数指示子:英数字なら文字数を9bitで表記。
データ:入力データを2文字ごとに区切り、区切ったデータを45進法表記とみなして2進数へ変換。
 2文字なら11bit,1文字なら6bitとする。
終端パターン:"0000"

これらを連結してから1バイト(8bit)ごとに分ける。最後のbit列が8bit未満なら0で埋める。
データが9バイト未満であれば、"11101100" と "00010001"を交互に追加する。

QR.cs
    class QRCode
    {
        public QRCode(string input)
        {
            //モード指示子 英数字固定
            string modeIndicator = "0010";
            //文字数指示子
            string lenIndicator = Convert.ToString((input.Length), 2);
            while (lenIndicator.Length < 9) { lenIndicator = "0" + lenIndicator; }
            //データ
            string data = "";
            for (int i = 0; i <= (input.Length - 1) / 2; i++)
            {
                int H, L, deciInt;
                string deciStr = "";
                if (i * 2 + 1 < input.Length)
                {
                    H = (int)input[i * 2];
                    L = (int)input[i * 2 + 1];
                    deciInt = AscTo45(H) * 45 + AscTo45(L);
                    deciStr = Convert.ToString((deciInt), 2);
                    while (deciStr.Length < 11) { deciStr = "0" + deciStr; }
                }
                else
                {
                    L = input[i * 2];
                    deciInt = AscTo45(L);
                    deciStr = Convert.ToString((deciInt), 2);
                    while (deciStr.Length < 6) { deciStr = "0" + deciStr; }
                }
                data += deciStr;
            }
            //終端パターン
            string terminator = "0000";

            string dataraw = modeIndicator + lenIndicator + data + terminator;
            List<int> dataList = new List<int>();
            while (dataraw.Length >= 8)
            {
                string codeLang = dataraw.Substring(0, 8);
                dataList.Add(Convert.ToInt32(codeLang, 2));
                dataraw = dataraw.Substring(8);
            }
            if (dataraw.Length > 0)
            {
                while (dataraw.Length < 8) { dataraw += "0"; }
                string codeLang = dataraw.Substring(0, 8);
                dataList.Add(Convert.ToInt32(codeLang, 2));
            }
            while (dataList.Count < 9)
            {
                bool addflg = true;
                if (addflg) { dataList.Add(236); }
                else { dataList.Add(17); }
                addflg = !addflg;
            }
           //…
     }
}
QR.cs
        int AscTo45(int asc)
        {
            if((asc >=48)&&(asc <= 57)){ return asc - 48; }
            if ((asc >= 65) && (asc <= 90)) { return asc - 65 + 10; }
            if ((asc >= 97) && (asc <= 122)) { return asc - 97 + 10; }
            if (asc == 32) { return 36; }
            if (asc == 36) { return 37; }
            if (asc == 37) { return 38; }
            if (asc == 42) { return 39; }
            if (asc == 43) { return 40; }
            if (asc == 45) { return 41; }
            if (asc == 46) { return 42; }
            if (asc == 47) { return 43; }
            if (asc == 58) { return 45; }
            return 0;
        }

誤り訂正コード語の作成

リードソロモン誤り訂正方式で作成します。

まず下準備としてガロア体GF(2^8)上の元の集まりとそのインデックス表を作成します。
なんのこっちゃオブ・ザ・イヤーですが許してください。

QR.cs
List<int> exponent = new List<int>() { 1 };
List<int> integer = new List<int>() { 0 };
for (int i = 0; i < 255; i++)
{
        exponent.Add(exponent[i] * 2);
        if (exponent[i + 1] >= 256)
        {
            exponent[i + 1] = exponent[i + 1] - 256;
            exponent[i + 1] = exponent[i + 1] ^ 29;
        }
        integer.Add(0);
}
for (int i = 0; i <= 255; i++)
{
         for (int j = 0; j < 255; j++)
         {
            if (exponent[j] == i) { integer[i] = j; }
         }
}

データコードから作った多項式f(x)を生成多項式g(x)で割った余りの多項式の係数が誤り訂正コード語になります。

QR.cs
List<int> fx = new List<int>() { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
for (int i = 8; i >= 0; i--) { fx.Add(dataList[i]); }
List<int> gx = new List<int>() { 79, 99, 125, 53, 85, 134, 143, 41, 249, 83, 197, 22, 119, 120, 83, 66, 119, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
while (GetMaxDegree(fx) >= 17)
{
        int DeltaDegree = GetMaxDegree(fx) - GetMaxDegree(gx);
        List<int> gxBuf = new List<int>() { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        for (int i = 0; i <= 17; i++) { gxBuf[i + DeltaDegree] = gx[i]; }
        int DeltaAlpha = integer[fx[GetMaxDegree(fx)]];
        for (int i = 0; i <= 25; i++)
        {
            int gxInt = gxBuf[i];
            if (gxInt == 0) { gxBuf[i] = 0; }
            else
            {
                int gxAlpha = integer[gxInt];
                gxAlpha += DeltaAlpha;
                if (gxAlpha > 255) { gxAlpha -= 255; }
                gxBuf[i] = exponent[gxAlpha];
            }
         }
         for (int i = 0; i <= 25; i++) { fx[i] = fx[i] ^ gxBuf[i]; }
}

for (int i = 16; i >= 0; i--) { dataList.Add(fx[i]); }
string dataWithErrorStr = "";
for (int i = 0; i <= 25; i++)
{
       int num = dataList[i];
       string str = Convert.ToString(num, 2);
       while (str.Length < 8) { str = "0" + str; }
       dataWithErrorStr += str;
}
QR.cs
//多項式の最高次を求める
int GetMaxDegree(List<int> function)
{
    for (int i = 25; i >= 0; i--) { if (function[i] > 0) { return i; } }
    return 0;
}

QRコード配列の作成

データは揃ったので、いよいよQRコード配列を埋めていきます。

固定領域

スマートに埋めていく方法が思いつかなかったので、地道にごりごり埋めていきます。

QR.cs
            int QRsize = 21;
            int[,] bitAry = new int[QRsize, QRsize];

            //初期化
            for (int i = 0; i < QRsize; ++i)
            {
                for (int j = 0; j < QRsize; ++j)
                {
                    bitAry[i,j] = 0;
                }
            }

            //タイミングパターン
            for (int i = 0; i < QRsize; ++i)
            {
                if(i % 2 ==0)
                {
                    bitAry[i, 6] = 1;
                    bitAry[6, i] = 1;
                } 
            }
            bitAry[13, 8] = 1;

            //位置検出パターン
            int startrow, startcol;
            startrow=0;
            startcol=0;
            for (int i = 0; i <= 6; ++i)
            {
                for (int j = 0; j <= 6; ++j)
                {                    
                    if ((i == 0) || (j == 0) || (i == 6) || (j == 6)) { bitAry[startrow + i, startcol + j] = 1; }
                    if ((i != 1) && (j != 1) && (i != 5) && (j != 5)) { bitAry[startrow + i, startcol + j] = 1; }
                }
            }
            startrow = 0;
            startcol = 14;
            for (int i = 0; i <= 6; ++i)
            {
                for (int j = 0; j <= 6; ++j)
                {
                    if ((i == 0) || (j == 0) || (i == 6) || (j == 6)) { bitAry[startrow + i, startcol + j] = 1; }
                    if ((i != 1) && (j != 1) && (i != 5) && (j != 5)) { bitAry[startrow + i, startcol + j] = 1; }
                }
            }
            startrow = 14;
            startcol = 0;
            for (int i = 0; i <= 6; ++i)
            {
                for (int j = 0; j <= 6; ++j)
                {
                    if ((i == 0) || (j == 0) || (i == 6) || (j == 6)) { bitAry[startrow + i, startcol + j] = 1; }
                    if ((i != 1) && (j != 1) && (i != 5) && (j != 5)) { bitAry[startrow + i, startcol + j] = 1; }
                }
            }

データ領域

データコード語と誤り訂正コード語をあわせたものを2進数文字列で用意していました。
これをQRの右下端から上方向に埋めていきます。
 左右隣り合う2マスを右→左の順番で埋めます。
  上が空いていたら上に移動し、同様に右→左の2マスを埋めます。
  上が空いていなかったら左の2列に移動して、次は下方向に移動していきます。 

QR.cs
            int row = QRsize-1;
            int col = QRsize-1;
            bool UpFlag = true;
            for (int i = 0; i <= 103; ++i)
            {
                bitAry[row, col] = (int)Char.GetNumericValue(dataWithErrorStr[i*2]);
                bitAry[row, col-1] = (int)Char.GetNumericValue(dataWithErrorStr[i*2+1]);
                if (UpFlag)
                {
                    if (IsDataArea(row - 1, col)){row += -1;}
                    else
                    {
                        if (IsTimingArea(row - 1, col)){row += -2;}
                        else
                        {
                            col += -2;
                            UpFlag = !UpFlag;
                            if (IsTimingArea(row, col)) { col += -1;}
                        }
                    }
                }
                else
                {
                    if (IsDataArea(row + 1, col)){row += 1;}
                    else
                    {
                        if (IsTimingArea(row + 1, col)){row += 2;}
                        else
                        {
                            col += -2;
                            UpFlag = !UpFlag;
                            if (IsTimingArea(row, col)){col += -1;}
                            else
                            {
                                if (IsFormatArea(row, col)){row += -8;}
                            }
                        }
                    }
                }
            }

指定したマスの役割を判定します。

QR.cs
        Boolean IsPositionArea(int i, int j)
        {
            if ((i - 0 <= 7) && (j - 0 <= 7)){ return true; }
            if((i - 0 <= 7) && (j - 13 <= 7) && (j >= 13)) { return true; }
            if((j - 0 <= 7) && (i - 13 <= 7) && (i >= 13)) { return true; }
            return false;
        }
        Boolean IsTimingArea(int i, int j)
        {
            if ((i ==6)|| (j == 6)) { return true; }
            if ((i == 13) && (j == 8)) { return true; }
            return false;
        }
        Boolean IsFormatArea(int i, int j)
        {
            if ((i == 8) && ((j < 6) || (j == 7)||(j == 8) || (j > 12))) { return true; }
            if ((j == 8) && ((i < 6) || (i == 7) || (i == 8) || (i > 13))) { return true; }
            return false;
        }
        Boolean IsDataArea(int i, int j)
        {
            if (IsPositionArea(i,j)) { return false; }
            if (IsTimingArea(i, j)) { return false; }
            if (IsFormatArea(i, j)) { return false; }
            if((i > 20) || (j > 20)) { return false; }
            if ((i < 0) || (j < 0)) { return false; }
            return true;
        }

マスク処理

データ領域のみ、マスをあるルールでビット反転させます。
本当は、数種類あるマスクから評価を行い、もっとも効果が高いものを選定するのですが、今回は固定にします。

QR.cs
            for (int i = 0; i <= 20; ++i)
            {
                for (int j = 0; j <= 20; ++j)
                {
                    if ((IsDataArea(i,j))&& ((i + j) % 3 == 0))
                    {
                        if(bitAry[i, j] == 1)
                        {
                            bitAry[i, j] = 0;
                        }
                        else
                        {
                            bitAry[i, j] = 1;
                        }
                    }
                }
            }

形式情報

QR.cs
string formatStr = "000010111001100";
            int index = 0;
            int Celindex = 0;
            while (index < 15)
            {
                bitAry[Celindex, 8] = (int)Char.GetNumericValue(formatStr[index]);
                Celindex += 1;
                while (!IsFormatArea(Celindex, 8)){ Celindex += 1;}
                index += 1;
            }

            index = 0;
            Celindex = 20;
            while (index < 15)
            {
                bitAry[8,Celindex] = (int)Char.GetNumericValue(formatStr[index]);
                Celindex += -1;
                while (!IsFormatArea(8, Celindex))
                {
                    Celindex += -1;
                }
                if (Celindex==8) { Celindex += -1; }
                index += 1;
            }

コンソールで出力

今回はコンソールでQRを表示します。

QR.cs
            Console.WriteLine("");
            Console.WriteLine("");
            Console.Write("  ");
            for (int i = 0; i < QRsize; ++i)
            {for (int j = 0; j < QRsize; ++j)
                {
                    if (bitAry[i, j] == 1){Console.Write("■");}
                    else{Console.Write(" ");}
                }
                Console.WriteLine("");
                Console.Write("  ");
            }
            Console.ReadKey();

出力結果

試しに「QR CODE」と打ってみました。
スクリーンショット 2021-08-20 153451.png

参考にしたサイト

Wikipedia QR code
独極 QRコードを極める
QRコードをつくってみる
特集:あなたも描ける! JIS X0510準拠 QRコード®超入門
拡大体をPythonで実装する

おわりに

Qiita初投稿でした。プログラムも文章ももっとスマートに書けるように精進します。

11
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
12