↓ 快轉到主要內容
html to pdf 輸出最漂亮的完整PDF
技術文章DockerLaravel

html to pdf 輸出最漂亮的完整PDF

Posted by Alvin Chen on

html to pdf 輸出最漂亮的完整PDF

·1180 字·3 分鐘
作者
Alvin Chen
相信寫 Code 可以改變世界

前陣子才介紹過透過puppeteer來將網頁儲存成PDF檔案,如果還沒看過可以參考

puppeteer docker image 中文網頁產生PDF

本篇要更新的部分有兩個

  1. 透過GoogleChromeLabs 提供的puppeteer as a service docker image ,可以不必再處理中文問題
  2. 網址直接輸出PDF的列印格式通常不會太漂亮的解決方案

參考連結

https://github.com/GoogleChromeLabs/pptraas.com

https://hub.docker.com/r/minuux/pptraas.com

首先pptraas.com直接可以支援中文輸出,沒有語系上的問題

docker run -d -p 9999:8080 minuux/pptraas.com

完成後就可以在9999 port上使用,經過測試無論是直接輸出PDF還是畫面截圖,皆可以正確顯示中文字

接著,該如何完整個將畫面完整的輸出到PDF上而不會跑版或者背景、圖片不見之類的狀況呢?

這次,我會使用到pptraas.com所提供的兩個方法

  1. Render page as a PNG
  2. Render page as PDF

因為puppeteer所提供的page to pdf 方法是透過chrome的列印成PDF功能來實現,所以有很多狀況會變成這樣子,我們用一個例子來看

原本的畫面是這樣子

mamigogo
mamigogo

而我們直接從chrome按下列印,看到的預覽畫面就是puppeteer所產生的PDF檔

會變成這樣子

mamigogo
mamigogo

雖然可以很快的產生PDF檔,但是這樣子的內容格式根本不是我要的,接下來就來想辦法把格式保留下來產生PDF吧

首先!概念上是這樣子的,要保留樣式我們透過截圖的方式把圖片存下來,最後再將各分頁多張圖片合併輸出成PDF,當然你也可以直接截圖整頁,不做紙張分頁也是可以完整保留內容樣式的

我們從pptraas.com提供的範例中知道如何將url轉換成截圖

https://pptraas.com/screenshot?url=https://developers.google.com&size=400,400

重點有兩個

  1. size=650,850 這樣截下來的圖剛好可以塞進A4大小中,如果你有其他紙張大小需求也可以自行調整
  2. 網址回傳的內容是PNG圖檔內容,所以我將圖片內容透過base64_encode存下來放到cache

下面是一段laravel的範例

$url = env('PPTRAAS_URL').'screenshot?size=650,850&url=THE_URL_YOU_WANT_TO_PRINT';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec($ch);
curl_close($ch);

$images = base64_encode($output);
$uuid = Str::uuid()->toString();
//把base64 image放到快取中,並設定life time只有一分鐘
Cache::put('pdf_images_'.$uuid, $images, now()->addMinutes(1));

範例中,我把pptraas.com docker image 的url放在env中方便使用,並且將網址截圖後放到cache中

接著你需要另一個URL來產生剛剛截好圖的PDF,而這個頁面很簡單,只需要將cache中的圖檔拿出來放好就行了

以下是laravel blade的範例

<style>
    @media print {
        .pagebreak { page-break-before: always; } /* page-break-after works, as well */
    }
</style>
@foreach($images as $k =>$v)
    <img src="data:image/png;base64,{{$v}}" style="width:800px;">
    @if($k != count($images)-1)
        <div class="pagebreak"> </div>
    @endif
@endforeach

範例中呈現的是多張images轉存成一份PDF的概念,因此在每一張圖的最後加上<div class=“pagebreak”> </div>來達成換頁

但是最後一張圖就不需要再加入換頁了

最終,這個頁面會把你產生的base64圖檔全部排列出來,然後我們就可以透過這個網址來產生PDF了

https://pptraas.com/pdf?url=THE_URL_ABOVE

透過上面的網址一樣使用curl來呼叫,你可以得到一個PDF內容

接著只要把內容return 回去就可以下載啦

$fileName = 'THE PDF NAME YOU WANT';
return response($output, 200, [
       'Content-Type' => 'application/json',
       'Content-Disposition' => 'attachment; filename="'.$fileName.'.pdf"',
]);

範例中,$output就是上面網址產生的PDF內容

以上,就可以把URL內容輕鬆轉換成PDF了