ompdf是一個可以將HTML生成PD并保留樣式效果的PHP第三方擴展。
下面就一步步講解如何使用:
一、通過composer安裝
composer require dompdf/dompdf
安裝過程
二 、編寫測試代碼
(1)引用autoload.php
include 'vendor/autoload.php';
(2)實例化Dompdf
$dompdf=new \Dompdf\Dompdf();
(3)加載HTML
$dompdf->loadHtml($html); //$html 為HTML字符串
(4)設置紙張和方向
$dompdf->setPaper('A4', 'landscape'); //紙張大小和紙張方向
(5)生成PDF并下載
$dompdf->render();
$dompdf->stream('數據字典.pdf');
三、導出PDF測試,發現中文亂碼了
導出PDF發現中文亂碼了
四、解決中文亂了問題
(1)下載支持中文的字體包放到根目錄下(和vendor目錄同級),這里演示使用的是阿里巴巴的普惠字體(字體格式是ttf的,小編原先下載使用的字體格式是otf格式的無效)
(2)下載dompdf字體安裝工具解壓到根目錄(和vendor目錄同級)
下載地址:https://github.com/dompdf/utils
(3)在命令行(CMD定位到根目錄)下執行命令
php load_font.php "puhui" Alibaba-PuHuiTi-Light.ttf
執行成功后在路徑(vendor\dompdf\dompdf\lib\fonts)下就會出現剛才的字體
(4)在樣式文件中指定使用剛才安裝的字體
body{font-family:puhui;}
(5)再次導出PDF測試成功
亂碼問題解決
近臨近開學了,大家都在忙著準備各種學習的資料,準備在新的學期好好學習,充實自己。小編身邊的同學也是如此,最近,小編的同學小麗就遇到了一個很棘手的問題。
她想將一個網頁的Python學習的教程打印下來,方便自己來學習,但是上千頁的教程,如果通過手動的方式,一個一個的去轉成pdf并保存到本地,實在是麻煩的不。
這就是一個html轉pdf的問題,其實網上有很多不錯的html資源,但是苦于學習起來,不方便!于是小編就跟小麗保證,這點小事包在我身上。今天,小編就跟分享一下如何用Python把html資料變成pdf。
如今網上的在線學習資料可謂是多如牛毛,為了方便講解,小編就利用python3.9.2的中文文檔作為演示的例子,來將其抓取并保存到本地,其網頁鏈接如下:
https://docs.python.org/zh-cn/3.9/tutorial/index.html
打開上述鏈接后,大家會在網頁中找到不同內容的鏈接地址,包括了基礎的python字符、python語法等內容。
在上圖中,我們需要格外關注的是紅色方格標注的鏈接,每個鏈接都會跳轉到對應的子網頁中,而在子網頁中,就是我們想要保存的內容。
可以看到,上圖中,在python速覽子頁面中,包含了我們需要提取的文字內容。所以將html內容保存為pdf的第一步便是獲取到子頁面的鏈接。由于教程大都是固定內容,因此對于教程的網頁,大都采用的是靜態頁面,在網頁源代碼中可以很輕松地找到子頁面的網頁鏈接。
對于子網頁的鏈接抓取,程序如下圖所示:
程序中,通過BeautifulSoup庫來解析網頁源代碼,然后提取所有的子頁面鏈接地址并返回,如果抓取失敗,則直接返回None。
03.html轉pdf
在得到子網頁的鏈接后,接下來就是將html的子網頁保存為pdf文件。小編使用的pdfkit庫,pdfkit庫可以將網頁保存為pdf文檔。首先小編來介紹一下pdfkit庫的安裝。
按照上述的操作流程,就可以安裝pdfkit庫。對于pdfkit庫的使用,常見的用法有以下三種:
上面的程序主要完成以下幾步:
首先需要指定wkhtmltopdf.exe文件的路徑;
因此,pdfkit庫只能將子網頁保存為單獨的pdf文檔,無法直接通過pdfkit庫將所有的子網頁拼接成一個完整的pdf文檔,小編通過PyPDF2庫中的PdfFileMerger類來實現pdf文檔的拼接。程序如下圖所示。
程序中首先將所有的html網頁保存為單獨的pdf文檔,然后通過PdfFileMerger類對象來實現pdf文檔的拼接。最后就可以得到全部的pdf內容。最后我們通過視頻的展示,來看一下程序的效果吧。
除此之外,程序不光可以抓取python3.9的中文文檔,針對其他的在線文檔,只需要對獲取網頁鏈接的程序進行修改即可抓取,例如對于Flask中文文檔的抓取,程序只需要按照下圖進行修改,即可將Flask的在線文檔保存為PDF文檔。
學習Python其實非常有趣,也很有用。因為Python有大量的現成的庫,可以幫助我們把工作中的很多瑣碎的煩事輕松解決。小編將上述的程序稍加修改,很快就幫阿麗搞定了教程,保存為pdf發送給了她,小編與女神的關系更拉近了一步
近碰到個需求,需要把當前頁面生成 pdf,并下載。弄了幾天,自己整理整理,記錄下來,我覺得應該會有人需要 :)
項目源碼地址:https://github.com/linwalker/render-html-to-pdf
我們可以直接在瀏覽器端使用html2canvas,對整個或局部頁面進行“截圖”。但這并不是真的截圖,而是通過遍歷頁面DOM結構,收集所有元素信息及相應樣式,渲染出canvas image。
由于html2canvas只能將它能處理的生成canvas image,因此渲染出來的結果并不是100%與原來一致。但它不需要服務器參與,整個圖片都由客戶端瀏覽器生成,使用很方便。
使用
使用的API也很簡潔,下面代碼可以將某個元素渲染成canvas:
html2canvas(element, { onrendered: function(canvas) { // canvas is the final rendered <canvas> element } });
通過onrendered方法,可以將生成的canvas進行回調,比如插入到頁面中:
html2canvas(element, { onrendered: function(canvas) { document.body.appendChild(canvas); } });
做個小例子(demo1)代碼如下:
這個例子將頁面body中的元素渲染成canvas,并插入到body中。
jsPDF庫可以用于瀏覽器端生成PDF。
使用方法如下:
// 默認a4大小,豎直方向,mm單位的PDF var doc = new jsPDF(); // 添加文本‘Download PDF’ doc.text('Download PDF!', 10, 10); doc.save('a4.pdf');
// 三個參數,第一個方向,第二個尺寸,第三個尺寸格式 var doc = new jsPDF('landscape','pt',[205, 155]) // 將圖片轉化為dataUrl var imageData = ‘data:image/png;base64,iVBORw0KGgo...’; //設置字體大小 doc.setFontSize(20); //10,20這兩參數控制文字距離左邊,與上邊的距離 doc.text('Stone', 10, 20); // 0, 40, 控制文字距離左邊,與上邊的距離 doc.addImage(imageData, 'PNG', 0, 40, 205, 115); doc.save('a4.pdf')
生成pdf需要把轉化的元素添加到jsPDF實例中,也有添加html的功能,但某些元素無法生成在pdf中,因此可以使用html2canvas + jsPDF的方式將頁面轉成pdf。通過html2canvas將遍歷頁面元素,并渲染生成canvas,然后將canvas圖片格式添加到jsPDF實例,生成pdf。
單頁
將demo1的例子修改下:
如果頁面內容根據a4比例轉化后高度超過a4紙高度呢,生成的pdf會怎么樣?會分頁嗎?
你可以試試,驗證一下自己的想法。
jsPDF提供了一個很有用的API, addPage(),我們可以通過 pdf.addPage(),來添加一頁pdf,然后通過 pdf.addImage(...),將圖片賦予這頁pdf來顯示。
那么我們如何確定哪里分頁?
這個問題好回答,我們可以設置一個 pageHeight,超過這個高度的內容放入下一頁pdf。
來捋一下思路,將html頁面內容生成canvas圖片,通過 addImage將第一頁圖片添加到pdf中,超過一頁內容,通過 addPage()添加pdf頁數,然后再通過 addImage將下一頁圖片添加到pdf中。
嗯~,很好!巴特,難道沒有發現問題嗎?
這個方法實現的前提是 — — 我們能根據 pageHeight先將整頁內容生成的canvas圖片分割成對應的小圖片,然后一個蘿卜一個坑,一頁一頁 addImage進去。
What? 想一想我們的canvas是腫么來的,不用拉上去,直接看下面:
html2canvas(document.body, { onrendered:function(canvas) { //it is here we handle the canvas } })
這里的 body就是要生成canvas的元素對象,一個元素生成一個canvas;那么我們需要一頁一頁的canvas,也就是說。。。
你覺得可能嗎? 我覺得不太現實,按這思路要獲取頁面上不同位置的DOM元素,然后通過 htnl2canvas(element,option)來處理,先不說能不能剛好在每個 pageHeight的位置剛好找到一個DOM元素,就算找到了,這樣做累不累。
累的話 :)可以看看下面這種方法。
我提供的思路是我們只生成一個canvas,對就一個,轉化元素就是你要轉成pdf內容的母元素,在這篇demo里就是 body了;其他不變,也是超過一頁內容就 addPage,然后 addImage,只不過這里添加的是同一個canvas。
當然這樣做只會出現多頁重復的pdf,那到底怎么實現正確分頁顯示。其實主要利用了jsPDF的兩點:
雖然每一頁pdf上顯示的圖片是相同的,但我們通過調整圖片的位置,產生了分頁的錯覺。以第二頁為例,將豎直方向上的偏移設置為 -841.89即一張a4紙的高度,又因為超過a4紙高度范圍的圖片不顯示,所以第二頁顯示了圖片豎直方向上[841.89,1682.78]范圍內的內容,這就得到了分頁的效果,以此類推。
還是看代碼吧:
修改imgWidth,并且在addImage時x方向參數設置你要的邊距,具體代碼如下:
作者:linwalkerhttps://segmentfault.com/a/1190000009211079
*請認真填寫需求信息,我們會在24小時內與您取得聯系。