PDF 簡介
PDF 全稱Portable Document Format (PDF)(便攜文檔格式),該格式的顯示與操作系統、分辨率、設備等因素沒有關系,不論是在Windows,Unix還是在蘋果公司的Mac OS操作系統中PDF格式都通用。Adobe公司在1993年為了文檔傳輸創造了這個文件格式,這個格式使用PostScript頁面描述語言,適用於列印圖像和文字(無論是在紙、膠片或非物質的CRT都可)。PDF是基於頁面描述語言。它既可以像程序代碼一樣具有可讀性,又能表示出可任意放大和縮小的矢量圖。
PDF文件格式可以將文字、字型、格式、顏色及獨立於設備和分辨率的圖形圖像等封裝在一個文件中,該格式文件還可以包含超文本鏈接、聲音和動態影像等電子信息,支持特長文件,集成度和安全可靠性都較高。
為什么PDF 文件能夠如此盛行
很多人所吐槽,說PDF 既不能編輯,也不好復制內容,更無法直接轉換成Word,為什么要用PDF來傳輸資料呢?
殊不知,大家吐槽的缺點,正是因為它優點的過於強大而引起的。
PDF的產生之初的目的,是為了適應紙媒的印刷行業。PDF 原本並非為小屏幕電子閱讀設計的文件標准,它來自於印刷——基於紙張大小進行的排版。我們可以把它當成紙質文稿的電子化,非電子文本,而是電子化的印刷了東西的紙張。它存在的目的是為了實現批量精准的印刷,保證在多個屏幕,多個系統,多終端中文件格式都能保存相對位置,展示布局都不會出現格式錯亂,保證了打印到紙張上的格式完全一致,而不會內容格式面目而非。
試想,如果我們需要打印一份保險認購書,保險業務人員使用 iPad 打印的PDF 文件和使用PC 電腦打印出來的文件格式相差很大,頁數不一致,換行不一致,那到底如何保證保險認購書的法律效應呢。 一份保單可以有多種格式,那就無法信任任何一份保單了。正如你面前有多個時鍾,我們也就無法獲取當前准確時間。
如果你實現過類似於打印頁面,打印表單等功能,你可能會深有體會這其中的坑,吃過的苦只有自己清楚。
因為將網頁保存為PDF 讓用戶預覽或下載不失為一種保證格式在各終端一致的好方法。
除此之外,PDF 的優勢除了跨平台,兼容性高,也 最大程度降低了查看成本 ,終端用戶不需要安裝一套沉重全功能的Adobe才能讀到 PDF文件,只要客戶機器上有瀏覽器就可以查看PDF內容。這也就是終端用戶無論是手機端 iOS, Android,還是老的PC,新的PC機器都可以隨時隨地打開PDF 文件,支持閱讀的方式非常多樣便捷,而不是像Excel文件必須要office才能夠讀取。
再加上PDF 也可以進行小范圍的編輯,安全屬性的設置,如加密,加密打印等功能,實用性也是上升到另一個層次。
前端生成PDF 文件應用場景
隨着移動互聯網的發展,手機端增長需求暴增,互聯網系統越多越多,新型系統都是為了更方便快捷解決用戶而應用而生的,而用戶需求也隨着技術的發展悄然發生改變。
"全民皆網民"的階段,再不是基本功能滿足就可以站住腳的時代,用戶體驗及交互需求更加迫切,使得從機器時代的設計到人性化的設計,更加易用性。
前后端分離的技術架構暢行,讓專業的人做專業的事情,開發更加高效暢通,因此在前端生成和展示PDF文件的需求也是比較普遍,我們總結一下PDF的常見應用場景:
- 項目中預覽PDF 文件,並且提供搜索能力
- 手機端預覽PDF 文件
- 用戶填寫表單,生成PDF 文件,用戶直接下載保存
- 線上生成PDF 合同,打印
簡單總結生成 PDF 的三類需求:
- 在線預覽,直接打開現有的PDF文件進行瀏覽確認信息。
- 實現在線生成PDF文件,根據用戶的上下文信息,如新提交的表單信息,客戶信息,采購信息等即時生成個性化的PDF文件,供用戶查看或下載。
- 打印,將已有或已生成的PDF 文件直接打印。
在前端生成PDF 文件是非常普遍的需求,幾乎業務復雜的系統都會有這樣的要求。
前端生成PDF 文件難點
前端生成PDF文件的難點在於,前端純依賴於客戶端的瀏覽器資源,可用的資源有限制,終端多樣性,導致生成PDF 難度也比服務端增加了不少。以ActiveReportsJS前端報表控件為示例,它提供了前端的PDF 導出能力,但在導出PDF 文件之前,我們需要注意以下幾個問題:
- ActiveReportsJS組件是前端控件,整體運行都基於Web瀏覽器環境來運行。
- 桌面報表設計器 是基於 Electron使用Chromium來顯示用戶界面。
- Web 在線設計器 和 報表 viewer 組件在用戶計算機的瀏覽器中運行的 Web 應用程序。
- PDF, Excel 和 HTML 作為生成器,基於瀏覽器環境來測量並生成報表內容。
- 報表由文本內容組成,瀏覽器通過基於glyphs(字形)來渲染的字體形狀。字體資源包含將字符編碼映射到代表這些字符的字形的信息。因此,瀏覽器需要訪問正確的字體資源,才能夠按照預期顯示文本。
因此在前端生成PDF有三座大山需要克服:
- 瀏覽器。瀏覽器可謂百家齊鳴,不過現在的主流瀏覽器數量也還好,不過三四家而已,如Chrome, FireFox,Safari,Edge,瀏覽器,當然還有國內稱霸的360瀏覽器。每個瀏覽器對於文字內容,甚至CSS 屬性處理都不一致,而正因為各家有各家的標准,會出現我們在Chrome中可以正常使用所有功能,而火狐使用PDF時,內容無法正常顯示,但打印功能正常。
- 分辨率。如果要列出天下所有的分辨率,恐怕一張A3紙都無法完全輸出了,如果基於Dom 渲染的網頁,遇到分辨率差異大的終端,那么放大縮小的問題完全無法解決。
- 字體。英文和數字等Unicode字符都可以保證PDF 正常顯示,但如果頁面中包含中文字符,在生成PDF 時是基於字形繪制的,如果提供的字形與實際頁面展示的字形不一致,那導致生成PDF並不是所見即所得的效果,可能對於一些格式要求比較嚴格的文件,精確到換行字符,行數,邊距等都會是災難性問題,因此提供正確的字體也是PDF生成時,保證格式一致是最重要的一點。
常用的前端生成PDF 文件方法
方法一
html2canvas+ jsPdf的方法將HTML 轉換成圖片后,在將圖轉PDF文件
適用場景:適用單頁PDF文件,且終端設備一致
示例代碼:
HTML:
<html>
<body>
<header>This is the header</header>
<div id="content">
This is the element you only want to capture
</div>
<button id="print">Download Pdf</button>
<footer>This is the footer</footer>
</body>
</html>
CSS:
body {
background: beige;
}
header {
background: red;
}
footer {
background: blue;
}
#content {
background: yellow;
width: 70%;
height: 100px;
margin: 50px auto;
border: 1px solid orange;
padding: 20px;
}
JS:
$('#print').click(function() {
var w = document.getElementById("content").offsetWidth;
var h = document.getElementById("content").offsetHeight;
html2canvas(document.getElementById("content"), {
dpi: 300, // Set to 300 DPI
scale: 3, // Adjusts your resolution
onrendered: function(canvas) {
var img = canvas.toDataURL("image/jpeg", 1);
var doc = new jsPDF('L', 'px', [w, h]);
doc.addImage(img, 'JPEG', 0, 0, w, h);
doc.save('sample-file.pdf');
}
});
})
缺點:
- 生成的PDF文件由圖片構成,內容無法拷貝,放大后不清晰
- 分頁打印位置無法控制
方法二
jsPDF 直接基於Dom對象生成PDF 文件
jsPDF,支持添加頁碼
適用場景: 適合簡單的頁面布局,如常規的二維表,但復雜的報表樣式定義Dom元素,使用起來就異常復雜了。
<script>
function demoFromHTML() {
var pdf = new jsPDF('p', 'pt', 'letter');
// source can be HTML-formatted string, or a reference
// to an actual DOM element from which the text will be scraped.
source = $('#content')[0];
// we support special element handlers. Register them with jQuery-style
// ID selector for either ID or node name. ("#iAmID", "div", "span" etc.)
// There is no support for any other type of selectors
// (class, of compound) at this time.
specialElementHandlers = {
// element with id of "bypass" - jQuery style selector
'#bypassme': function (element, renderer) {
// true = "handled elsewhere, bypass text extraction"
return true
}
};
margins = {
top: 80,
bottom: 60,
left: 40,
width: 522
};
// all coords and widths are in jsPDF instance's declared units
// 'inches' in this case
pdf.fromHTML(
source, // HTML string or DOM elem ref.
margins.left, // x coord
margins.top, { // y coord
'width': margins.width, // max width of content on PDF
'elementHandlers': specialElementHandlers
},
function (dispose) {
// dispose: object with X, Y of the last line add to the PDF
// this allow the insertion of new lines after html
pdf.save('Test.pdf');
}, margins);
}
</script>
缺點:
- 多平台之間展示有差異,如手機端展示的Dom結構和電腦端布局有很大不同
- 對中日韓文的字體支持不佳,會出現亂碼
- 布局在不同瀏覽器中有差異
方法三
使用 ActiveReportsJS直接在線設計布局,並直接生成PDF 文件
優點: 簡單易用,可視化操作,所見即所得,代碼量少,適用於多平台,保證PC端,Web端,手機端三端一致。
缺點:需要配相應字體,能夠滿足精准生成PDF 的需求。適用於保險業,金融業,檢測業等對於PDF文件格式要求嚴格的的行業。
字體信息通常包含:
- 字體名稱: 字體ID 如 Arial, Calibri, 或 Times New Roman
- 字體樣式: 正常 或 斜體
- 字體粗細: 較細,細體,正常,適中,粗體,較粗
- 字體系列通常由多個字體組成,通常由單獨的文件表示。
接下來我們一起來看看具體實現過程。
在報表Viewer中顯示報表,將報表導出為PDF或托管報表設計器組件的應用程序應使用與為獨立設計器應用程序創建的配置相同的配置。 最簡單的方式是復制Fonts 文件夾和 fontsConfig.json 文件到項目的 assets 文件夾下面. 此文件夾因不同的前端框架而異。 示例如下:
RegisterFonts 方法是個異步函數,並會返回 Promise 對象。 也可以調用此方法的代碼可以等待,直到返回Promise結果后,再在查看器組件中加載報表或導出報表。
{
"name": "Montserrat",
"weight": "900",
"style": "italic",
"source": "assets/Fonts/Montserrat/Montserrat-BlackItalic.ttf"
}
<script src="https://cdn.grapecity.com/activereportsjs/2.latest/dist/ar-js-core.js"></script>
<script>
GC.ActiveReports.Core.FontStore.registerFonts(
"/resources/fontsConfig.json" // replace the URL with the actual one
)
</script>
var pageReport = new ARJS.PageReport();
pageReport.load('Quotation.rdlx-json')
.then(function() { return pageReport.run() })
.then(function(pageDocument) { return PDF.exportDocument(pageDocument, settings) })
.then(function(result) { result.download('arjs-pdf') });
HTML 展示效果圖:
PDF 展示效果圖:
參考示例:https://demo.grapecity.com.cn/activereportsjs/demos/api/export/purejs
本文為大家介紹了三種不同方式實現了各種PDF打印的方式,后續還會為大家帶來更多有趣的內容~覺得不錯點個贊再走吧