Go如何处理PDF

这篇文章将为大家详细讲解有关Go如何处理PDF,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

工作中经常会遇到一些pdf文件处理的问题,一千种pdf有一千种处理方式,每次都是绞尽脑汁和这些pdf战斗到底。

Go如何处理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”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

发布于 2021-05-30 14:06:24
收藏
分享
海报
0 条评论
183
上一篇:CSS filter中有什么用 下一篇:SpringBoot Session共享图解
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码