LoginSignup
3
2

UnityでC#だけでQRを読み込む

Last updated at Posted at 2023-12-19

前書き

この記事は、2023のUnityアドカレの12/20の記事です。
今年は、完走賞に挑戦してみたいと思います。Qiita君ぬい欲しい!

TL;DR;

PackageManagerで↓これをインストール

https://github.com/wallstudio/UniQRCode.git?path=QRCodeSource/QRCodeDecoder/QRCodeDecoderLibrary
Texture texture = ...;
string text = await UniQRDecoder.Decode(texture);
Debug.Log(text);

はじめに

端末間でデータの転送をする手段は山ほどありますが、QRコードは、コネクションに必要な情報もありませんし、多人数に一気に読み取ってもらうこともできます。何より、「カメラを向ける」という直感的な選択&読み取り操作が便利です。

ゲーム内コンテンツとして使うのはもちろんですが、デバッグツールとの連携にも大活躍です。例えば、任意のユーザーでログインしたい場合や、ちょっとしたパラメータを流し込みたいなど。手でGUIDやパラメータをテキストとして打ち込む必要がなくなります。

しかし我らがUnityにはQRコードを読み取るAPIはありません。よく使われるライブラリとして、zxingなどが有名ですが、JavaなのでクロスプラットフォームではいくつかのライブラリやネイティブAPIを使い分ける必要があります。

C#フルマネージド

純粋なC#だけで出来たら、クロスプラットフォームのことはUnity層に丸投げすることができます。

そこで良さそうなライブラリを見つけました。

このライブラリは、C#だけで実装されています。なので、これをUnityに…

QRCodeSource/QRCodeDecoder/QRCodeDecoderLibrary/QRDecoder.cs
using System.Drawing.Imaging;

System.Drawing.Imagingは、Windows専用です…Unityでも参照を追加すれば使うことができますが、Windows上限定、クロスプラットフォームでの実行はできません。

.NET Standard2.0で動くようにする

.NET Standardは、.NETのサブセットで、あらゆる.NETのランタイムの共通集合的なターゲットAPIです。つまり、.NET Standardの範囲内のAPIしか使っていないのならば、ほぼすべての.NET上で動きますぜ!という規格です。こればっかりは、ちゃんとUnityも含まれています😓

今回はQRコードをデコードしたいだけなので、まずは、余計なクラスファイルを消します。

  • Camera.cs
  • DirectShowLib.cs
  • SampleGrabberHelper.cs

この三つのファイルは不要です。Unity側に同等のAPIがあるからです。

次に、System.Drawing.Imagingの顔でもあるBitmapクラスの互換品を作ります。ランタイムに依存しない、「配列」をラップして、Bitmapのふりをさせます。

public enum ImageLockMode { ReadOnly }
public enum PixelFormat { Format24bppRgb }

public class Bitmap
{
    public (byte r, byte g, byte b)[] Data { get; }
    public int Width { get; set; }
    public int Height { get; set; }

    public Bitmap(string fileName) => throw new NotImplementedException();

    public Bitmap((byte r, byte g, byte b)[] data, int width) => (Data, Width, Height) = (data, width, data.Length / width);

    public BitmapData LockBits(Rectangle rectangle, ImageLockMode readOnly, PixelFormat format24bppRgb)
    {
        var handle = GCHandle.Alloc(Data, GCHandleType.Pinned);
        var ptr = handle.AddrOfPinnedObject();
        return new BitmapData(handle, ptr, Width * 3);
    }

    public void UnlockBits(BitmapData bitmapData) => bitmapData.Handle.Free();
}

public readonly struct BitmapData
{
    public readonly GCHandle Handle;
    public readonly IntPtr Scan0;
    public readonly int Stride;
    public BitmapData(GCHandle reference, IntPtr scan0, int stride) => (Handle, Scan0, Stride) = (reference, scan0, stride);
}

public readonly struct Rectangle
{
    public readonly int X, Y, ImageWidth, ImageHeight;
    public Rectangle(int x, int y, int imageWidth, int imageHeight) => (X, Y, ImageWidth, ImageHeight) = (x, y, imageWidth, imageHeight);
}

あとはコンパイルエラーを起こすusingや、メソッド(使わない)を消したりして完成です。

Unityへのインポート

ここまでの修正をしたものをGithubに上げましたので、PackageManagerから参照してください。

https://github.com/wallstudio/UniQRCode.git?path=QRCodeSource/QRCodeDecoder/QRCodeDecoderLibrary

image.png

image.png

UniQRDecoderコンポーネントを適当なGameObjectに張り付けて、テクスチャをアタッチしたら再生。

image.png

画面にデコードされた文字列が出力されました。

カメラの入力

UnityにはカメラをそのままTextureとしてくれる、便利なAPIがあります。これをUniQRDecoderに食わせます。

var tex = new WebCamTexture(); // デフォルトのカメラ
await Task.Delay(1000);
var text = await UniQRDecoder.Decode(tex);
Debug.Log(text);

まとめ

Uzi-Granot/QRCodeを使って、C#オンリーでクロスプラットフォーム対応なQRデコードを、Unity上で実現することができました。理論上はSwitchなどでも利用できるはずです。

PackageManagerでぽちっと入れるだけの状態で公開しているので、良ければご活用ください!(MITライセンス)

ライセンス表記

Uzi-Granot/QRCode
# [Uzi-Granot/QRCode](https://github.com/Uzi-Granot/QRCode/)

The Code Project Open License (CPOL) 1.02

https://www.codeproject.com/Articles/1250071/QR-Code-Encoder-and-Decoder-Csharp-Class-Library-f

https://www.codeproject.com/info/cpol10.aspx
3
2
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
3
2