這篇文章將為大家詳細(xì)講解有關(guān)Go如何處理PDF,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
新鄭ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書未來市場(chǎng)廣闊!成為成都創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18980820575(備注:SSL證書合作)期待與您的合作!工作中經(jīng)常會(huì)遇到一些pdf文件處理的問題,一千種pdf有一千種處理方式,每次都是絞盡腦汁和這些pdf戰(zhàn)斗到底。
本人又是一個(gè)gopher,所以這篇文章會(huì)以一個(gè)goper的視角,列舉一下我所經(jīng)歷過的每一種pdf處理場(chǎng)景,比如:
pdf渲染
pdf校驗(yàn)
pdf加水印
pdf獲取頁數(shù)
pdf合并
pdf拆分
修復(fù)受損pdf
pdf轉(zhuǎn)png
識(shí)別pdf中的字體
pdf解密
...
本文大多是場(chǎng)景問題的羅列,可以根據(jù)標(biāo)題摘取自己有興趣的部分查看
很多pdf的問題我也不是特別專業(yè),如果問題或者疑問歡迎與我交流
一、HTML頁面渲染PDF
根據(jù)html頁面渲染pdf,我使用過以下兩種方案:
wkhtmltopdf
chromedp
1. 使用wkhtmltopdf渲染pdf
wkhtmltopdf是一個(gè)命令行工具,用于將HTML頁面渲染為PDF,基于Qt WebKit渲染引擎實(shí)現(xiàn)
使用方式比較簡單:
## 將一個(gè)靜態(tài)html頁面打印成pdf $ wkhtmltopdf input.html output.pdf ## 將一個(gè)網(wǎng)頁打印成pdf $ wkhtmltopdf https://www.google.com output.pdf
wkhtmltopdf的參數(shù)很豐富,比如:
支持發(fā)送 http post請(qǐng)求,適合將自定義開發(fā)的網(wǎng)頁渲染成pdf文件:
$ wkhtmltopdf --help ... --postAdd an additional post field (repeatable) ...
支持javascript腳本,在渲染pdf前對(duì)html進(jìn)行修改:
$ wkhtmltopdf --run-script "javascript:(function(){document.getElementsByClassName('dom_class_name')[0].style.display = 'none'}())" page input.html output.pdf
更多詳細(xì)參數(shù)可看官網(wǎng)文檔
如果你使用Go語言,還有一個(gè)第三方包,是對(duì)wkhtmltopdf的使用封裝:go-wkhtmltopdf
2. 使用chromedp渲染pdf
chromedp是一種在Go語言中以更快,更簡單的方式來驅(qū)動(dòng)支持Chrome DevTools協(xié)議的瀏覽器的軟件包,而無需外部依賴((例如Selenium或PhantomJS).
使用方式:
package main import ( "context" "io/ioutil" "github.com/chromedp/cdproto/page" "github.com/chromedp/chromedp" "errors" ) func main(){ err := ChromedpPrintPdf("https://www.google.com", "/path/to/file.pdf") if err != nil { fmt.Println(err) return } } func ChromedpPrintPdf(url string, to string) error { ctx, cancel := chromedp.NewContext(context.Background()) defer cancel() var buf []byte err := chromedp.Run(ctx, chromedp.Tasks{ chromedp.Navigate(url), chromedp.WaitReady("body"), chromedp.ActionFunc(func(ctx context.Context) error { var err error buf, _, err = page.PrintToPDF(). Do(ctx) return err }), }) if err != nil { return fmt.Errorf("chromedp Run failed,err:%+v", err) } if err := ioutil.WriteFile(to, buf, 0644); err != nil { return fmt.Errorf("write to file failed,err:%+v", err) } return nil }
二、PDF加水印
我了解到的支持pdf加水印的工具有:
unidoc/unipdf
pdfcpu
1.unidoc/unipdf
unidoc平臺(tái)開發(fā)的unipdf是一款用Go語言編寫的PDF庫,提供API和CLI使用模式,支持以下功能:
$ unipdf -h ... Available Commands: decrypt Decrypt PDF files encrypt Encrypt PDF files explode Explodes the input file into separate single page PDF files extract Extract PDF resources form PDF form operations grayscale Convert PDF to grayscale help Help about any command info Output PDF information merge Merge PDF files optimize Optimize PDF files passwd Change PDF passwords rotate Rotate PDF file pages search Search text in PDF files split Split PDF files version Output version information and exit watermark Add watermark to PDF files ...
CLI模式添加水印
$ unipdf watermark in.pdf watermark.png -o out.pdf Watermark successfully applied to in.pdf Output file saved to out.pdf
使用API添加水印,可以直接參考unipdf github example
注意:unidoc的產(chǎn)品需要付費(fèi)購買license使用
2.pdfcpu
pdfcpu 是一個(gè)用Go語言編寫的PDF處理庫,提供API和CLI模式使用
支持以下功能:
$ pdfcpu help ... The commands are: attachments list, add, remove, extract embedded file attachments changeopw change owner password changeupw change user password decrypt remove password protection encrypt set password protection extract extract images, fonts, content, pages, metadata fonts install, list supported fonts grid rearrange pages or images for enhanced browsing experience import import/convert images to PDF info print file info merge concatenate 2 or more PDFs nup rearrange pages or images for reduced number of pages optimize optimize PDF by getting rid of redundant page resources pages insert, remove selected pages paper print list of supported paper sizes permissions list, set user access permissions rotate rotate pages split split multi-page PDF into several PDFs according to split span stamp add, remove, update text, image or PDF stamps for selected pages trim create trimmed version of selected pages validate validate PDF against PDF 32000-1:2008 (PDF 1.7) version print version watermark add, remove, update text, image or PDF watermarks for selected pages ...
使用CLI工具以圖片形式添加水印:
$ pdfcpu watermark add -mode image 'voucher_watermark.png' 's:1 abs, rot:0' in.pdf out.pdf
調(diào)用api添加水印
package main import ( "github.com/pdfcpu/pdfcpu/pkg/api" "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" ) func main() { onTop := false wm, _ := pdfcpu.ParseImageWatermarkDetails("watermark.png", "s:1 abs, rot:0", onTop) api.AddWatermarksFile("in.pdf", "out.pdf", nil, wm, nil) }
三、PDF合并
cpdf
unipdfc
pdfcpu
1.使用cpdf合并pdf
cpdf是一個(gè)開源免費(fèi)的PDF命令行工具庫,有豐富的功能,比如:
Merge PDF files together, or split them apart
Encrypt and decrypt
Scale, crop and rotate pages
Read and set document info and metadata
Copy, add or remove bookmarks
Stamp logos, text, dates, page numbers
Add or remove attachments
Losslessly compress PDF files
合并pdf:
$ cpdf -merge input1.pdf input2.pdf -o output.pdf
2.使用unipdf合并pdf
$ unipdf merge output.pdf input1.pdf input2.pdf
使用API合并pdf,參考unpdf github example
3.使用pdfcpu合并pdf
$ pdfcpu merge output.pdf input1.pdf input2.pdf
注意: pdfcpu只支持版本低于PDF V1.7的pdf文件
四、拆分PDF
cpdf
unipdf
pdfcpu
1.使用cpdf拆分pdf
## 逐頁拆分成單個(gè)pdf $ cpdf -split in.pdf 1 even -chunk 1 -o ./out%%%.pdf
2. 使用unipdf拆分pdf
## 將第一頁拆分出來 $ unipdf split input.pdf out.pdf 1-1
使用api拆分pdf,參考unipdf github examples
3.使用pdfcpu拆分pdf
$ pdfcpu split in.pdf .
五、PDF轉(zhuǎn)圖片
mupdf
xpdf
1. 使用mupdf操作pdf轉(zhuǎn)圖片
MuPDF is a lightweight PDF, XPS, and E-book viewer.
MuPDF consists of a software library, command line tools, and viewers for various platforms.
下載mupdf后得到一些工具,比如:
mupdf
pdfdraw
pdfinfo
pdfclean
pdfextract
pdfshow
xpsdraw
其中pdfdraw可用來轉(zhuǎn)換圖片
$ pdfdraw -o out%d.png in.pdf
注意: mupdf不支持mac OS
2. 使用xpdf操作pdf轉(zhuǎn)圖片
xpdf是一個(gè)免費(fèi)的PDF工具包,包括文字解析,圖片轉(zhuǎn)換,html轉(zhuǎn)換等
下載該軟件包后,可以得到一系列的工具:
pdfdetach
pdffonts
pdfimages
pdfinfo
pdftohtml
pdftopng
pdftoppm
pdftops
pdftotext
從名稱上看,大致能看出來每一個(gè)工具的用處
## 使用pdftopng將pdf轉(zhuǎn)換成png $ pdftopng in.pdf out-prefix
六、PDF解密
經(jīng)常會(huì)遇到一種場(chǎng)景,讀取pdf文件的時(shí)候發(fā)現(xiàn)會(huì)報(bào)錯(cuò):文件被加密
但是在沒有密碼的情況下怎么解決呢?
使用qpdf解密
使用qpdf進(jìn)行強(qiáng)制解密,有些情況是可以解密成功的,但是有些情況也不一定能解密成功
qpdf是一個(gè)支持命令行的pdf工具
$ qpdf --decrypt in.pdf out.pdf
使用pdfcpu解密
$ pdfcpu decrypt encrypted.pdf output.pdf
當(dāng)有密碼的情況下,可以使用密碼解密:
使用unipdf解密pdf
$ unipdf decrypt -p pass -o output.pdf input.pdf
七、PDF識(shí)別
經(jīng)常會(huì)遇到一些場(chǎng)景,比如識(shí)別一個(gè)文件是不是pdf文件,識(shí)別pdf中的文字,識(shí)別pdf中的圖片等
1.識(shí)別pdf中的文字
這里使用xpdf將pdf中的文字解析出來,然后再使用一些字符串操作或者正則表達(dá)式進(jìn)行業(yè)務(wù)分析
使用xpdf/pdftotext解析pdf中的文本
$ pdftotext input.pdf output.txt
使用unipdf解析pdf中的文本
$ unipdf extract text input.pdf
使用API解析pdf文本,參考unipdf github examples
使用坐標(biāo)信息解析pdf數(shù)據(jù)
上面都是先解析出pdf的文本,再根據(jù)業(yè)務(wù)進(jìn)行處理
還有一種方式是按照坐標(biāo)位置解析pdf,這種方式更加靈活以及通用,利用的是pdflib/tet
## 輸入一組坐標(biāo),即可按照坐標(biāo)解析pdf中的數(shù)據(jù) $ tet --pageopt "includebox={{38 707.93 243.91 716.93}}" input.pdf
坐標(biāo)可以使用tet對(duì)pdf進(jìn)行分析得到一個(gè)tetml文件,里面包含了坐標(biāo)信息:
$ tet --tetml input.pdf
當(dāng)然也可以用一些其他的方式獲取pdf中數(shù)據(jù)的坐標(biāo)信息,比如nodejs等
注意: pdflib/tet是收費(fèi)軟件,但是根據(jù)官方文檔說明,tet提供基礎(chǔ)功能,處理不超過10頁或者小于1M的pdf文件是不需要購買license的
pdflib/tet提供了命令行工具以及多種語言的sdk支持,比如C/C++/Java/.NET/Perl/PHP/Python/Ruby/Swift 但目前還不支持Go語言,所以對(duì)于gopher而言目前只有兩種選擇:CLI OR CGO
八、修復(fù)受損PDF文件
有一些pdf文件在電腦上打開時(shí),顯示正常,但是用代碼檢測(cè)卻是不正常的,比如在Go中嘗試用一個(gè)第三方庫去解析一個(gè)(受損的)pdf:
import ( "fmt" "github.com/rsc.io/pdf" ) func main() { filePath := "path/to/your/broken.pdf" _, err := pdf.Open(filePath) if err != nil { fmt.Println("open pdf failed,err:", err.Error()) return } }
運(yùn)行后會(huì)得到這樣一個(gè)結(jié)果:
open pdf failed,err: malformed PDF: cross-reference table not found: {5 0 obj}<> /MediaBox [0 0 595.27600098 841.89001465] /Parent 3 0 R /Type /Page>>
電腦打開正常,程序卻讀取錯(cuò)誤!
這時(shí)候如果嘗試在電腦上打開pdf,然后另存為一個(gè)新的pdf文件,再用代碼去檢測(cè),會(huì)發(fā)現(xiàn)竟然修復(fù)了!
太好了,問題解決!
等等,如果我有1000張pdf文件,難道要逐個(gè)打開并另存為?這怎么能忍? 所以如果有一種批量修復(fù)的功能就好了
在網(wǎng)上找了很久,大概得到三種解決方案:
利用 Acrobat SDK,調(diào)用SDK中的另存為功能,可以實(shí)現(xiàn)電腦打開另存為的效果
利用ghostscript進(jìn)行pdf修復(fù)
利用mupdf進(jìn)行pdf修復(fù)
這里我只驗(yàn)證了第三種方式是可行的,這里我使用mupdf-0.9-linux-amd64這個(gè)版本進(jìn)行驗(yàn)證
下載軟件包后,得到其中一個(gè)可執(zhí)行文件:pdfclean
$ pdfclean broken.pdf repaired.pdf + pdf/pdf_xref.c:160: pdf_read_trailer(): cannot recognize xref format: '%' | pdf/pdf_xref.c:481: pdf_load_xref(): cannot read trailer \ pdf/pdf_xref.c:537: pdf_open_xref_with_stream(): trying to repair
從輸出結(jié)果來看,mupdf嘗試了修復(fù)處理
得到新的pdf文件之后,再用前面的Go代碼嘗試打開,就正常了
剩下的就是寫一個(gè)bash腳本,批量修復(fù),目標(biāo)達(dá)成!
九、識(shí)別一個(gè)PDF文件的字體信息
有時(shí)候要使多個(gè)pdf文本字體保持一致,免不得要去分析pdf中都使用了哪些字體,這時(shí)候可以使用xpdf/pdffonts進(jìn)行字體分析
$ pdffonts input.pdf name type encoding emb sub uni object ID ------------------------------------ ----------------- ---------------- --- --- --- --------- NimbusSanL-Regu CID TrueType Identity-H yes no yes 10 0 NimbusSanL-Bold CID TrueType Identity-H yes no yes 20 0
其他Libiray介紹:
PDF-Writer
這是一個(gè)C++的開源庫,支持創(chuàng)建pdf,合并pdf,圖片水印文字操作等
對(duì)于gopher來講,要使用這個(gè)庫,需要封裝一層CGO代碼才可以
rsc/pdf
這是一個(gè)Go語言實(shí)現(xiàn)的pdf庫,可以用于讀取pdf信息,比如讀取pdf內(nèi)容/頁數(shù)/字體等... 具體可以參考文檔
介紹了這么多第三方庫,簡直就是五花八門,各顯神通。有些功能在大多數(shù)庫中都是有重復(fù)的,具體使用中會(huì)遇到什么問題,還是要看實(shí)際情況如何。
關(guān)于“Go如何處理PDF”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。