news 2026/1/11 11:19:52

golang PDF转图片,图片转PDF(无cgo,以及其他二进制程序依赖)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
golang PDF转图片,图片转PDF(无cgo,以及其他二进制程序依赖)

直接上代码和效果:

packagemainimport("fmt"_"image/png""os""path/filepath""regexp""sort""strconv""sync""github.com/jung-kurt/gofpdf""github.com/pdfcpu/pdfcpu/pkg/api""github.com/pdfcpu/pdfcpu/pkg/pdfcpu/model")// PDFToImages// pdfPath: 输入PDF路径// outputDir: 图片输出目录// maxWorkers: 最大并发协程数(0表示不限制)funcPDFToImages(pdfPath,outputDirstring,maxWorkers...int)error{// 1. 创建输出目录iferr:=os.MkdirAll(outputDir,0755);err!=nil{returnfmt.Errorf("创建输出目录失败: %w",err)}// 2. 配置PDF渲染参数conf:=model.NewDefaultConfiguration()conf.Cmd=model.WMImage// 3. 获取PDF页数pageCount,err:=api.PageCountFile(pdfPath)iferr!=nil{returnfmt.Errorf("获取PDF页数失败: %w",err)}ifpageCount==0{returnfmt.Errorf("PDF文件无页面")}// 4. 设置并发参数workers:=pageCountiflen(maxWorkers)>0&&maxWorkers[0]>0{workers=maxWorkers[0]ifworkers>pageCount{workers=pageCount}}// 5. 创建任务通道和结果通道tasks:=make(chanint,pageCount)errChan:=make(chanerror,pageCount)varwg sync.WaitGroup// 6. 启动工作协程fori:=0;i<workers;i++{wg.Add(1)gofunc(workerIDint){deferwg.Done()forpageNum:=rangetasks{// 转换单页PDF为图片err:=api.ExtractImagesFile(pdfPath,outputDir,[]string{fmt.Sprintf("%d",pageNum)},conf)iferr!=nil{errChan<-fmt.Errorf("转换第%d页失败: %w",pageNum,err)continue}fmt.Printf("第%d页已保存\n",pageNum)}}(i)}// 7. 发送任务forpageNum:=1;pageNum<=pageCount;pageNum++{tasks<-pageNum}close(tasks)// 8. 等待所有协程完成wg.Wait()close(errChan)// 9. 检查错误forerr:=rangeerrChan{iferr!=nil{returnerr}}returnnil}// extractPageNum 从图片文件名中提取页码funcextractPageNum(pdfFileNamestring,filenamestring)int{// 定义正则表达式匹配页码部分re:=regexp.MustCompile(pdfFileName+`_(\d+)_Im0\.(jpg|jpeg|png)`)matches:=re.FindStringSubmatch(filename)iflen(matches)<2{return0}pageNum,err:=strconv.Atoi(matches[1])iferr!=nil{return0}returnpageNum}// ImagesToPDF 图片批量转回PDFfuncImagesToPDF(imgDir,pdfPathstring,sortByNamebool)error{varimgFiles[]stringerr:=filepath.Walk(imgDir,func(pathstring,info os.FileInfo,errerror)error{iferr!=nil{returnerr}ifinfo.IsDir(){returnnil}ext:=filepath.Ext(path)ifext==".png"||ext==".jpg"||ext==".jpeg"{imgFiles=append(imgFiles,path)}returnnil})iferr!=nil{returnfmt.Errorf("遍历图片目录失败: %w",err)}iflen(imgFiles)==0{returnfmt.Errorf("未找到图片文件")}ifsortByName{// 根据页码数字排序sort.Slice(imgFiles,func(i,jint)bool{pageNumI:=extractPageNum("D3D9_DEV",filepath.Base(imgFiles[i]))// 记得把D3D9_DEV替换为你的PDF文件名,只要文件名,不要文件后缀pageNumJ:=extractPageNum("D3D9_DEV",filepath.Base(imgFiles[j]))// 记得把D3D9_DEV替换为你的PDF文件名,只要文件名,不要文件后缀returnpageNumI<pageNumJ})}pdf:=gofpdf.New("P","mm","A4","")pdf.SetMargins(0,0,0)for_,imgPath:=rangeimgFiles{pdf.AddPage()pdf.Image(imgPath,0,0,210,297,false,"",0,"")// A4尺寸 210x297mmfmt.Printf("添加图片到PDF:%s\n",imgPath)}iferr:=pdf.OutputFileAndClose(pdfPath);err!=nil{returnfmt.Errorf("保存PDF失败: %w",err)}returnnil}funcmain(){// PDF转图片err:=PDFToImages("D3D9_DEV.pdf","pdf_images",10)iferr!=nil{fmt.Printf("PDF转图片失败: %v\n",err)return}// 图片转回PDFerr=ImagesToPDF("pdf_images","output_from_images.pdf",true)iferr!=nil{fmt.Printf("图片转PDF失败: %v\n",err)return}fmt.Println("操作完成!")}

在main函数中进行操作:

先把图片转回PDF注释掉:

funcmain(){// PDF转图片err:=PDFToImages("D3D9_DEV.pdf","pdf_images",10)iferr!=nil{fmt.Printf("PDF转图片失败: %v\n",err)return}// 图片转回PDF// err = ImagesToPDF("pdf_images", "output_from_images.pdf", true)// if err != nil {// fmt.Printf("图片转PDF失败: %v\n", err)// return// }fmt.Println("操作完成!")}


因为采用了协程,所以效率非常高。

之后把图片转PDF的注释打开,把PDF转图片注释,注意要修改的地方:

funcmain(){// PDF转图片// err := PDFToImages("D3D9_DEV.pdf", "pdf_images", 10)// if err != nil {// fmt.Printf("PDF转图片失败: %v\n", err)// return// }// 图片转回PDFerr:=ImagesToPDF("pdf_images","output_from_images.pdf",true)iferr!=nil{fmt.Printf("图片转PDF失败: %v\n",err)return}fmt.Println("操作完成!")}

因为我的pdf文件就叫D3D9_DEV.pdf,你们在还原的时候,需要根据你们的pdf文件名进行修改:

ifsortByName{// 根据页码数字排序sort.Slice(imgFiles,func(i,jint)bool{pageNumI:=extractPageNum("D3D9_DEV",filepath.Base(imgFiles[i]))// 记得把D3D9_DEV替换为你的PDF文件名,只要文件名,不要文件后缀pageNumJ:=extractPageNum("D3D9_DEV",filepath.Base(imgFiles[j]))// 记得把D3D9_DEV替换为你的PDF文件名,只要文件名,不要文件后缀returnpageNumI<pageNumJ})}


因为现在AI越来越强大了,希望能够有更多的人可以把图片进行修复,比如文字更加平滑,清晰,图片更加精美漂亮,等每张图片都修复好了,再把他们合成最终的pdf文件。

老旧PDF图书大多都不太清晰,希望能多加利用这个案例,修复更多的pdf,给后来人留下更多的数字遗产。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/16 18:56:07

解决 macOS 26.1 The application “xxxx” can’t be opened. 问题

报错如下&#xff1a; “xxx.app” is damaged and can’t be opened. You should move it to the Trash.The application “Charles” can’t be opened.非 M 系列芯片可以通过下面的命令解决&#xff1a; sudo xattr -rd com.apple.quarantine /Applications/xxx.app M 芯片解…

作者头像 李华
网站建设 2025/12/16 18:56:06

NSQ 在 Golang 项目中的监控与管理方法

NSQ 在 Golang 项目中的监控与管理方法 关键词&#xff1a;NSQ、消息队列、Golang、监控指标、故障排查、动态扩缩容、云原生 摘要&#xff1a;本文以“快递中转站”为类比&#xff0c;用通俗易懂的语言讲解 NSQ 消息队列的核心组件与监控管理逻辑。结合 Golang 项目实战&#…

作者头像 李华
网站建设 2026/1/10 15:22:30

用户体验测试的启发式评估:理论与实践

在当今软件快速迭代的背景下&#xff0c;用户体验&#xff08;UX&#xff09;已成为产品成功的关键因素之一。作为软件测试从业者&#xff0c;我们不仅需关注功能缺陷&#xff0c;还需从用户视角评估产品的可用性和易用性。启发式评估作为一种高效、低成本的用户体验测试方法&a…

作者头像 李华
网站建设 2025/12/24 0:38:51

农业气象数据从哪来?小型农业气象站6要素实时监测,为农事安排添参考

农业生产与天气变化息息相关&#xff0c;霜冻、大风、暴雨等天气可能对作物造成直接影响。依赖大范围的公共天气预报&#xff0c;有时难以满足对特定小气候环境精准了解的需求。如何便捷地获取田间局地的气象信息&#xff0c;成为一些种植户关心的问题。小型农业气象站正是部署…

作者头像 李华
网站建设 2025/12/16 18:52:42

用Wan2.2-T2V-A14B实现720P高保真视频生成

用Wan2.2-T2V-A14B实现720P高保真视频生成 你有没有试过&#xff0c;在脑海中构思一个画面&#xff1a;阳光斜照的古风庭院里&#xff0c;一位身着汉服的女孩轻抚古琴&#xff0c;竹影随风摇曳&#xff0c;衣袖微扬&#xff0c;连琴弦的震颤都清晰可辨&#xff1f;过去&#xf…

作者头像 李华