Go如何处理PDF
这篇文章将为大家详细讲解有关Go如何处理PDF,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
工作中经常会遇到一些pdf文件处理的问题,一千种pdf有一千种处理方式,每次都是绞尽脑汁和这些pdf战斗到底。
本人又是一个gopher,所以这篇文章会以一个goper的视角,列举一下我所经历过的每一种pdf处理场景,比如:
pdf渲染pdf校验pdf加水印pdf获取页数pdf合并pdf拆分修复受损pdfpdf转png识别pdf中的字体pdf解密...
本文大多是场景问题的罗列,可以根据标题摘取自己有兴趣的部分查看
很多pdf的问题我也不是特别专业,如果问题或者疑问欢迎与我交流
一、HTML页面渲染PDF
根据html页面渲染pdf,我使用过以下两种方案:
wkhtmltopdf
chromedp
1. 使用wkhtmltopdf渲染pdf
wkhtmltopdf是一个命令行工具,用于将HTML页面渲染为PDF,基于Qt WebKit渲染引擎实现
使用方式比较简单:
##将一个静态html页面打印成pdf $wkhtmltopdfinput.htmloutput.pdf ##将一个网页打印成pdf $wkhtmltopdfhttps://www.google.comoutput.pdf
wkhtmltopdf的参数很丰富,比如:
支持发送 http post请求,适合将自定义开发的网页渲染成pdf文件:
$wkhtmltopdf--help ... --post<name><value>Addanadditionalpostfield(repeatable) ...
支持javascript脚本,在渲染pdf前对html进行修改:
$wkhtmltopdf--run-script"javascript:(function(){document.getElementsByClassName('dom_class_name')[0].style.display='none'}())"pageinput.htmloutput.pdf
更多详细参数可看官网文档
如果你使用Go语言,还有一个第三方包,是对wkhtmltopdf的使用封装:go-wkhtmltopdf
2. 使用chromedp渲染pdf
chromedp是一种在Go语言中以更快,更简单的方式来驱动支持Chrome DevTools协议的浏览器的软件包,而无需外部依赖((例如Selenium或PhantomJS).
使用方式:
packagemain import( "context" "io/ioutil" "github.com/chromedp/cdproto/page" "github.com/chromedp/chromedp" "errors" ) funcmain(){ err:=ChromedpPrintPdf("https://www.google.com","/path/to/file.pdf") iferr!=nil{ fmt.Println(err) return } } funcChromedpPrintPdf(urlstring,tostring)error{ ctx,cancel:=chromedp.NewContext(context.Background()) defercancel() varbuf[]byte err:=chromedp.Run(ctx,chromedp.Tasks{ chromedp.Navigate(url), chromedp.WaitReady("body"), chromedp.ActionFunc(func(ctxcontext.Context)error{ varerrerror buf,_,err=page.PrintToPDF(). Do(ctx) returnerr }), }) iferr!=nil{ returnfmt.Errorf("chromedpRunfailed,err:%+v",err) } iferr:=ioutil.WriteFile(to,buf,0644);err!=nil{ returnfmt.Errorf("writetofilefailed,err:%+v",err) } returnnil }
二、PDF加水印
我了解到的支持pdf加水印的工具有:
unidoc/unipdf
pdfcpu
1.unidoc/unipdf
unidoc平台开发的unipdf是一款用Go语言编写的PDF库,提供API和CLI使用模式,支持以下功能:
$unipdf-h ... AvailableCommands: decryptDecryptPDFfiles encryptEncryptPDFfiles explodeExplodestheinputfileintoseparatesinglepagePDFfiles extractExtractPDFresources formPDFformoperations grayscaleConvertPDFtograyscale helpHelpaboutanycommand infoOutputPDFinformation mergeMergePDFfiles optimizeOptimizePDFfiles passwdChangePDFpasswords rotateRotatePDFfilepages searchSearchtextinPDFfiles splitSplitPDFfiles versionOutputversioninformationandexit watermarkAddwatermarktoPDFfiles ...
CLI模式添加水印
$unipdfwatermarkin.pdfwatermark.png-oout.pdf Watermarksuccessfullyappliedtoin.pdf Outputfilesavedtoout.pdf
使用API添加水印,可以直接参考unipdf github example
注意:unidoc的产品需要付费购买license使用
2.pdfcpu
pdfcpu 是一个用Go语言编写的PDF处理库,提供API和CLI模式使用
支持以下功能:
$pdfcpuhelp ... Thecommandsare: attachmentslist,add,remove,extractembeddedfileattachments changeopwchangeownerpassword changeupwchangeuserpassword decryptremovepasswordprotection encryptsetpasswordprotection extractextractimages,fonts,content,pages,metadata fontsinstall,listsupportedfonts gridrearrangepagesorimagesforenhancedbrowsingexperience importimport/convertimagestoPDF infoprintfileinfo mergeconcatenate2ormorePDFs nuprearrangepagesorimagesforreducednumberofpages optimizeoptimizePDFbygettingridofredundantpageresources pagesinsert,removeselectedpages paperprintlistofsupportedpapersizes permissionslist,setuseraccesspermissions rotaterotatepages splitsplitmulti-pagePDFintoseveralPDFsaccordingtosplitspan stampadd,remove,updatetext,imageorPDFstampsforselectedpages trimcreatetrimmedversionofselectedpages validatevalidatePDFagainstPDF32000-1:2008(PDF1.7) versionprintversion watermarkadd,remove,updatetext,imageorPDFwatermarksforselectedpages ...
使用CLI工具以图片形式添加水印:
$pdfcpuwatermarkadd-modeimage'voucher_watermark.png''s:1abs,rot:0'in.pdfout.pdf
调用api添加水印
packagemain import( "github.com/pdfcpu/pdfcpu/pkg/api" "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" ) funcmain(){ onTop:=false wm,_:=pdfcpu.ParseImageWatermarkDetails("watermark.png","s:1abs,rot:0",onTop) api.AddWatermarksFile("in.pdf","out.pdf",nil,wm,nil) }
三、PDF合并
cpdf
unipdfc
pdfcpu
1.使用cpdf合并pdf
cpdf是一个开源免费的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-mergeinput1.pdfinput2.pdf-ooutput.pdf
2.使用unipdf合并pdf
$unipdfmergeoutput.pdfinput1.pdfinput2.pdf
使用API合并pdf,参考unpdf github example
3.使用pdfcpu合并pdf
$pdfcpumergeoutput.pdfinput1.pdfinput2.pdf
注意: pdfcpu只支持版本低于PDF V1.7的pdf文件
四、拆分PDF
cpdf
unipdf
pdfcpu
1.使用cpdf拆分pdf
##逐页拆分成单个pdf $cpdf-splitin.pdf1even-chunk1-o./out%%%.pdf
2. 使用unipdf拆分pdf
##将第一页拆分出来 $unipdfsplitinput.pdfout.pdf1-1
使用api拆分pdf,参考unipdf github examples
3.使用pdfcpu拆分pdf
$pdfcpusplitin.pdf.
五、PDF转图片
mupdf
xpdf
1. 使用mupdf操作pdf转图片
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 pdfdrawpdfinfo pdfclean pdfextract pdfshow xpsdraw
其中pdfdraw可用来转换图片
$pdfdraw-oout%d.pngin.pdf
注意: mupdf不支持mac OS
2. 使用xpdf操作pdf转图片
xpdf是一个免费的PDF工具包,包括文字解析,图片转换,html转换等
下载该软件包后,可以得到一系列的工具:
pdfdetach pdffonts pdfimages pdfinfo pdftohtml pdftopng pdftoppm pdftops pdftotext
从名称上看,大致能看出来每一个工具的用处
##使用pdftopng将pdf转换成png $pdftopngin.pdfout-prefix
六、PDF解密
经常会遇到一种场景,读取pdf文件的时候发现会报错:文件被加密
但是在没有密码的情况下怎么解决呢?
使用qpdf解密
使用qpdf进行强制解密,有些情况是可以解密成功的,但是有些情况也不一定能解密成功
qpdf是一个支持命令行的pdf工具
$qpdf--decryptin.pdfout.pdf
使用pdfcpu解密
$pdfcpudecryptencrypted.pdfoutput.pdf
当有密码的情况下,可以使用密码解密:
使用unipdf解密pdf
$unipdfdecrypt-ppass-ooutput.pdfinput.pdf
七、PDF识别
经常会遇到一些场景,比如识别一个文件是不是pdf文件,识别pdf中的文字,识别pdf中的图片等
1.识别pdf中的文字
这里使用xpdf将pdf中的文字解析出来,然后再使用一些字符串操作或者正则表达式进行业务分析
使用xpdf/pdftotext解析pdf中的文本
$pdftotextinput.pdfoutput.txt
使用unipdf解析pdf中的文本
$unipdfextracttextinput.pdf
使用API解析pdf文本,参考unipdf github examples
使用坐标信息解析pdf数据
上面都是先解析出pdf的文本,再根据业务进行处理
还有一种方式是按照坐标位置解析pdf,这种方式更加灵活以及通用,利用的是pdflib/tet
##输入一组坐标,即可按照坐标解析pdf中的数据 $tet--pageopt"includebox={{38707.93243.91716.93}}"input.pdf
坐标可以使用tet对pdf进行分析得到一个tetml文件,里面包含了坐标信息:
$tet--tetmlinput.pdf
当然也可以用一些其他的方式获取pdf中数据的坐标信息,比如nodejs等
注意: pdflib/tet是收费软件,但是根据官方文档说明,tet提供基础功能,处理不超过10页或者小于1M的pdf文件是不需要购买license的
pdflib/tet提供了命令行工具以及多种语言的sdk支持,比如C/C++/Java/.NET/Perl/PHP/Python/Ruby/Swift 但目前还不支持Go语言,所以对于gopher而言目前只有两种选择:CLI OR CGO
八、修复受损PDF文件
有一些pdf文件在电脑上打开时,显示正常,但是用代码检测却是不正常的,比如在Go中尝试用一个第三方库去解析一个(受损的)pdf:
import( "fmt" "github.com/rsc.io/pdf" ) funcmain(){ filePath:="path/to/your/broken.pdf" _,err:=pdf.Open(filePath) iferr!=nil{ fmt.Println("openpdffailed,err:",err.Error()) return } }
运行后会得到这样一个结果:
open pdf failed,err: malformed PDF: cross-reference table not found: {5 0 obj}<</Contents 6 0 R /Group <</CS /DeviceRGB /S /Transparency /Type /Group>> /MediaBox [0 0 595.27600098 841.89001465] /Parent 3 0 R /Type /Page>>
电脑打开正常,程序却读取错误!
这时候如果尝试在电脑上打开pdf,然后另存为一个新的pdf文件,再用代码去检测,会发现竟然修复了!
太好了,问题解决!
等等,如果我有1000张pdf文件,难道要逐个打开并另存为?这怎么能忍? 所以如果有一种批量修复的功能就好了
在网上找了很久,大概得到三种解决方案:
利用 Acrobat SDK,调用SDK中的另存为功能,可以实现电脑打开另存为的效果
利用ghostscript进行pdf修复
利用mupdf进行pdf修复
这里我只验证了第三种方式是可行的,这里我使用mupdf-0.9-linux-amd64这个版本进行验证
下载软件包后,得到其中一个可执行文件:pdfclean
$pdfcleanbroken.pdfrepaired.pdf +pdf/pdf_xref.c:160:pdf_read_trailer():cannotrecognizexrefformat:'%' |pdf/pdf_xref.c:481:pdf_load_xref():cannotreadtrailer \pdf/pdf_xref.c:537:pdf_open_xref_with_stream():tryingtorepair
从输出结果来看,mupdf尝试了修复处理
得到新的pdf文件之后,再用前面的Go代码尝试打开,就正常了
剩下的就是写一个bash脚本,批量修复,目标达成!
九、识别一个PDF文件的字体信息
有时候要使多个pdf文本字体保持一致,免不得要去分析pdf中都使用了哪些字体,这时候可以使用xpdf/pdffonts进行字体分析
$pdffontsinput.pdf nametypeencodingembsubuniobjectID --------------------------------------------------------------------------------------- NimbusSanL-ReguCIDTrueTypeIdentity-Hyesnoyes100 NimbusSanL-BoldCIDTrueTypeIdentity-Hyesnoyes200
其他Libiray介绍:
PDF-Writer这是一个C++的开源库,支持创建pdf,合并pdf,图片水印文字操作等
对于gopher来讲,要使用这个库,需要封装一层CGO代码才可以
rsc/pdf这是一个Go语言实现的pdf库,可以用于读取pdf信息,比如读取pdf内容/页数/字体等... 具体可以参考文档
介绍了这么多第三方库,简直就是五花八门,各显神通。有些功能在大多数库中都是有重复的,具体使用中会遇到什么问题,还是要看实际情况如何。
关于“Go如何处理PDF”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。
推荐阅读
-
go如何实现职责链模式
-
Go Callvis如何使用
-
go pprof如何使用
-
Go框架三件套Gorm、Kitex、Hertz怎么使用
-
Go语言单元测试和基准测试实例代码分析
-
go Realize怎么使用
goRealize怎么使用本文小编为大家详细介绍“goReal...
-
14天学会Go语言第四天:Array Map Slice 数组 和切片
-
如何从 PHP 过渡到 Golang?
我是PHP开发者,转Go两个月了吧,记录一下使用Golang怎么一步步开发新项目。本着有坑填坑,有错改错的宗...
-
零经验Go语言MVC框架,并推荐PHP函数库和MySQL表自动转struct
最近搭建k8s系统,为了调试自动部署用Go做了个MVC框架,这是个适用于喜欢Go语言练习的框架,零Go语言经验学习Go;配合Go模...
-
从php到Golang系统的演变