Panduan Pasukan Lucee MY

Bina penjana QR sendiri dalam CFML, versi ringkas

Bina penjana QR sendiri dalam CFML: warna, saiz, logo di tengah, dan muat turun PNG tanpa menyimpan fail pada pelayan atau menyimpan pautan pengguna anda.

Bina penjana QR sendiri dalam CFML, versi ringkas
0
Kandungan

Bina penjana QR sendiri dalam CFML, versi ringkas

Orang guna kod QR untuk satu perkara yang membosankan: menyampaikan pautan tanpa perlu ditaip. Menu restoran, pautan WhatsApp, kad nama, label produk.

Perkhidmatan dalam talian menjadikannya mudah, tetapi kebanyakannya menyimpan pautan anda, mengehadkan muat turun, atau meletakkan jenama mereka pada hasilnya. Untuk kebanyakan kerja, kita hanya perlukan tiga perkara: teks, warna, dan butang muat turun.

Bab ini membina penjana itu dalam CFML, dalam dua fail.

Apa yang kita bina

CiriKeputusan dalam artikel ini
Teks atau URLMedan teks, had 1200 aksara
Saiz300 hingga 900 piksel, dikawal pelayan
WarnaWarna kod dan warna latar, pilihan pengguna
LogoSatu fail logo di tengah, pilihan
Muat turunPNG dihantar terus, tiada fail disimpan
PengesahanSetiap hasil diimbas semula sebelum diterbitkan

Penjana QR ringkas: borang di kiri, pratonton dan muat turun di kanan

Hasil sebenar pada rig ujian: QR teal dengan logo, dijana dalam beberapa milisaat.

Kita tidak membina pengedit penuh. Tiada gradien, tiada bentuk mata tersuai, tiada pustaka awan. Itu kerja berbulan, dan bukan yang membuat kod QR berguna.

Sediakan ZXing

Kita menggunakan ZXing melalui Java, sama seperti artikel asas kod QR. Kalau anda belum memasangnya, ikut langkah di sana dahulu. Artikel ini menganggap com.google.zxing sudah ada pada classpath Lucee.

Fail pertama: penghasil imej

Fail qr-jana.cfm menerima parameter, menghasilkan PNG, dan menghantarnya. Ia tidak menulis apa-apa ke cakera.

<cfparam name="url.teks" default="">
<cfparam name="url.saiz" default="400">
<cfparam name="url.warna" default="0b6b5f">
<cfparam name="url.latar" default="ffffff">
<cfparam name="url.logo" default="0">
<cfparam name="url.muat" default="0">

<cfset teks = trim(url.teks)>
<cfset saiz = max(120, min(1200, val(url.saiz)))>
<cfset warna = reReplace(url.warna, "[^0-9A-Fa-f]", "", "all")>
<cfset latar = reReplace(url.latar, "[^0-9A-Fa-f]", "", "all")>
<cfif len(warna) NEQ 6><cfset warna = "0b6b5f"></cfif>
<cfif len(latar) NEQ 6><cfset latar = "ffffff"></cfif>

<cfif NOT len(teks)>
    <cfheader statuscode="400">
    <cfcontent type="text/plain" reset="true">Teks atau URL diperlukan.
    <cfabort>
</cfif>

Tiga baris pengesahan itu penting. max dan min menghalang saiz 40,000 piksel yang boleh menghabiskan memori. reReplace memastikan warna hanya mengandungi aksara hex, supaya tiada apa-apa selain warna sampai ke Color.decode.

Seterusnya, jana matriks dan tukarkannya kepada imej berwarna:

<cfset petunjuk = createObject("java", "java.util.HashMap").init()>
<cfset petunjuk.put(
    createObject("java", "com.google.zxing.EncodeHintType").ERROR_CORRECTION,
    createObject("java", "com.google.zxing.qrcode.decoder.ErrorCorrectionLevel").H)>
<cfset petunjuk.put(
    createObject("java", "com.google.zxing.EncodeHintType").MARGIN,
    javacast("int", 2))>
<cfset petunjuk.put(
    createObject("java", "com.google.zxing.EncodeHintType").CHARACTER_SET,
    "UTF-8")>

<cfset penulis = createObject("java", "com.google.zxing.qrcode.QRCodeWriter").init()>
<cfset bit = penulis.encode(
    teks,
    createObject("java", "com.google.zxing.BarcodeFormat").QR_CODE,
    javacast("int", saiz),
    javacast("int", saiz),
    petunjuk)>

<cfset konfig = createObject("java", "com.google.zxing.client.j2se.MatrixToImageConfig").init(
    javacast("int", createObject("java", "java.awt.Color").decode("##" & warna).getRGB()),
    javacast("int", createObject("java", "java.awt.Color").decode("##" & latar).getRGB()))>

<cfset imej = createObject("java", "com.google.zxing.client.j2se.MatrixToImageWriter")
    .toBufferedImage(bit, konfig)>

ERROR_CORRECTION ditetapkan kepada H, iaitu tahap tertinggi. Itu bukan kemewahan: logo di tengah menutup sebahagian kod, dan tahap H membenarkan sehingga 30 peratus bahagian hilang. Tanpa H, logo yang sama akan memusnahkan kod.

MARGIN ialah zon senyap di sekeliling kod. Dua modul cukup untuk kebanyakan pembaca; sifar modul menyebabkan kamera sukar mengesan bingkai.

Logo di tengah

<cfif url.logo EQ "1" AND fileExists(expandPath("./logo-uji.png"))>
    <cfset logo = createObject("java", "javax.imageio.ImageIO")
        .read(createObject("java", "java.io.File").init(expandPath("./logo-uji.png")))>
    <cfset grafik = imej.createGraphics()>
    <cfset saizLogo = javacast("int", saiz * 0.22)>
    <cfset posisi = javacast("int", (saiz - saizLogo) / 2)>
    <cfset grafik.setRenderingHint(
        createObject("java", "java.awt.RenderingHints").KEY_INTERPOLATION,
        createObject("java", "java.awt.RenderingHints").VALUE_INTERPOLATION_BILINEAR)>
    <cfset grafik.setColor(createObject("java", "java.awt.Color").decode("##" & latar))>
    <cfset grafik.fillRect(posisi - 8, posisi - 8, saizLogo + 16, saizLogo + 16)>
    <cfset grafik.drawImage(logo, posisi, posisi, saizLogo, saizLogo,
        createObject("java", "java.awt.Color").WHITE, javacast("null", ""))>
    <cfset grafik.dispose()>
</cfif>

Tiga butiran kecil menentukan hasilnya.

Saiz logo 22 peratus, bukan 30. Lebih besar nampak menarik pada skrin, tetapi kamera telefon mula gagal pada sudut condong.

fillRect dengan warna latar meletakkan bingkai di sekeliling logo, supaya ia tidak bercantum dengan modul QR di sebelahnya.

javacast("null", "") diperlukan kerana null bertindih dengan kata kunci CFML. Ini pepijat yang saya terserempak semasa menulis artikel ini, dan ia menghasilkan ralat variable [NULL] doesn't exist.

Hantar sebagai imej, bukan fail

<cfset aliran = createObject("java", "java.io.ByteArrayOutputStream").init()>
<cfset createObject("java", "javax.imageio.ImageIO").write(imej, "png", aliran)>

<cfheader name="Content-Disposition" value="#(url.muat EQ '1' ? 'attachment' : 'inline')#; filename=qr-kod.png">
<cfcontent type="image/png" variable="#aliran.toByteArray()#" reset="true">

Tiada fail sementara, tiada folder yang perlu dibersihkan, tiada risiko nama fail bertembung. Imej ditulis ke aliran memori dan dihantar.

Perhatikan javax.imageio.ImageIO mesti melalui createObject("java", ...). Menulis javax.imageio.ImageIO.write(...) terus memberi ralat variable [JAVAX] doesn't exist, kerana CFML menyangka javax ialah pemboleh ubah.

Fail kedua: borang

qr.cfm hanya membina borang dan pratonton. Bahagian pentingnya ialah ia menghantar parameter ke qr-jana.cfm melalui URL, jadi pratonton dan muat turun menggunakan tetapan yang sama.

<cfoutput>
<img src="qr-jana.cfm?teks=#encodeForURL(url.teks)#&saiz=#encodeForURL(url.saiz)#&warna=#encodeForURL(url.warna)#&latar=#encodeForURL(url.latar)#&logo=#encodeForURL(url.logo)#"
     alt="Kod QR untuk #encodeForHTMLAttribute(url.teks)#" width="280">
</cfoutput>

encodeForURL wajib pada setiap nilai. Tanpa itu, pautan yang mengandungi & akan memecahkan parameter, dan QR yang terhasil tidak sepadan dengan apa yang dipaparkan.

Satu perangkap CSS: warna hex seperti #f8fafc di dalam <cfoutput> dibaca sebagai ungkapan, dan halaman gagal dikompil dengan missing terminating [#]. Letakkan blok <style> di luar <cfoutput>, atau tulis ##f8fafc.

Kenapa tidak guna API pihak ketiga

Ada perkhidmatan percuma dalam talian yang menerima teks dan memulangkan imej QR. Ia cepat disiapkan, tetapi tiga perkara berubah apabila kod itu digunakan dalam kerja sebenar.

Pertama, pautan pelanggan dihantar ke pelayan orang lain. Untuk menu restoran atau kad nama, itu mungkin tidak mengapa; untuk pautan dalaman syarikat, ia kebocoran kecil yang tidak perlu.

Kedua, perkhidmatan percuma berubah, mengehadkan, atau hilang. Kod QR yang sudah dicetak pada 5,000 kotak tidak boleh menunggu vendor memutuskan semula dasar mereka.

Ketiga, setiap panggilan rangkaian menambah kelewatan dan satu titik kegagalan. Penjana tempatan siap dalam beberapa milisaat dan berfungsi walaupun pelayan tiada sambungan internet keluar.

Ujian yang saya jalankan

Setiap kes diuji dengan curl, dan setiap PNG diimbas semula menggunakan zbarimg:

KesKeputusan
URL biasa, 400 px200, image/png, diimbas sebagai https://lucee.my/cfml-assist
Warna ungu pada latar krim200, diimbas sebagai UJIAN
Logo di tengah, 600 px200, diimbas sebagai https://lucee.my
muat=1Content-Disposition: attachment
Teks kosong400 dengan mesej yang jelas
Saiz 99,999 dimintaDikurangkan kepada 1,200, 200 OK

Ujian ketiga itu yang paling penting. Ia membuktikan logo pada 22 peratus masih boleh diimbas, bukan hanya kelihatan cantik pada skrin.

Apa yang tidak ada

Tiada muat naik logo oleh pengguna, jadi tiada risiko fail berbahaya masuk ke pelayan. Kalau anda mahu ciri itu, hadkan jenis fail, saiz, dan simpan di luar webroot.

Tiada kod QR dinamik, jadi pautan tidak boleh ditukar selepas dicetak. Kalau itu keperluan, anda perlukan satu jadual dan satu halaman lencongan, seperti yang dibincangkan dalam artikel DuitNow.

Tiada pengesanan imbasan. Kod QR statik tidak memberitahu sesiapa bila ia diimbas, dan sebarang laman yang mendakwa sebaliknya menggunakan lencongan.

Soalan Lazim

Boleh saya guna warna terang seperti kuning? Boleh, tetapi kontras mesti cukup. Kamera membaca perbezaan kecerahan, bukan warna. Uji dengan mengimbas pada skrin telefon sebelum mencetak.

Kenapa kod QR saya tidak boleh diimbas selepas dicetak? Biasanya saiz terlalu kecil atau zon senyap terpotong semasa mencetak. Kekalkan margin sekurang-kurangnya empat modul untuk bahan cetak.

Boleh saya letak logo yang lebih besar? Boleh dicuba, tetapi uji. Melebihi 25 peratus biasanya mula gagal pada sudut condong walaupun tahap H digunakan.

Adakah teks bukan URL berfungsi? Ya. Nombor telefon, teks biasa dan vCard semuanya boleh dikodkan. Telefon akan memaparkan teks itu, bukan membuka pelayar.

Perlukah saya simpan imej di pelayan? Tidak untuk penjana segera. Simpan hanya kalau kod itu akan digunakan berulang kali, contohnya label produk.

Sumber

0 komen

0 komen

Log masuk untuk menjawab atau memberi komen.

Log masuk