できない.dev

QRコードを生成するには

文字列や URL から QR コードの PNG 画像を作る書き方を、各言語の定番ライブラリで示す。
生成した画像を別のデコーダで読み戻して確かめた結果と、誤り訂正レベル・余白・データの長さによるつまずきもまとめる。

公開:

選んだ言語は、ほかのサンプルコードを開いたときも最初に表示する。

Python

# pip install "qrcode[pil]"
import qrcode
 
qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_M, box_size=10, border=4)
qr.add_data("https://example.com/hello")
qr.make(fit=True)
qr.make_image().save("qr.png")
print(qr.version)  # 2

qrcode.QRCode に誤り訂正レベル・1 マスの大きさ(box_size)・余白(border)を渡し、make(fit=True) でデータに合う版を自動で選ばせる。
PNG の保存には Pillow を使うので、qrcode[pil] の形で一緒に入れる。

できないときPython import できない(ModuleNotFoundError)

JavaScript

// npm install qrcode
import QRCode from "qrcode";
 
const url = "https://example.com/hello";
await QRCode.toFile("qr.png", url, { errorCorrectionLevel: "M", margin: 4, scale: 10 });
console.log(QRCode.create(url, { errorCorrectionLevel: "M" }).version); // 2

QRCode.toFile に出力先とデータを渡すと、.png の拡張子で PNG として保存される。
scale は 1 モジュールのピクセル数、margin は余白のモジュール数で、画像の幅は(版の幅 + 余白 × 2)× scale になる。

できないときNode.js「Error: Cannot find module」の原因と直し方

TypeScript

// npm install qrcode && npm install -D @types/qrcode
import QRCode from "qrcode";
 
const url: string = "https://example.com/hello";
const options: QRCode.QRCodeToFileOptions = { errorCorrectionLevel: "M", margin: 4, scale: 10 };
await QRCode.toFile("qr.png", url, options);
console.log(QRCode.create(url, { errorCorrectionLevel: "M" }).version); // 2

qrcode 本体には型定義が含まれず、@types/qrcode を別に入れる。
オプションに QRCode.QRCodeToFileOptions の型を付けておくと、errorCorrectionLevel に "X" のような存在しない値を渡したときに実行前に気づける。

できないときTypeScript「Cannot find module ... or its corresponding type declarations」の原因と直し方

Go

// go get github.com/skip2/go-qrcode
package main
 
import (
	"fmt"
 
	"github.com/skip2/go-qrcode"
)
 
func main() {
	q, err := qrcode.New("https://example.com/hello", qrcode.Medium)
	if err != nil {
		panic(err)
	}
	if err := q.WriteFile(256, "qr.png"); err != nil {
		panic(err)
	}
	fmt.Println(q.VersionNumber) // 2
}

qrcode.New にデータと誤り訂正レベル(qrcode.Medium)を渡し、WriteFile で一辺 256 ピクセルの PNG を書く。
余白は既定で付き、選ばれた版は VersionNumber で読める。

できないときGo「cannot find module providing package」の原因と直し方

Rust

// Cargo.toml: qrcode = "0.14", image = "0.25"
use image::Luma;
use qrcode::{EcLevel, QrCode};
 
fn main() {
    let code = QrCode::with_error_correction_level("https://example.com/hello", EcLevel::M).unwrap();
    let img = code.render::<Luma<u8>>().min_dimensions(256, 256).build();
    img.save("qr.png").unwrap();
    println!("{:?}", code.version()); // Normal(2)
}

標準ライブラリに QR コードの生成が無いので、qrcode と image の 2 つのクレートを使う。
render::<Luma<u8>>() で白黒の画像にし、min_dimensions で下限の大きさを指定すると、1 モジュールが整数ピクセルになる大きさへ切り上がる。

できないときRust「failed to resolve: use of undeclared crate or module」の原因と直し方

Java

// ZXing の core と javase(3.5.4)をクラスパスに置く
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.nio.file.Path;
import java.util.Map;
 
public class Main {
    public static void main(String[] args) throws Exception {
        // 何も指定しないと誤り訂正レベルは L になる。他の言語に合わせて M を指定する
        Map<EncodeHintType, Object> hints = Map.of(
            EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M,
            EncodeHintType.MARGIN, 4);
        BitMatrix matrix = new QRCodeWriter()
            .encode("https://example.com/hello", BarcodeFormat.QR_CODE, 256, 256, hints);
        MatrixToImageWriter.writeToPath(matrix, "PNG", Path.of("qr.png"));
    }
}

ZXing では QRCodeWriter で BitMatrix を作り、MatrixToImageWriter で PNG に書き出す。
誤り訂正レベルの既定は L なので、ほかの言語と条件をそろえるなら EncodeHintType.ERROR_CORRECTION で明示する。

できないときJava「package does not exist」が javac で出る原因と直し方

C#

// dotnet add package QRCoder
using System.IO;
using QRCoder;
 
using var generator = new QRCodeGenerator();
using var data = generator.CreateQrCode("https://example.com/hello", QRCodeGenerator.ECCLevel.M);
byte[] png = new PngByteQRCode(data).GetGraphic(10); // 1 モジュールを 10 ピクセルで描く
File.WriteAllBytes("qr.png", png);

QRCodeGenerator.CreateQrCode で誤り訂正レベルを指定してデータを作り、PngByteQRCode に渡すと PNG のバイト列が得られる。
GetGraphic(10) の 10 は 1 モジュールのピクセル数で、描画用のネイティブライブラリを足さなくても Linux のコンテナで動いた。

できないときC# の CS0246「型または名前空間名が見つかりませんでした」の原因と直し方

標準ライブラリでは作れないので定番のライブラリを使う

QR コードの生成は、ここで扱う 7 言語のどれも標準ライブラリだけでは書けないので、各言語で広く使われているライブラリを使った。

  • Python は qrcode 8.2(Pillow 13.0.0、Python 3.14.10)。
  • JavaScript は qrcode 1.5.4(Node.js 24.22.2)。
  • TypeScript は同じ qrcode 1.5.4 に @types/qrcode 1.5.6 と tsx を組み合わせた。
  • Go は github.com/skip2/go-qrcode(v0.0.0-20200617195104-da1b6568686e、Go 1.27.3)。
  • Rust は qrcode 0.14.1 と image 0.25.10(Rust 1.99.1)。
  • Java は ZXing の core と javase 3.5.4(OpenJDK 21.0.13)。
  • C# は QRCoder 1.8.1(.NET SDK 8.0.426)。

画像を作れたことと、QR コードとして読めることは別なので、7 つの PNG はすべて別のデコーダ(Debian bookworm の zbar-tools に入っている zbarimg 0.23.92)で読み戻した。
結果は 7 つとも元の文字列 https://example.com/hello と一致した。

誤り訂正レベルは頑丈さと大きさの引き換えになる

QR コードには誤り訂正レベルが L・M・Q・H の 4 段階あり、上げるほど汚れや欠けに強くなる代わりに、同じデータでも模様が大きく細かくなる。

  • 25 文字の URL を qrcode(Python)で作ると、L と M は 25 モジュール四方(版 2)、Q は 29 四方(版 3)、H は 33 四方(版 4)になった。
  • 中央を正方形に白く塗りつぶして zbarimg が読める最大の一辺を調べると、L は 3 モジュール、M は 5、Q は 10、H は 13 だった。

既定値はライブラリごとに違う。
Python の qrcode は M だった。
JavaScript と Rust は 30 文字の URL で L より大きい版になり、既定が L ではないと分かった。
Java の ZXing は L と同じ 33 モジュール幅になり、既定が L だった。
ライブラリを替えたら、レベルを明示して条件をそろえる。

余白を削ると読めなくなることがある

QR コードの周りには、規格で 4 モジュール分の白い余白(クワイエットゾーン)が必要とされている。
画像を小さくしたくて余白を削ると、読み取り側が模様の外側を判別できなくなる場合がある。

  • 余白 0 の PNG を黒で囲んだ画像に貼ると、zbarimg は読めなかった。余白が 1 モジュールあれば同じ条件で読めた。
  • 周囲が白・暗いグレー・白黒のランダムなブロックのときは、余白 0 でも読めた。

zbarimg は読み取りに寛容なほうなので、読めたからといってスマートフォンのカメラで読める保証にはならない。
余白は規格どおり 4 モジュール残しておくのが安全である。

URL が長いと版が上がって 1 つの点が小さくなる

データが長くなるほど必要な版が上がり、模様のモジュール数が増える。
誤り訂正レベル M の qrcode(Python)で、https://example.com/ に文字を足して長さを変えた結果は次のとおりだった。

  • 25 文字は版 2(25 モジュール四方)。
  • 60 文字は版 4(33 四方)。
  • 100 文字は版 6(41 四方)。
  • 200 文字は版 10(57 四方)。

レベルを H にすると 200 文字は版 15(77 四方)になる。
画像の幅を 256 ピクセルに固定すると、1 モジュールは版 2 で約 7.8 ピクセル、版 10 で約 3.9 ピクセルになる(余白 4 モジュールを含めて計算)。
点が小さいほど読み取りは難しくなるので、QR コードに入れる URL は短縮するか、不要なクエリを削るほうがよい。

ライブラリを入れる前に実行すると失敗する

どの例も外部ライブラリが前提なので、入れ忘れると最初の行で止まる。
実際に出た表示は次のとおりだった。

  • Python は ModuleNotFoundError: No module named 'qrcode' になる。
  • Node.js は Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'qrcode' になる。
  • Go は no required module provides package github.com/skip2/go-qrcode; to add it: に続いて go get github.com/skip2/go-qrcode が案内される。
  • TypeScript は @types/qrcode を外すと TS7016: Could not find a declaration file for module 'qrcode' になる。

言語ごとの入れ方は各コードの先頭のコメントに書いた。

画像の大きさの決め方が言語ごとに違う

同じ文字列・同じ誤り訂正レベル M でも、出力された PNG の一辺は言語で違った。

  • Python(box_size=10)、JavaScript と TypeScript(scale: 10)、C#(GetGraphic(10))は 330 ピクセルだった。33 モジュール(余白込み)× 10 ピクセルである。
  • Rust は min_dimensions(256, 256) を渡しても 264 ピクセルだった。33 モジュール × 8 ピクセルに切り上がった。
  • Go と Java は指定した 256 ピクセルのままだった。

1 モジュールのピクセル数を指定する書き方は点の細かさを決めやすく、全体の大きさを指定する書き方は貼り付け先の枠に合わせやすい。