تمرین و پروژه‌های پایتون

ساخت QR کد با پایتون؛ پروژه کامل QR ساز با لوگو، وای‌فای و CSV

ساخت QR کد با پایتون

🗓 آخرین به‌روزرسانی:

QR کد را امروز همه‌جا می‌بینید: روی منوی رستوران، کارت ویزیت، بسته‌بندی محصولات و حتی برای اتصال به وای‌فای. خبر خوب این است که ساخت QR کد با پایتون فقط چند خط کد است. در این پروژه یک ابزار کامل QR ساز می‌سازیم که لینک و متن را به QR تبدیل می‌کند، رنگ و اندازه و حاشیه را تنظیم می‌کند، QR مخصوص وای‌فای و کارت ویزیت می‌سازد، لوگو وسط آن قرار می‌دهد، از روی یک فایل CSV ده‌ها QR را یک‌جا تولید می‌کند و در پایان، QR ساخته‌شده را با OpenCV می‌خواند تا مطمئن شویم درست کار می‌کند. همه کدها روی پایتون ۳.۱۳ اجرا شده‌اند و خروجی‌ها واقعی هستند؛ سورس کامل را هم می‌توانید به‌صورت ZIP دانلود کنید.

QR کد چیست و چطور کار می‌کند؟

QR کد (Quick Response) یک بارکد دوبعدی است که داده را در قالب مربع‌های کوچک سیاه و سفید ذخیره می‌کند. برخلاف بارکدهای خطی که فقط چند عدد نگه می‌دارند، یک QR کد می‌تواند تا چند هزار کاراکتر ذخیره کند. سه مربع بزرگ در گوشه‌ها به دوربین کمک می‌کنند جهت و اندازه کد را تشخیص دهد. دو مفهوم مهم در ساخت QR وجود دارد:

  • نسخه (Version): عددی از ۱ تا ۴۰ که اندازه شبکه را تعیین می‌کند. نسخه ۱ شبکه ۲۱ در ۲۱ خانه دارد و هر نسخه ۴ خانه به هر ضلع اضافه می‌کند. داده بیشتر یعنی نسخه بزرگ‌تر.
  • سطح تصحیح خطا: چهار سطح L، M، Q و H که به ترتیب حدود ۷، ۱۵، ۲۵ و ۳۰ درصد از کد را قابل بازیابی می‌کنند. سطح بالاتر یعنی QR حتی با خط‌خوردگی یا لوگوی وسط هم خوانده می‌شود، اما بزرگ‌تر می‌شود.

کاربردهای QR کد در پروژه‌های واقعی

  • لینک سایت و شبکه‌های اجتماعی: روی کارت ویزیت، بروشور و بسته‌بندی محصول، کاربر را مستقیم به صفحه موردنظر می‌برد.
  • منوی دیجیتال: کافه‌ها و رستوران‌ها به‌جای منوی کاغذی، یک QR روی میز می‌گذارند که به صفحه منو لینک می‌شود.
  • اتصال به وای‌فای مهمان: بدون گفتن و تایپ کردن رمز شبکه.
  • کارت ورود رویداد: برای هر شرکت‌کننده یک کد یکتا ساخته و هنگام ورود اسکن می‌شود.
  • انبارداری و اموال: روی هر کالا یک QR با شناسه آن چسبانده می‌شود؛ ایده‌ای که می‌توانید با پروژه مدیریت موجودی فروشگاه ترکیب کنید.

QR ایستا یا پویا؛ تفاوت چیست؟

QRهایی که در این آموزش می‌سازیم «ایستا» هستند؛ یعنی داده مستقیم داخل خود کد ذخیره شده و بعد از چاپ قابل تغییر نیست. سرویس‌های آنلاین QR «پویا» هم ارائه می‌دهند که در واقع یک لینک کوتاه به سرور خودشان است و مقصد آن را می‌توان بعداً عوض کرد و آمار اسکن گرفت. اگر چنین قابلیتی می‌خواهید، لازم نیست سراغ سرویس پولی بروید: کافی است در QR لینکی به سایت خودتان بگذارید، مثلاً یک صفحه کوتاه با پارامتر UTM، و هر وقت لازم شد آن صفحه را به مقصد جدید هدایت کنید. به این ترتیب QR چاپ‌شده همیشه معتبر می‌ماند و آمار بازدید را هم در ابزار تحلیل سایت می‌بینید.

نصب کتابخانه‌ها

برای ساخت QR از کتابخانه qrcode همراه با Pillow برای ساخت تصویر استفاده می‌کنیم. برای خواندن و تست QR هم نسخه سبک OpenCV را نصب می‌کنیم. بهتر است این کار را داخل یک محیط مجازی انجام دهید:

pip install "qrcode[pil]" opencv-python-headless

ساده‌ترین QR کد با یک خط

تابع qrcode.make سریع‌ترین راه ساخت QR است. داده را می‌گیرد و یک تصویر برمی‌گرداند که با save ذخیره می‌شود. برای بررسی، اندازه تصویر و نسخه انتخاب‌شده را چاپ می‌کنیم:

import qrcode

img = qrcode.make("https://dev-source.ir/")
img.save("site.png")
print("image size:", img.size)
print("saved:", "site.png")

خروجی:

image size: (330, 330)
saved: site.png

این تصویر ۳۳۰ پیکسلی همین حالا با دوربین گوشی خوانده می‌شود. اما برای کنترل بیشتر روی اندازه، رنگ و سطح تصحیح خطا باید از کلاس QRCode استفاده کنیم.

کنترل اندازه، حاشیه و رنگ

کلاس QRCode چند پارامتر مهم دارد: box_size اندازه هر خانه به پیکسل است، border عرض حاشیه سفید دور کد به تعداد خانه است (استاندارد حداقل ۴ خانه را توصیه می‌کند) و version=None همراه با fit=True باعث می‌شود کوچک‌ترین نسخه مناسب داده به‌طور خودکار انتخاب شود. تابع make_qr در فایل پروژه همه این‌ها را در یک تابع جمع کرده است:

from qr_tool import make_qr

version, size = make_qr("https://dev-source.ir/", "navy.png", fill="#0b1d3f", back="#ffffff")
print("navy:", "version", version, "size", size)

version, size = make_qr("https://dev-source.ir/", "big.png", box_size=20, border=2)
print("big:", "version", version, "size", size)

خروجی:

navy: version 2 size (330, 330)
big: version 2 size (580, 580)

هنگام انتخاب رنگ، تضاد کافی را حفظ کنید: رنگ کد باید تیره و پس‌زمینه روشن باشد. QR با رنگ روشن روی پس‌زمینه تیره را خیلی از اپلیکیشن‌ها نمی‌خوانند.

سطح تصحیح خطا و اثر آن روی اندازه

بیایید ببینیم سطح تصحیح خطا چطور روی نسخه و اندازه QR اثر می‌گذارد. یک متن نسبتاً بلند را با هر چهار سطح می‌سازیم و نسخه نهایی را مقایسه می‌کنیم:

import qrcode
from qrcode import constants

data = "https://dev-source.ir/python-course/?utm_source=qr&utm_medium=print"
levels = {"L": constants.ERROR_CORRECT_L, "M": constants.ERROR_CORRECT_M,
          "Q": constants.ERROR_CORRECT_Q, "H": constants.ERROR_CORRECT_H}
for name, level in levels.items():
    qr = qrcode.QRCode(error_correction=level)
    qr.add_data(data)
    qr.make(fit=True)
    cells = qr.modules_count
    print(f"level {name}: version {qr.version}, grid {cells}x{cells}")

خروجی:

level L: version 4, grid 33x33
level M: version 5, grid 37x37
level Q: version 6, grid 41x41
level H: version 8, grid 49x49

هرچه سطح بالاتر باشد، شبکه بزرگ‌تر و خانه‌ها ریزتر می‌شوند. برای چاپ روی کاغذ و کارت ویزیت سطح M کافی است؛ اما اگر قرار است لوگو روی QR بگذارید یا کد در محیط بیرون در معرض خط و خش باشد، سطح H را انتخاب کنید.

خواندن QR کد با OpenCV

یک QR ساز خوب باید مطمئن شود خروجی‌اش قابل خواندن است. کلاس QRCodeDetector در OpenCV تصویر را می‌گیرد، محل QR را پیدا می‌کند و متن داخل آن را برمی‌گرداند. تابع decode در پروژه همین کار را انجام می‌دهد:

from qr_tool import make_qr, decode

make_qr("Hello from Dev Source!", "hello.png")
print("decoded:", decode("hello.png"))

خروجی:

decoded: Hello from Dev Source!

متد detectAndDecode سه مقدار برمی‌گرداند: متن داخل QR، مختصات چهار گوشه کد در تصویر و تصویر صاف‌شده خود کد. اگر QR پیدا نشود یا خوانده نشود، متن یک رشته خالی است؛ پس در برنامه واقعی همیشه بررسی کنید که نتیجه خالی نباشد. از مختصات گوشه‌ها هم می‌توانید برای کشیدن کادر دور QR در تصویر دوربین استفاده کنید.

QR کد اتصال به وای‌فای

یکی از کاربردی‌ترین QRها، QR وای‌فای است: مهمان شما گوشی را جلوی کد می‌گیرد و بدون تایپ رمز به شبکه وصل می‌شود. این QR در واقع یک متن با قالب استاندارد WIFI:T:WPA;S:name;P:password;; است. اگر نام شبکه یا رمز شامل کاراکترهای خاص مثل ; یا : باشد، باید قبل از آن‌ها بک‌اسلش بگذاریم؛ تابع wifi_payload این کار را انجام می‌دهد:

from qr_tool import wifi_payload, make_qr, decode

payload = wifi_payload("Home_Net", "p@ss;word:2026")
print(payload)
make_qr(payload, "wifi.png")
print("decoded matches:", decode("wifi.png") == payload)

خروجی:

WIFI:T:WPA;S:Home_Net;P:p@ss\;word\:2026;H:false;;
decoded matches: True

هشدار امنیتی: هر کسی که QR وای‌فای را ببیند، رمز شبکه شما را دارد. آن را فقط برای شبکه مهمان استفاده کنید و در جای عمومی نصب نکنید. برای ساخت رمزهای قوی هم می‌توانید از پروژه تولیدکننده رمز عبور با پایتون کمک بگیرید.

QR کارت ویزیت (vCard)

QR می‌تواند اطلاعات تماس را هم در قالب استاندارد vCard نگه دارد؛ با اسکن آن، گوشی پیشنهاد می‌کند مخاطب جدید ذخیره شود. قالب vCard چند خط ساده است که با BEGIN:VCARD شروع و با END:VCARD تمام می‌شود:

from qr_tool import vcard_payload, make_qr, decode

card = vcard_payload("Sara Ahmadi", "+98-912-000-0000", "sara@example.com")
print(card)
version, size = make_qr(card, "card.png")
print("version:", version, "| decoded ok:", decode("card.png") == card)

خروجی:

BEGIN:VCARD
VERSION:3.0
FN:Sara Ahmadi
TEL:+98-912-000-0000
EMAIL:sara@example.com
END:VCARD
version: 6 | decoded ok: True

قرار دادن لوگو وسط QR کد

QRهای برند معمولاً یک لوگوی کوچک در وسط دارند. این کار به لطف تصحیح خطا ممکن است: لوگو بخشی از خانه‌ها را می‌پوشاند و QR با استفاده از اطلاعات اضافه، آن بخش را بازسازی می‌کند. پس حتماً سطح H را انتخاب کنید و لوگو را بیشتر از حدود ۲۵ درصد عرض کد بزرگ نکنید. در مثال زیر یک لوگوی ساده با Pillow می‌سازیم، روی QR می‌گذاریم و بررسی می‌کنیم که هنوز خوانده شود:

from PIL import Image, ImageDraw
from qr_tool import make_qr, add_logo, decode

logo = Image.new("RGBA", (120, 120), (255, 201, 40, 255))
ImageDraw.Draw(logo).text((38, 50), "DS", fill=(11, 29, 63, 255))
logo.save("logo.png")

make_qr("https://dev-source.ir/", "plain.png", high=True)
add_logo("plain.png", "logo.png", "branded.png", ratio=0.22)
print("branded decoded:", decode("branded.png"))

خروجی:

branded decoded: https://dev-source.ir/

قبل از چاپ، اندازه فیزیکی QR را هم در نظر بگیرید. قانون سرانگشتی این است که فاصله اسکن حدود ده برابر عرض کد باشد؛ پس QR دو و نیم سانتی روی کارت ویزیت از فاصله حدود ۲۵ سانتی‌متر خوانده می‌شود، اما برای پوستری که از دو متری دیده می‌شود دست‌کم ۲۰ سانتی‌متر عرض لازم است. برای چاپ باکیفیت، box_size را بزرگ بگیرید تا تصویر وضوح کافی داشته باشد و همیشه نمونه چاپی را قبل از تیراژ نهایی با چند گوشی مختلف تست کنید.

ساخت گروهی QR از روی فایل CSV

فرض کنید برای ۵۰ محصول یا ۵۰ شرکت‌کننده یک رویداد QR لازم دارید. ساختن دستی آن‌ها خسته‌کننده است؛ اما با یک فایل CSV و یک حلقه، همه در چند ثانیه ساخته می‌شوند. تابع batch_from_csv فایل را با csv.DictReader می‌خواند و برای هر سطر یک تصویر با نام همان سطر در پوشه خروجی می‌سازد. پوشه را هم با pathlib ایجاد می‌کنیم:

from qr_tool import batch_from_csv, decode

files = batch_from_csv("links.csv", "qr_out")
print("created:", files)
print("check:", decode("qr_out/contact.png"))

خروجی:

created: ['site.png', 'course.png', 'contact.png']
check: mailto:info@dev-source.ir

ابزار خط فرمان

در پایان، تابع main با کمک argparse پروژه را به یک ابزار خط فرمان تبدیل می‌کند. داده اجباری است و نام فایل خروجی و رنگ‌ها اختیاری هستند. برنامه بعد از ساخت تصویر، آن را دوباره می‌خواند و نتیجه را نشان می‌دهد:

python qr_tool.py "https://dev-source.ir/" -o site.png
python qr_tool.py "Hello" -o hello.png --fill "#0b1d3f" --back "#ffffff"
from qr_tool import main

main(["https://dev-source.ir/python-projects/", "-o", "projects.png", "--fill", "#1d4ed8"])

خروجی:

Saved projects.png (version 3, 370x370 px)
Decoded back: https://dev-source.ir/python-projects/

سورس کامل QR ساز با پایتون

کد کامل پروژه در ادامه آمده است. فایل ZIP شامل همین کد، requirements.txt و راهنمای اجراست:

⬇ دانلود سورس کامل QR ساز (ZIP)

"""QR code generator with Python - Dev Source (dev-source.ir)"""
import argparse
import csv
from pathlib import Path

import qrcode
from qrcode.constants import ERROR_CORRECT_H, ERROR_CORRECT_M


def make_qr(data, filename, fill="black", back="white", box_size=10, border=4, high=False):
    qr = qrcode.QRCode(
        version=None,
        error_correction=ERROR_CORRECT_H if high else ERROR_CORRECT_M,
        box_size=box_size,
        border=border,
    )
    qr.add_data(data)
    qr.make(fit=True)
    img = qr.make_image(fill_color=fill, back_color=back).convert("RGB")
    img.save(filename)
    return qr.version, img.size


def wifi_payload(ssid, password, security="WPA", hidden=False):
    def esc(text):
        for ch in "\\;,:\"":
            text = text.replace(ch, "\\" + ch)
        return text
    return f"WIFI:T:{security};S:{esc(ssid)};P:{esc(password)};H:{'true' if hidden else 'false'};;"


def vcard_payload(name, phone, email):
    return ("BEGIN:VCARD\nVERSION:3.0\n"
            f"FN:{name}\nTEL:{phone}\nEMAIL:{email}\nEND:VCARD")


def add_logo(qr_file, logo_file, out_file, ratio=0.22):
    from PIL import Image
    qr_img = Image.open(qr_file).convert("RGB")
    logo = Image.open(logo_file).convert("RGBA")
    size = int(qr_img.size[0] * ratio)
    logo.thumbnail((size, size))
    pos = ((qr_img.size[0] - logo.size[0]) // 2, (qr_img.size[1] - logo.size[1]) // 2)
    qr_img.paste(logo, pos, logo)
    qr_img.save(out_file)


def decode(filename):
    import cv2
    img = cv2.imread(str(filename))
    text, points, _ = cv2.QRCodeDetector().detectAndDecode(img)
    return text


def batch_from_csv(csv_file, out_dir):
    out = Path(out_dir)
    out.mkdir(exist_ok=True)
    made = []
    with open(csv_file, newline="", encoding="utf-8") as f:
        for row in csv.DictReader(f):
            path = out / f"{row['name']}.png"
            make_qr(row["data"], path)
            made.append(path.name)
    return made


def main(argv=None):
    parser = argparse.ArgumentParser(description="Create a QR code image")
    parser.add_argument("data", help="text or URL to encode")
    parser.add_argument("-o", "--output", default="qr.png")
    parser.add_argument("--fill", default="black")
    parser.add_argument("--back", default="white")
    args = parser.parse_args(argv)
    version, size = make_qr(args.data, args.output, args.fill, args.back)
    print(f"Saved {args.output} (version {version}, {size[0]}x{size[1]} px)")
    print("Decoded back:", decode(args.output))


if __name__ == "__main__":
    main()

ایده‌هایی برای توسعه پروژه

  • رابط گرافیکی: با Tkinter یک پنجره بسازید که متن را بگیرد و پیش‌نمایش QR را همان‌جا نشان دهد.
  • نسخه وب: با Flask صفحه‌ای بسازید که QR را می‌سازد و برای دانلود ارائه می‌دهد.
  • QR با رنگ گرادیان: از ماژول qrcode.image.styledpil برای خانه‌های گرد و رنگی استفاده کنید.
  • اسکنر وب‌کم: با cv2.VideoCapture تصویر دوربین را بخوانید و QRها را زنده تشخیص دهید.
  • ربات تلگرام: رباتی بسازید که هر متنی دریافت کرد، QR آن را برگرداند؛ ساخت ربات تلگرام را ببینید.

خطاهای رایج و راه رفع

  • ModuleNotFoundError: No module named qrcode یا PIL: کتابخانه را با pip install "qrcode[pil]" در همان محیطی نصب کنید که برنامه را اجرا می‌کنید.
  • QR خوانده نمی‌شود: تضاد رنگ کم است، حاشیه را حذف کرده‌اید یا لوگو خیلی بزرگ است؛ سطح H و حاشیه ۴ را امتحان کنید.
  • DataOverflowError: داده برای نسخه انتخاب‌شده زیاد است؛ version=None و fit=True بگذارید یا داده را کوتاه کنید.
  • متن فارسی درست خوانده نمی‌شود: بعضی اسکنرهای قدیمی UTF-8 را پشتیبانی نمی‌کنند؛ برای اطلاعات فارسی بهتر است یک لینک به صفحه وب در QR بگذارید.
  • decode رشته خالی برمی‌گرداند: تصویر خیلی کوچک یا تار است؛ box_size را بزرگ‌تر کنید.

سوالات متداول

چطور با پایتون QR کد بسازم؟

کتابخانه qrcode را با pip install “qrcode[pil]” نصب کنید و با qrcode.make(“متن یا لینک”).save(“qr.png”) یک تصویر QR بسازید.

بهترین سطح تصحیح خطا برای QR کد کدام است؟

برای استفاده عادی سطح M کافی است. اگر لوگو روی QR می‌گذارید یا کد ممکن است خراب شود، سطح H را انتخاب کنید.

چطور QR کد را با پایتون بخوانم؟

با OpenCV و کلاس QRCodeDetector؛ تصویر را با cv2.imread بخوانید و متد detectAndDecode متن داخل QR را برمی‌گرداند.

آیا می‌توانم QR کد رنگی بسازم؟

بله، با پارامترهای fill_color و back_color در make_image. فقط رنگ کد را تیره و پس‌زمینه را روشن نگه دارید تا اسکنرها آن را بخوانند.

QR وای‌فای چطور ساخته می‌شود؟

متنی با قالب WIFI:T:WPA;S:نام شبکه;P:رمز;; بسازید و آن را به QR تبدیل کنید. کاراکترهای خاص در نام و رمز باید با بک‌اسلش escape شوند.

آیا QR کد تاریخ انقضا دارد؟

QR ثابت که داده مستقیم در آن ذخیره شده منقضی نمی‌شود. فقط اگر لینک داخل آن از کار بیفتد، QR دیگر به جای درستی نمی‌رود.

آموزش‌های مرتبط

آموزش‌های تازه، کد آماده و رفع خطاهر هفته در کانال Dev Source؛ رایگان.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *