当前位置: 首页 > news >正文

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,给后来人留下更多的数字遗产。

http://www.cnnetsun.cn/news/89489.html

相关文章:

  • Kamailio 怎样使用 STIR/SHAKEN
  • COMSOL光学仿真:光镊与光力模型专题解析(三个模型详解、近似算法与张量算法探讨)
  • 北斗导航系统在实际应用中总会遇到各种干扰,尤其是脉冲干扰和窄带干扰特别烦人。今天咱们用Matlab仿真几种典型抗干扰方法,顺便看看代码咋写
  • Qwen3-8B大模型快速部署与实战体验
  • AI 时代,数据湖的“拐点”与展望
  • 使用 TensorRT-LLM 高性能部署大语言模型
  • A/B测试在功能验证中的应用:从理论到实践
  • 创建一个rust写的python库[signatures和错误处理]
  • 震撼!这家全景效果企业如何颠覆传统,让客户体验飙升!
  • JVM性能分析
  • 商家福音!用PHP对接快递鸟接口,一键搞定单号所属快递识别
  • YT29B凿岩机吕梁精准检测稳定性能解析
  • 26、网络连接与安全全解析
  • 2025.12.16 HSRP双机热备
  • 万全智能RFID模块设备他们产品档次怎么样
  • RuoYi v1.2.0 全端开发神器:让多端适配从未如此简单!
  • 少儿编程Scratch3.0教程——03 外观积木(基础知识)
  • libxslt XSLT转换库:鸿蒙PC上的XML转换工具
  • GPU算力租赁推荐:低成本训练YOLO大模型
  • VonaJS是如何做到文件级别精确HMR(热更新)的?
  • 口碑好的货架哪里有好的
  • pytorch框架训练、推理、模块冻结等各种细节说明
  • Java毕设项目推荐-基于Java语言的茶叶销售系统的前端设计与实现基于SpringBoot+Vue茶叶销售系统的设计与实现【附源码+文档,调试定制服务】
  • 大数据生态核心组件语法与原理详解
  • UVa 11617 An Odd Love
  • LobeChat能否对接Slack?团队协作平台集成方案
  • 集团宽带是什么意思?企业如何选择合适的宽带方案?
  • 运维外包的公司靠谱吗?企业真能省心?
  • HunyuanVideo-Foley:AI让视频自动配声
  • 信息安全技术与Kali Linux