Watermark dan thumbnail imej dengan cfimage dalam Lucee
Lucee tiada action watermark dalam cfimage. Panduan membina tera air dengan imagePaste, thumbnail tidak herot dengan imageScaleToFit dan angka saiz sebenar.

Kandungan
- Watermark dan thumbnail imej dengan cfimage dalam Lucee
- Apa yang cfimage sebenarnya boleh buat dalam Lucee?
- Kenapa cfimage action="watermark" gagal dalam Lucee?
- Bagaimana menyediakan imej ujian yang boleh diulang?
- Bagaimana membuat thumbnail yang tidak herot?
- Bagaimana menulis tera air teks yang betul?
- Bagaimana menampal logo sebagai tera air?
- Berapa besar fail WebP berbanding JPEG?
- Kenapa foto telefon muncul senget walaupun failnya betul?
- Berapa lama masa menjana satu thumbnail?
- Soalan Lazim
- Sumber
Watermark dan thumbnail imej dengan cfimage dalam Lucee
Jawapan pantas: Tag cfimage dalam Lucee hanya menerima action border, captcha, convert, info, read, resize, rotate, write dan writeToBrowser, jadi tiada action watermark untuk dipanggil. Tera air dibina daripada dua bahagian asas, iaitu ketelusan untuk jalur atau teks dan imagePaste untuk logo yang membawa saluran alpha. Thumbnail pula dibuat dengan imageScaleToFit(imej, lebar, ""), kerana argumen ketiga wajib diisi dan rentetan kosong mengekalkan nisbah aspek.
Semua angka di bawah diukur pada rig Lucee 7.1.1.17-RC, dan setiap blok kod dijalankan pada rig itu sebelum artikel ini terbit.
Apa yang cfimage sebenarnya boleh buat dalam Lucee?
Senarai ini datang daripada mesej ralat enjin sendiri, bukan daripada andaian. Ia penting kerana banyak tutorial lama menyebut action="watermark", dan kod itu gagal pada kali pertama dijalankan.
| Action | Kegunaan | Nota |
|---|---|---|
info | Baca saiz dan metadata | Hasil masuk structName |
read | Muat imej ke pemboleh ubah | Sama seperti imageRead |
resize | Tukar kepada lebar dan tinggi tepat | Boleh herotkan imej |
rotate | Putar mengikut darjah | EXIF sudah diambil kira |
convert | Tulis dalam format lain | Termasuk WebP |
border | Tambah bingkai | Saiz dalam piksel |
captcha | Jana imej captcha | Teks dipulangkan |
write | Simpan ke cakera | Kawalan kualiti melalui imageWrite |
writeToBrowser | Hantar ke pelayar | Tetapkan format |
Yang tiada daripada senarai itu: watermark, overlay, crop dan thumbnail. Ketiga-tiganya dibuat dengan fungsi, iaitu imagePaste, imageOverlay, imageCrop, imageScaleToFit, imageSetDrawingTransparency, imageDrawRect dan imageDrawText. Semuanya ada dalam teras dan disahkan melalui getFunctionList() dalam rig.
Kenapa cfimage action="watermark" gagal dalam Lucee?
Action itu tidak wujud dalam enjin, dan mesej ralat menyenaraikan apa yang wujud. Inilah teks sebenar daripada Lucee 7.1.1.17-RC:
invalid action [watermark], valid actions are
[border,captcha,convert,info,read,resize,rotate,write,writeToBrowser]
Menampal logo melalui atribut tag juga gagal lebih awal dengan Attribute [image] is not allowed for tag [cfimage]. Jadi laluan yang tinggal ialah fungsi. Tera air pada asasnya kerja menyusun lapisan: satu imej asal, satu elemen separa lutsinar, dan satu kedudukan yang dikira daripada saiz imej itu sendiri.
Bagaimana menyediakan imej ujian yang boleh diulang?
Blok pertama menjana imej sendiri dan mencetak format yang benar-benar disokong pada mesin itu, supaya kod boleh dijalankan tanpa fail gambar peribadi.
folder = getTempDirectory() & "imej-cfimage/";
if (!directoryExists(folder)) {
directoryCreate(folder);
}
asas = imageNew("", 1600, 900, "rgb", "2b6cb0");
imageWrite(asas, folder & "sumber.jpg", 0.92);
writeOutput("boleh tulis: " & getWriteableImageFormats() & "<br>");
writeOutput("boleh baca: " & getReadableImageFormats() & "<br>");
writeOutput("saiz asal: " & getFileInfo(folder & "sumber.jpg").size & " bait<br>");
Dua perkara daripada output itu. getWriteableImageFormats() memulangkan senarai sebagai rentetan, bukan array, jadi arrayToList() ke atasnya membaling Can't cast String [...] to a value of type [Array]. WebP ada dalam kedua-dua senarai, manakala HEIC dan AVIF tiada, jadi fail HEIC daripada telefon tidak boleh dibaca langsung walaupun sambungannya ditukar kepada .jpg.
Bagaimana membuat thumbnail yang tidak herot?
imageScaleToFit memerlukan tiga argumen: imej, lebar maksimum dan tinggi maksimum. Menghantar dua argumen sahaja gagal pada peringkat kompil dengan Too few arguments in function call, dan menghantar sifar sebagai tinggi gagal pada runtime dengan height has to be a none negative number. Yang berfungsi ialah rentetan kosong, yang bermaksud kekalkan nisbah aspek.
imej = imageNew("", 1600, 900, "rgb", "2b6cb0");
imageScaleToFit(imej, 400, "");
writeOutput("thumb: " & imageGetWidth(imej) & "x" & imageGetHeight(imej) & "<br>");
segi = imageNew("", 1600, 900, "rgb", "2b6cb0");
sisi = min(imageGetWidth(segi), imageGetHeight(segi));
imageCrop(segi, int((imageGetWidth(segi) - sisi) / 2), int((imageGetHeight(segi) - sisi) / 2), sisi, sisi);
imageScaleToFit(segi, 400, 400);
writeOutput("kad: " & imageGetWidth(segi) & "x" & imageGetHeight(segi) & "<br>");
Imej 1600x900 menjadi 400x225, manakala imageResize(imej, 400, 400) memaksa kedua-dua dimensi dan menjadikan imej penyek. Untuk kad segi empat sama, potong dahulu dengan imageCrop di tengah kemudian kecilkan, kerana mengecilkan dahulu menghasilkan piksel yang lebih lembut.
Bagaimana menulis tera air teks yang betul?
Kuncinya ialah urutan. Ketelusan mesti ditetapkan sebelum sesuatu dilukis, bukan selepasnya. Apabila ditetapkan dahulu, jalur hitam pada ketelusan 55 di atas latar biru menghasilkan biru gelap, bukan hitam pekat: pada rig, piksel jalur berubah daripada -13931344 kepada -15189151, iaitu kira-kira 55 peratus warna asal dikekalkan.
imej = imageNew("", 1600, 900, "rgb", "2b6cb0");
lebar = imageGetWidth(imej);
tinggi = imageGetHeight(imej);
tinggiJalur = max(60, int(tinggi * 0.08));
imageSetDrawingTransparency(imej, 55);
imageSetDrawingColor(imej, "000000");
imageDrawRect(imej, 0, tinggi - tinggiJalur, lebar, tinggiJalur, true);
imageSetDrawingTransparency(imej, 0);
imageSetDrawingColor(imej, "ffffff");
imageDrawText(imej, "Lucee Malaysia", 40, tinggi - 18, {font: "Arial", size: 34, style: "bold"});
writeOutput("jalur: " & imageGetBufferedImage(imej).getRGB(500, tinggi - 50) & "<br>");
Nilai 0 pada panggilan kedua mengembalikan lukisan kepada legap, jadi teks kelihatan jelas di atas jalur separa lutsinar. Tanpa panggilan itu, teks juga ditulis pada 55 peratus dan sukar dibaca pada foto yang terang.
Perangkap yang paling kerap menimpa ialah mencipta lapisan argb dengan warna latar, kemudian menetapkan ketelusan selepas itu, lalu menampalnya. Lapisan itu kekal legap walaupun imageSetDrawingTransparency dipanggil, dan hasil tampalan ialah jalur hitam pekat: alpha dibaca sebagai 255 dan piksel menjadi -16777216. Warna latar semasa imageNew dan imageClearRect tidak termasuk dalam lukisan yang terjejas oleh ketelusan.
Bagaimana menampal logo sebagai tera air?
Untuk logo, imagePaste ialah alat yang betul, dengan syarat lapisan logo benar-benar membawa saluran alpha. Pada rig, teks yang dilukis pada lapisan argb selepas ketelusan 50 ditetapkan menghasilkan piksel glif dengan alpha 128, dan tampalan itu bercampur dengan foto: piksel sasaran berubah daripada -13931344 kepada -6965672, bukan menjadi kuning penuh.
imej = imageNew("", 1600, 900, "rgb", "2b6cb0");
lapis = imageNew("", 400, 120, "argb");
imageSetDrawingTransparency(lapis, 50);
imageSetDrawingColor(lapis, "ffff00");
imageDrawText(lapis, "TERA", 10, 85, {font: "Arial", size: 56, style: "bold"});
imagePaste(imej, lapis, imageGetWidth(imej) - 440, imageGetHeight(imej) - 160);
hasil = imageGetBufferedImage(imej);
writeOutput("piksel: " & hasil.getRGB(1170, 784) & "<br>");
Kedudukan dikira daripada saiz imej dan saiz logo, jadi kod yang sama berfungsi untuk foto menegak dan melintang tanpa nilai tetap. Kalau logo perlu lebih halus, kecilkan logo itu sendiri, bukan keseluruhan foto, kerana mengecilkan foto merosakkan butiran yang hendak dilindungi.
Satu had yang perlu diingat: imageOverlay hanya menerima dua argumen. Panggilan dengan empat argumen untuk meletakkan kedudukan membaling Too many arguments (2:4) in function call [imageOverlay], jadi gunakan imagePaste apabila kedudukan perlu dikawal.
Berapa besar fail WebP berbanding JPEG?
WebP boleh ditulis terus oleh enjin, dan saiznya jauh lebih kecil. Inilah angka pada rig untuk thumbnail 400x225 daripada imej ujian yang sama, kedua-duanya pada kualiti 0.85:
| Ukuran | Saiz fail |
|---|---|
| WebP 400x225, kualiti 0.85 | 4762 bait |
| JPEG 400x225, kualiti 0.85 | 12514 bait |
| JPEG 800x450, kualiti 0.95 | 36631 bait |
| JPEG 800x450, kualiti 0.60 | 17602 bait |
| JPEG 800x450, kualiti 0.40 | 14839 bait |
Angka ini bergantung pada kandungan imej, jadi jangan jadikannya sasaran mutlak. Yang kekal benar ialah urutan saiz: WebP pada kualiti sederhana mengalahkan JPEG, dan menurunkan kualiti JPEG daripada 0.95 kepada 0.60 menjimatkan lebih separuh saiz pada imej bertekstur. Nilai kualiti mesti antara 0 dan 1; integer seperti 82 ditolak dengan third Argument [quality] is invalid, value have to be between 0 and 1.
Pelayar menyokong WebP, tetapi og:image untuk WhatsApp dan Facebook lebih selamat dalam JPEG, jadi simpan kedua-duanya dengan nama asas yang sama.
Kenapa foto telefon muncul senget walaupun failnya betul?
Kerana telefon menyimpan orientasi dalam EXIF, bukan dalam susunan piksel, dan Lucee membaca nilai itu semasa imej dimuatkan. Buktinya diukur pada rig: fail 400x300 yang ditulis dengan Orientation=6 dibaca oleh imageNew sebagai 300x400, dan imageInfo memulangkan width 300 serta height 400 berserta kunci Orientation bernilai 6.
Maksudnya, jangan tambah imageRotate untuk membetulkan foto telefon. Putaran manual akan memutarkan imej yang sudah diputarkan, dan hasilnya senget ke arah lain. Kalau nilai EXIF itu sendiri diperlukan, imageGetEXIFMetadata(imej) memulangkan struct dengan kunci exif, gps, Orientation dan medan kamera yang lain.
Risiko sebenar bukan orientasi, tetapi format. Fail HEIC tiada penyahkod dalam enjin, dan fail yang bukan imej membaling MultiException dengan mesej No SOF segment in stream. Kedua-duanya mesti ditangkap dengan cftry sebelum dipaparkan kepada pelawat, dan artikel muat naik fail dengan selamat membincangkan bahagian penerimaan fail itu dengan lebih teliti.
Berapa lama masa menjana satu thumbnail?
Menjana 20 thumbnail daripada imej 1600x900 kepada 400x225 mengambil 1893 milisaat pada rig, iaitu sekitar 95 milisaat untuk setiap satu, termasuk membaca JPEG asal, mensampel semula dan menulis semula ke cakera. Larian berasingan dengan 40 imej mengambil 3885 milisaat, jadi angkanya konsisten.
Seratus gambar bermakna sekitar sepuluh saat kerja CPU. Itu munasabah untuk kerja latar, tetapi terlalu mahal untuk setiap permintaan halaman. Corak yang betul ialah menjana sekali semasa muat naik, menyimpan hasilnya, dan menyemak kewujudan fail sebelum menjana semula. Kalau dua permintaan tiba serentak untuk gambar yang sama, kedua-duanya akan menjana thumbnail yang sama, jadi kerja itu perlu dikunci dengan cflock atau dijadikan kerja giliran. Perbincangan lanjut tentang menyimpan hasil ada dalam panduan caching dan prestasi.
Untuk gambaran umum tentang fungsi imej yang lain, termasuk membaca daripada storan luar dan menjana captcha, artikel memproses imej dalam CFML menyediakan peta yang lebih luas.
Soalan Lazim
Adakah cfimage dalam Lucee mempunyai action watermark?
Tidak. Action yang sah hanya border, captcha, convert, info, read, resize, rotate, write dan writeToBrowser. Tera air dibina dengan imageSetDrawingTransparency untuk jalur dan teks, atau dengan imagePaste untuk logo yang mempunyai saluran alpha.
Bolehkah saya guna imageResize untuk membuat thumbnail?
Boleh, tetapi hasilnya herot kalau lebar dan tinggi tidak mengikut nisbah aspek asal. imageScaleToFit dengan rentetan kosong pada argumen ketiga mengekalkan nisbah, manakala imageResize memaksa kedua-dua dimensi yang diberi.
Kenapa jalur tera air saya menjadi hitam pekat, bukan separa lutsinar?
Kerana ketelusan ditetapkan selepas lapisan itu diisi. Lapisan argb yang diisi semasa imageNew atau melalui imageClearRect kekal legap dengan alpha 255. Tetapkan imageSetDrawingTransparency dahulu, kemudian lukis jalur pada imej yang sama.
Perlukah saya putarkan foto telefon secara manual?
Tidak. Lucee membaca EXIF Orientation dan memutarkan imej semasa bacaan, jadi fail 400x300 dengan orientasi 6 muncul sebagai 300x400. Putaran manual akan memutarkan imej dua kali.
Format apa yang patut saya tulis, WebP atau JPEG? Tulis kedua-duanya. WebP lebih kecil untuk paparan halaman, manakala JPEG lebih selamat untuk pratonton pautan. Pada ujian ini, thumbnail 400x225 menjadi 4762 bait dalam WebP berbanding 12514 bait dalam JPEG.
Sumber
- Dokumentasi tag
cfimage: https://docs.lucee.org/reference/tags/image.html imageScaleToFit: https://docs.lucee.org/reference/functions/imagescaletofit.htmlimagePaste: https://docs.lucee.org/reference/functions/imagepaste.htmlimageSetDrawingTransparency: https://docs.lucee.org/reference/functions/imagesetdrawingtransparency.htmlimageWrite: https://docs.lucee.org/reference/functions/imagewrite.htmlimageInfodanimageGetEXIFMetadata: https://docs.lucee.org/reference/functions/imageinfo.html