Tutorial Pasukan Lucee MY

cfpdf: gabung, pecah dan ekstrak teks PDF

Panduan tag cfpdf dalam Lucee: gabung, pecah dan ekstrak teks PDF, baca metadata, kunci kata laluan dan tampal tera air, dengan contoh CFML yang diuji.

cfpdf: gabung, pecah dan ekstrak teks PDF
0
Kandungan

cfpdf ialah tag CFML untuk memanipulasi fail PDF yang sudah wujud. Dengan satu tag ini anda boleh menggabungkan beberapa PDF menjadi satu dokumen, mengekstrak semua teks daripadanya, membaca metadata seperti bilangan halaman dan pengarang, mengunci dokumen dengan kata laluan, dan menampal tera air. Artikel ini mengajar semua itu dalam bentuk tag, dan menyatakan dengan jujur di mana sempadannya: fungsi sepadan seperti pdfMerge(), pdfSplit() dan pdfExtractText() tidak wujud dalam teras Lucee dan memerlukan sambungan PDF.

Apa itu cfpdf, dan bezanya dengan cfdocument

Ramai yang keliru antara dua tag ini kerana kedua-duanya berkaitan PDF, tetapi tugasnya bertentangan. cfdocument menjana PDF baharu daripada HTML atau CFML, manakala cfpdf mengambil PDF yang sudah wujud dan mengubahnya. Analoginya mudah: cfdocument ialah mesin cetak yang mencipta dokumen, cfpdf ialah meja kerja yang memotong, menyusun dan menyusun semula kertas yang sudah dicetak.

Pemisahan ini penting secara praktikal. Kalau anda mahu menghasilkan invois daripada templat, itu kerja cfdocument, dan kami sudah membincangkannya secara terperinci dalam panduan cfdocument untuk Lucee. Kalau anda mahu menggabungkan tiga invois bulanan menjadi satu fail untuk dihantar kepada akauntan, mengekstrak teks untuk indeks carian, atau mengunci PDF sebelum dimuat naik, itu kerja cfpdf. Jangan campurkan kedua-duanya dalam satu kepala: jana dahulu dengan cfdocument, manipulasi kemudian dengan cfpdf.

Bentuk tag lawan bentuk fungsi

Satu fakta yang sering mengejutkan pembangun Lucee ialah laluan tag dan laluan fungsi PDF tidak sama lengkap. Tag <cfpdf> berjalan dalam enjin Lucee teras tanpa pemasangan tambahan, dan setiap tindakan dalam artikel ini diuji dalam Lucee 7.1. Tetapi fungsi CFML yang namanya kelihatan sepadan, iaitu pdfMerge(), pdfSplit() dan pdfExtractText(), tidak wujud dalam teras. Memanggilnya memulangkan ralat No matching function dan memerlukan pemasangan sambungan PDF Lucee untuk Jakarta EE.

Oleh sebab itu artikel ini mengajar bentuk tag secara konsisten. Ini bukan pilihan gaya semata-mata: bentuk tag ialah laluan yang berfungsi dalam pemasangan teras, manakala bentuk fungsi ialah laluan yang memerlukan sambungan. Sebelum memulakan projek PDF dalam Lucee, semak dahulu sama ada pelayan anda memasang sambungan PDF, supaya anda tahu laluan mana yang terbuka.

Sediakan PDF ujian dan gabungkan dengan action="merge"

action="merge" menggabungkan beberapa PDF menjadi satu dokumen. Dua atribut utamanya ialah directory, yang menunjukkan folder yang mengandungi fail sumber, dan destination, iaitu laluan fail PDF gabungan. Semua PDF di dalam folder sumber akan disertakan, jadi pastikan folder itu hanya mengandungi dokumen yang ingin digabungkan.

Contoh di bawah menjana dua PDF ujian dengan cfdocument ke dalam subfolder sumber, kemudian menggabungkannya menjadi laporan.pdf di luar subfolder itu supaya arahan ini boleh dijalankan berulang kali tanpa memasukkan fail hasil ke dalam gabungan berikutnya:

<cfset dir = "/tmp/uji-cfpdf">
<cfset sumber = "#dir#/sumber">
<cfif not directoryExists(sumber)>
    <cfdirectory action="create" directory="#sumber#" recurse="true">
</cfif>

<cfdocument format="pdf" filename="#sumber#/depan.pdf" overwrite="true">
    <h1>Kulit Depan</h1>
    <p>Halaman pertama laporan.</p>
</cfdocument>
<cfdocument format="pdf" filename="#sumber#/isi.pdf" overwrite="true">
    <h1>Isi Laporan</h1>
    <p>Halaman kedua laporan.</p>
</cfdocument>

<cfpdf action="merge" directory="#sumber#" destination="#dir#/laporan.pdf" overwrite="true">

<cfoutput>laporan wujud: #fileExists("#dir#/laporan.pdf")#</cfoutput>

overwrite="true" membenarkan fail hasil ditimpa pada larian berikutnya. Susunan halaman dalam PDF gabungan mengikut susunan fail di dalam folder sumber, jadi namakan fail dengan awalan nombor seperti 01-depan.pdf, 02-isi.pdf kalau susunan itu penting.

Ekstrak teks dan baca metadata

action="extractText" menyalin semua teks daripada PDF ke dalam satu pemboleh ubah rentetan melalui atribut name, manakala action="getInfo" memulangkan struktur metadata dokumen: bilangan halaman, pengarang, tajuk, subjek, kata kunci, tarikh dicipta dan diubah, serta saiz halaman. Kedua-duanya ialah tindakan baca, jadi wajar digabungkan dalam satu langkah.

<cfset dir = "/tmp/uji-cfpdf">

<cfpdf action="extractText" source="#dir#/laporan.pdf" name="teks">
<cfpdf action="getInfo" source="#dir#/laporan.pdf" name="maklumat">

<cfoutput>
    Bilangan halaman: #maklumat.totalPages#<br>
    Panjang teks: #len(teks)# aksara<br>
    <pre>#encodeForHTML(teks)#</pre>
</cfoutput>

Tiga perkara perlu diberi perhatian. Pertama, nama tindakan metadata ialah getInfo, bukan info; action="info" memulangkan ralat Invalid PDF action. Kedua, extractText hanya membaca lapisan teks yang wujud dalam PDF, jadi dokumen imbasan tanpa lapisan teks memulangkan rentetan kosong dan memerlukan OCR luar. Ketiga, susunan teks yang dipulangkan tidak semestinya sama dengan susunan visual pada halaman, terutamanya untuk dokumen berbilang lajur. Teks yang diekstrak boleh disimpan terus ke fail dengan cffile, seperti yang diterangkan dalam membaca dan menulis fail dengan cffile.

Pecah PDF: tiada tindakan split dalam Lucee

Di sinilah anda perlu berhati-hati dengan rujukan yang anda baca. Lucee tidak mempunyai tindakan split pada cfpdf; action="split" memulangkan Invalid PDF action, dan fungsi pdfSplit() juga tiada dalam teras. Cara yang berfungsi untuk memecah PDF kepada halaman individu ialah gabungan getInfo dan deletePages: kira jumlah halaman dahulu, kemudian untuk setiap halaman, buang semua halaman lain dan simpan hasilnya sebagai fail baharu.

<cfset dir = "/tmp/uji-cfpdf">

<cfpdf action="getInfo" source="#dir#/laporan.pdf" name="maklumat">

<cfloop from="1" to="#maklumat.totalPages#" index="i">
    <cfset buang = "">
    <cfloop from="1" to="#maklumat.totalPages#" index="j">
        <cfif j neq i>
            <cfset buang = listAppend(buang, j)>
        </cfif>
    </cfloop>
    <cfpdf action="deletePages" source="#dir#/laporan.pdf" pages="#buang#" destination="#dir#/halaman-#i#.pdf" overwrite="true">
</cfloop>

<cfoutput>halaman 1: #fileExists("#dir#/halaman-1.pdf")#; halaman 2: #fileExists("#dir#/halaman-2.pdf")#</cfoutput>

deletePages menerima senarai nombor halaman yang hendak dibuang melalui atribut pages, jadi gelung di atas membina senarai semua halaman kecuali halaman yang ingin dikekalkan. Untuk PDF besar pendekatan ini tidak sepantas tindakan pecah khusus, tetapi ia berfungsi sepenuhnya dalam teras tanpa sambungan, dan itulah pertukaran yang jujur.

Kunci dan tera air PDF

action="protect" menyulitkan PDF dan menetapkan dua kata laluan: newUserPassword untuk sesiapa yang membuka dokumen, dan newOwnerPassword untuk pemilik yang mahu mengubah kebenaran. action="addWatermark" pula menampal imej pada setiap halaman, dan ia tidak menerima teks terus sebagai tera air; anda mesti menyediakan imej melalui atribut image, seperti contoh di bawah yang mencipta imej teks DRAF dengan fungsi imej teras.

<cfset dir = "/tmp/uji-cfpdf">

<cfpdf action="protect"
    source="#dir#/laporan.pdf"
    destination="#dir#/laporan-kunci.pdf"
    newUserPassword="rahasia123"
    newOwnerPassword="pemilik123"
    permissions="all"
    overwrite="true">

<cfset cap = imageNew("", 300, 80, "rgb", "white")>
<cfset imageDrawText(cap, "DRAF", 20, 50, {font="Arial", size=36, style="bold", color="red"})>
<cfset imageWrite(cap, "#dir#/cap.png", true)>

<cfpdf action="addWatermark"
    source="#dir#/laporan.pdf"
    destination="#dir#/laporan-cap.pdf"
    image="#dir#/cap.png"
    opacity="3"
    foreground="true"
    overwrite="true">

<cfoutput>kunci: #fileExists("#dir#/laporan-kunci.pdf")#; tera air: #fileExists("#dir#/laporan-cap.pdf")#</cfoutput>

Dua perangkap yang sering tersekat pembangun. Pertama, opacity dalam cfpdf menggunakan skala 0 hingga 10, bukan 0 hingga 100, jadi nilai 30 memulangkan ralat dan nilai yang betul untuk tera air samar ialah sekitar 2 hingga 4. Kedua, foreground="true" meletakkan tera air di hadapan kandungan supaya ia tidak tersembunyi di belakang elemen dokumen. Simpan kata laluan pemilik berasingan daripada kata laluan pengguna, dan untuk membuang kata laluan daripada PDF yang anda miliki, guna action="removePassword" dengan password pemilik.

Jadual rujukan tindakan cfpdf

Berikut ialah ringkasan tindakan yang dibincangkan, dengan nama yang tepat seperti yang diterima enjin:

TindakanKegunaan
mergeGabungkan berbilang PDF dalam satu folder menjadi satu dokumen
extractTextSalin semua teks PDF ke dalam satu pemboleh ubah rentetan
getInfoBaca metadata: bilangan halaman, pengarang, tajuk, saiz halaman (bukan info)
protectSulitkan PDF dan tetapkan kata laluan pengguna serta pemilik
addWatermarkTampal tera air imej pada halaman, dengan kelegapan dan kedudukan
pecah halaman (via deletePages)Tiada tindakan split; asingkan satu halaman dengan membuang halaman lain

Dua baris terakhir perlu ditegaskan kerana rujukan pihak ketiga sering menulis info dan split seolah-olah ia tindakan yang sah. Dalam Lucee kedua-duanya memulangkan Invalid PDF action. Tulis getInfo untuk metadata, dan gunakan deletePages untuk memecah dokumen.

cfpdf dalam aliran kerja fail dan muat naik

cfpdf jarang digunakan bersendirian; ia biasanya satu langkah dalam aliran kerja fail yang lebih besar. Ia duduk bersebelahan tag manipulasi fail lain dalam CFML, antaranya cfzip untuk memampatkan dan mengekstrak arkib, seperti yang dibincangkan dalam panduan cfzip. Gabungan biasa ialah menjana beberapa PDF dengan cfdocument, menggabungkannya dengan cfpdf, kemudian memampatkannya dengan cfzip sebelum dihantar kepada pelanggan.

Apabila PDF datang daripada muat naik pengguna, gunakan getInfo sebagai lapisan pengesahan sebelum memprosesnya: semak bilangan halaman untuk menolak dokumen yang terlalu panjang, dan sahkan saiz fail sebelum menyimpannya. Amalan ini berjalan seiring dengan prinsip dalam panduan muat naik fail selamat, kerana fail PDF yang dimuat naik ialah input tidak dipercayai sama seperti arkib ZIP atau imej.

Soalan Lazim

Adakah cfpdf memerlukan sambungan PDF dalam Lucee?

Tindakan asas seperti merge, extractText, getInfo, protect, deletePages dan addWatermark berjalan dalam enjin teras tanpa sambungan, dan semuanya diuji dalam Lucee 7.1. Yang memerlukan sambungan PDF Lucee ialah bentuk fungsi seperti pdfMerge(), pdfSplit() dan pdfExtractText().

Kenapa tiada tindakan split dalam cfpdf?

Lucee tidak melaksanakan tindakan split. Untuk memecah PDF kepada halaman individu, kira bilangan halaman dengan getInfo, kemudian gunakan deletePages untuk membuang semua halaman kecuali satu, berulang untuk setiap halaman. Pendekatan ini berfungsi dalam teras tanpa sambungan.

Bagaimana hendak mengekstrak teks daripada PDF yang diimbas?

extractText hanya membaca lapisan teks yang wujud dalam PDF. Dokumen imbasan ialah imej tanpa lapisan teks, jadi hasilnya kosong. Untuk kes itu anda perlu menjalankan OCR dengan pustaka luar dahulu untuk membina lapisan teks, kemudian baharu extractText berfungsi.

Apakah perbezaan cfdocument dan cfpdf?

cfdocument menjana PDF baharu daripada HTML atau CFML, manakala cfpdf memanipulasi PDF yang sudah wujud. Jana dahulu dengan cfdocument, kemudian gabung, pecah, kunci atau tera air hasilnya dengan cfpdf. Rujuk panduan cfdocument untuk Lucee untuk bahagian penjanaan.

Bagaimana hendak membuka PDF yang dikunci dengan kata laluan?

cfpdf menyediakan action="removePassword" untuk membuang kata laluan daripada PDF, dengan syarat anda membekalkan kata laluan pemilik melalui atribut password. Tanpa kata laluan itu, PDF kekal terkunci dan anda perlu meminta pemilik dokumen.

Sumber

0 komen

Log masuk untuk menjawab atau memberi komen.

Log masuk