Bỏ qua, tới nội dung chính

Cách tạo mã QR bằng Python và JavaScript

“Tôi có danh sách 800 mã sản phẩm trong file CSV, viết code sinh mã QR cho từng dòng có phức tạp lắm không?” Câu hỏi kiểu này tôi nhận khá đều, và câu trả lời làm nhiều người ngạc nhiên: khoảng năm dòng Python.

Hệ sinh thái cho việc này đã chín từ lâu. Bên Python có hai thư viện đáng dùng là qrcodesegno; bên JavaScript có qrcode cho Node cùng trình duyệt, và qr-code-styling khi cần mã có logo và bo tròn. Cả bốn đều miễn phí, sinh mã tĩnh chuẩn ISO/IEC 18004 bản 2015, và chạy hoàn toàn trên máy bạn — không gửi nội dung tới máy chủ nào.

Bài này đưa code chạy được cho từng thư viện, cách chọn mức sửa lỗi và kích thước trong code, và một mục thẳng thắn về lúc nào viết code là thừa công. Nếu việc của bạn chỉ là sinh một bộ mã từ danh sách rồi thôi, công cụ tạo mã QR hàng loạt từ CSV làm xong trong hai phút mà không cần cài gì.

Python với thư viện qrcode

Đây là thư viện phổ biến nhất, xuất ảnh PNG qua Pillow. Cài đặt và dùng ở mức đơn giản nhất:

pip install "qrcode[pil]"

import qrcode

img = qrcode.make("https://taomaqrcode.com/")

img.save("ma.png")

Khi cần kiểm soát mức sửa lỗi, kích thước ô và độ rộng viền trắng, dùng lớp QRCode thay vì hàm rút gọn:

qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_H, box_size=10, border=4)

qr.add_data("noi dung can ma hoa")

qr.make(fit=True)

img = qr.make_image(fill_color="black", back_color="white")

img.save("ma.png")

Tham số border chính là vùng trắng bắt buộc quanh mã, tính theo số ô. Giá trị 4 là mức chuẩn; hạ xuống 1 hoặc 2 cho gọn là cách nhanh nhất để tự làm hỏng mã của mình.

Segno khi cần xuất SVG

Segno không phụ thuộc thư viện ảnh nào và xuất được SVG, EPS, PDF ngay từ đầu — hợp hơn hẳn khi mã sẽ đem đi in.

pip install segno

import segno

segno.make("https://taomaqrcode.com/", error="h").save("ma.svg", scale=10)

Tham số error nhận các giá trị l, m, q, h tương ứng bốn mức sửa lỗi. Đổi đuôi file trong lệnh save là đổi định dạng đầu ra, không cần thêm dòng nào. Với mã in khổ lớn, tôi luôn chọn segno và xuất SVG vì file vector phóng to không vỡ.

Trong JavaScript

Thư viện qrcode chạy được cả trên Node lẫn trong trình duyệt. Ghi ra file từ Node:

npm install qrcode

const QRCode = require("qrcode");

QRCode.toFile("ma.png", "https://taomaqrcode.com/", { errorCorrectionLevel: "H", width: 500 });

Trong trình duyệt, hàm toCanvas vẽ thẳng lên một thẻ canvas có sẵn, còn toDataURL trả về chuỗi ảnh dạng base64 để gán vào thẻ img. Cả hai chạy hoàn toàn phía người dùng, không gửi dữ liệu đi đâu — đây cũng chính là cách site này hoạt động.

Khi cần mã có logo ở giữa, ô bo tròn hay màu chuyển sắc, thư viện qr-code-styling làm tốt hơn nhiều và cũng chạy trong trình duyệt. Đổi lại nó nặng hơn và chỉ dùng được ở phía trình duyệt.

Sinh hàng loạt từ file CSV

Đây là lúc viết code thật sự đáng công. Đoạn dưới đọc một file CSV có hai cột — nội dung và tên file — rồi ghi ra một mã SVG cho mỗi dòng:

import csv, segno

with open("danh_sach.csv", encoding="utf-8") as f:

    for row in csv.DictReader(f):

        segno.make(row["noi_dung"], error="m").save("out/" + row["ten_file"] + ".svg", scale=10)

Nhớ tạo sẵn thư mục out trước khi chạy, và mở file CSV bằng encoding UTF-8 nếu dữ liệu có tiếng Việt có dấu. Với 800 dòng, đoạn này chạy xong trong vài giây.

Chọn mức sửa lỗi và kích thước trong code

Hai tham số này quyết định mã có quét được sau khi in hay không, và chúng đánh đổi lẫn nhau. Mức sửa lỗi cao giúp mã chịu xước và cho phép chèn logo, nhưng làm lưới dày hơn ở cùng lượng nội dung — chi tiết ở bài mức sửa lỗi L, M, Q, H.

Về kích thước, đừng nghĩ theo pixel mà nghĩ theo kích thước in. Tham số box_size trong qrcode và scale trong segno là số điểm ảnh cho mỗi ô của mã. Muốn in ở 300 điểm ảnh mỗi 2,54 cm với mã 5 cm, hãy tính ngược ra tổng chiều rộng file cần khoảng 590 điểm ảnh rồi chia cho số ô mỗi cạnh.

Cách chắc hơn là bỏ qua phép tính: xuất SVG, rồi đặt kích thước lúc dàn trang.

Khi nào viết code là thừa

Viết code chỉ đáng khi việc sinh mã lặp lại, hoặc khi nó là một bước trong quy trình tự động. Sinh mã cho danh sách nhân viên mỗi kỳ tuyển mới, gắn mã vào phiếu xuất kho, dựng mã trong một ứng dụng bạn đang xây — đó là những chỗ code thắng.

Còn nếu bạn chỉ cần một bộ mã, một lần, thì cài Python, cài thư viện, viết vòng lặp và xử lý lỗi encoding sẽ tốn nhiều thời gian hơn là nạp file CSV vào một công cụ có sẵn. Tôi nói điều này dù đang viết bài về code.

Giới hạn và lời khuyên cuối

Có một việc các thư viện này không làm được: chúng không tạo mã QR động, không đếm lượt quét và không sửa được đích sau khi tạo. Toàn bộ những gì bạn sinh ra bằng code đều là mã tĩnh, nên nếu yêu cầu của dự án là thống kê lượt quét thì phải tự dựng một dịch vụ chuyển hướng ở giữa — công việc lớn hơn nhiều so với việc vẽ hình.

Ngoài chuyện đó, bốn thư viện trong bài đủ cho gần như mọi việc. Nếu chỉ cần một cái tên để bắt đầu, tôi chọn segno cho Python vì nó xuất SVG mà không kéo theo Pillow. Và dù dùng thư viện nào, hãy in thử một mã ở đúng khổ rồi quét bằng điện thoại cũ trước khi sinh cả nghìn cái — code chạy đúng không có nghĩa mã in ra quét được. Với việc chỉ làm một lần, nạp thẳng file CSV rồi tải bộ mã về vẫn là đường ngắn nhất.

Hỏi đáp cho người viết code

Thư viện qrcode và segno khác nhau thế nào

Thư viện qrcode phổ biến hơn và xuất ảnh qua Pillow; segno nhẹ hơn, không phụ thuộc gì, và xuất SVG cùng PDF ngay từ đầu. Nếu bạn cần file vector để in, segno tiện hơn hẳn.

Tạo mã QR chuyển khoản VietQR bằng Python được không

Được, nhưng phần khó không nằm ở việc vẽ mã mà ở việc ghép chuỗi EMVCo đúng chuẩn Napas 247, gồm các trường có độ dài cố định và một mã kiểm tra CRC ở cuối. Sai một ký tự là app ngân hàng từ chối. Nếu chỉ cần vài mã, hãy tạo mã QR chuyển khoản trực tiếp thay vì tự ghép chuỗi.

Mã QR sinh bằng code có khác mã tạo bằng công cụ web không

Không khác về bản chất. Cùng chuẩn ISO/IEC 18004, cùng thuật toán sửa lỗi, và cùng cho ra mã tĩnh. Khác biệt chỉ nằm ở tùy chọn giao diện và định dạng xuất.

Xử lý tiếng Việt có dấu trong nội dung mã thế nào

Các thư viện này mã hóa theo UTF-8 nên tiếng Việt chạy bình thường. Điều cần nhớ là mỗi chữ có dấu chiếm ba byte, nên nội dung dài sẽ đẩy mã lên phiên bản cao và dày ô — cân nhắc giới hạn dung lượng theo phiên bản trước khi nhồi cả đoạn văn.

Có thư viện nào tạo mã QR có logo không

Bên JavaScript thì qr-code-styling làm sẵn. Bên Python, cách phổ biến là sinh mã ở mức sửa lỗi H rồi dùng Pillow dán logo vào giữa, nhớ chừa viền trắng quanh logo và giữ nó dưới khoảng một phần năm diện tích mã.

Bài viết liên quan

Mã QR tạo ở đây không hết hạn

Toàn bộ mã trên taomaqrcode.com là mã QR tĩnh: nội dung nằm ngay trong hình, không đi qua máy chủ trung gian nên dùng được mãi và không giới hạn lượt quét.

Đọc thêm mã QR tĩnh và mã QR động khác nhau thế nàomã QR có hết hạn không.