[{"data":1,"prerenderedAt":1944},["ShallowReactive",2],{"blog-zh-go-pdf-fpdf-archived":3},{"id":4,"title":5,"author":6,"body":9,"date":698,"description":1931,"draft":1932,"extension":1933,"howTo":1934,"image":1934,"meta":1935,"navigation":784,"path":1936,"seo":1937,"stem":1938,"tags":1939,"updated":1934,"__hash__":1943},"blogZh/zh/blog/006.go-pdf-fpdf-archived.md","go-pdf/fpdf 也归档了。2026 年的 Go PDF 栈长这样。",{"name":7,"url":8},"gpdf team","https://gpdf.dev",{"type":10,"value":11,"toc":1915},"minimark",[12,17,45,48,67,70,87,99,103,106,141,147,151,157,173,176,185,191,195,198,382,385,398,410,416,422,425,429,436,439,481,484,723,739,743,759,762,767,1119,1124,1534,1552,1561,1564,1571,1668,1675,1681,1684,1692,1695,1745,1752,1755,1762,1771,1777,1781,1793,1799,1809,1827,1836,1842,1846,1849,1866,1880,1883,1911],[13,14,16],"h2",{"id":15},"tldr","TL;DR",[18,19,20,24,25,28,29,33,34,28,37,40,41,44],"p",{},[21,22,23],"code",{},"fpdf"," 系两个还在维护的分支都已经只读。",[21,26,27],{},"jung-kurt/gofpdf"," 于 ",[30,31,32],"strong",{},"2021 年 9 月"," 归档；社区 fork ",[21,35,36],{},"go-pdf/fpdf",[30,38,39],{},"2025 年"," 归档。不会再有\"下一任维护者\"。新项目的现代默认是 ",[30,42,43],{},"gpdf","：纯 Go、零外部依赖、CJK 原生、在常见工作负载上快 10–30 倍。这篇文章是 2026 年的局势图，以及对 \"何时选 gpdf、何时不选\" 的诚实回答。",[13,46,47],{"id":47},"现状",[18,49,50,51,54,55,59,60,63,64,66],{},"上周同事敲下 ",[21,52,53],{},"go get github.com/go-pdf/fpdf","，在 GitHub 的横幅前停住：",[56,57,58],"em",{},"\"This repository has been archived by the owner. It is now read-only.\""," —— 这本来应该是 ",[56,61,62],{},"修复版","，是 2021 年被归档的 ",[21,65,27],{}," 的社区接棒 fork。",[18,68,69],{},"它也归档了。README 现在建议去找别的库。",[18,71,72,73,76,77,79,80,82,83,86],{},"过去五年里，如果你用 Go 写服务、输出 PDF（发票、报表、运单、增值税发票、电子归档文件），",[21,74,75],{},"go.mod"," 最底下那一行几乎一定是这两个之一。Stack Overflow 的回答指向 ",[21,78,27],{},"；更新一点的教程指向 ",[21,81,36],{},"。",[30,84,85],{},"现在两个都是供应链上的负债"," —— CVE 分诊、Go 版本跟进、性能修复、规范更新，全部冻结。",[18,88,89,90,95,96],{},"这篇不是又一份逐行迁移指南——",[91,92,94],"a",{"href":93},"/zh/blog/gofpdf-migration","那份我们已经写过了","。这篇想回答迁移指南没回答的问题：",[30,97,98],{},"2026 年用 Go 生成 PDF，到底应该选什么？生态为什么会走到这一步？",[13,100,102],{"id":101},"归档-在生产中意味着什么","\"归档\" 在生产中意味着什么",[18,104,105],{},"GitHub 的 \"archived\" 标签看起来温柔。对于一个在你 import 图里的库，它其实意味着四件很具体的事：",[107,108,109,116,126,132],"ol",{},[110,111,112,115],"li",{},[30,113,114],{},"不会有安全补丁","。TTF 解析器里出现内存安全问题，不会有人合并修复到上游。你可以自己 fork 来修，大多数团队不会。",[110,117,118,121,122,125],{},[30,119,120],{},"不会跟进 Go 工具链","。Go 1.25 的循环变量语义今天在 gofpdf 上跑得好好的。但明天 ",[21,123,124],{},"for range"," 或某个标准库 API 废弃之类的改动如果把它弄坏，修补只读仓库的 fork 就是你自己的事。",[110,127,128,131],{},[30,129,130],{},"不会跟进规范","。PDF 2.0（ISO 32000-2）在 2020 年就定稿了。gofpdf 大部分实现停留在 PDF 1.7。页面级关联文件、丰富的 XMP 元数据、现代数字签名（PAdES-B-LT），要么缺失，要么靠第三方胶水拼上去。",[110,133,134,137,138,140],{},[30,135,136],{},"CJK 不会再前进","。gofpdf 的 Unicode 路径是在 \"单字节字体\" 的旧设计上后加的。能跑，但在大多数真实配置下会嵌入完整字体而不是子集；某些 CJK TTF 上会触发 glyph-id 冲突，输出乱码。",[21,139,36],{}," 继承了同样的架构。",[18,142,143,144,82],{},"安全和前向兼容两条，是合规会议上最刺眼的。\"我们的 PDF 库已归档且无人发 CVE 补丁\"，不是审计想听的回答。",[30,145,146],{},"如果你的 PDF 还涉及电子会计档案或增值税电子发票的保存期，这个问题不能再拖",[13,148,150],{"id":149},"为什么两个-fork-都死了","为什么两个 fork 都死了",[18,152,153,154,82],{},"把归档简单归咎于维护者倦怠很容易——一位累了的 reviewer，一个 bus factor 为 1 的维护人下线。那是原因之一，但不是全貌。",[30,155,156],{},"架构让追赶变得困难",[18,158,159,161,162,165,166,165,169,172],{},[21,160,27],{}," 是 FPDF 的移植——一个 2002 年的 PHP 库。PHP 原版通过在页面上推游标、按流程吐内容：",[21,163,164],{},"SetXY(x, y)","、",[21,167,168],{},"Cell(w, h, text)",[21,170,171],{},"Ln(h)","。这个模型在 2002 年的 PHP 下是合理折中——当时的替代方案是裸 PostScript 或商业工具包。移植到 Go 时，保留了游标、保留了单字节字体表、保留了手动分页管理。",[18,174,175],{},"每过一年，\"人们想生成的东西\"和\"游标模型能表达的东西\"之间的落差就变大一点。发票是表格。报告是带重复页眉页脚的网格。运单是二维码 + 本地语言文本。游标被辅助函数包起来，辅助函数又被教程包起来，到 2023 年左右，大多数人\"针对 gofpdf 写的代码\"其实不是 gofpdf——是每个团队自己的胶水层，试图把游标装成布局引擎。",[18,177,178,180,181,184],{},[21,179,36],{}," 继承了这一切。这个 fork 重构了内部实现、修了一些老 bug，但",[30,182,183],{},"没法改公开 API 的形状","——一动就要让所有下游工程崩。库的外形冻结在 2002 年的 PHP 里，维护这个形状的成本比收益涨得更快。",[18,186,187,190],{},[30,188,189],{},"所以","：两位维护者，两次归档，一个架构上的原因。2026 年要重新来一遍，就得选一个匹配今天 PDF 生成方式的方法——今天的方式更像搭网页，不像驱动绘图仪。",[13,192,194],{"id":193},"_2026-年-go-pdf-的局势","2026 年 Go PDF 的局势",[18,196,197],{},"在推荐任何东西之前，先把场面列出来。\"maintained\"（在维护）这里的意思是\"最近 6 个月有提交、issue 有响应\"。",[199,200,201,226],"table",{},[202,203,204],"thead",{},[205,206,207,211,214,217,220,223],"tr",{},[208,209,210],"th",{},"库",[208,212,213],{},"状态 (2026-04)",[208,215,216],{},"许可证",[208,218,219],{},"CJK 原生",[208,221,222],{},"零依赖",[208,224,225],{},"备注",[227,228,229,253,273,293,316,337,360],"tbody",{},[205,230,231,236,241,244,247,250],{},[232,233,234],"td",{},[21,235,27],{},[232,237,238],{},[30,239,240],{},"2021 已归档",[232,242,243],{},"MIT",[232,245,246],{},"后加的",[232,248,249],{},"是",[232,251,252],{},"原版。在大多数语言的搜索结果里至今仍是第一。",[205,254,255,259,264,266,268,270],{},[232,256,257],{},[21,258,36],{},[232,260,261],{},[30,262,263],{},"2025 已归档",[232,265,243],{},[232,267,246],{},[232,269,249],{},[232,271,272],{},"上者的社区 fork。同样的架构，同样的天花板。",[205,274,275,280,283,285,288,290],{},[232,276,277],{},[21,278,279],{},"signintech/gopdf",[232,281,282],{},"维护中",[232,284,243],{},[232,286,287],{},"部分",[232,289,249],{},[232,291,292],{},"低层库，你自己写坐标。适合表单叠加。",[205,294,295,301,303,305,308,311],{},[232,296,297,300],{},[21,298,299],{},"johnfercher/maroto"," v2",[232,302,282],{},[232,304,243],{},[232,306,307],{},"经 gofpdf",[232,309,310],{},"否",[232,312,313,314,82],{},"网格优先的 builder，但底层用 ",[21,315,36],{},[205,317,318,323,325,330,332,334],{},[232,319,320],{},[21,321,322],{},"unidoc/unipdf",[232,324,282],{},[232,326,327],{},[30,328,329],{},"商业",[232,331,249],{},[232,333,310],{},[232,335,336],{},"功能齐全的 PDF SDK。商用需付费许可。",[205,338,339,345,347,350,352,357],{},[232,340,341,344],{},[21,342,343],{},"chromedp"," + Chromium",[232,346,282],{},[232,348,349],{},"MIT + Chrome",[232,351,249],{},[232,353,354],{},[30,355,356],{},"否——自带浏览器",[232,358,359],{},"用无头 Chrome 做 HTML→PDF。运行时巨大。",[205,361,362,366,368,370,375,379],{},[232,363,364],{},[21,365,43],{},[232,367,282],{},[232,369,243],{},[232,371,372],{},[30,373,374],{},"原生",[232,376,377],{},[30,378,249],{},[232,380,381],{},"纯 Go 重写。Builder API、12 列网格。",[18,383,384],{},"只看这张表就能得出几个结论：",[18,386,387,390,391,393,394,397],{},[30,388,389],{},"目前\"仍在维护\"的每个方案，要么是商业许可、要么自带巨大运行时、要么坐在一个即将过时的地基上","。例外是 ",[21,392,279],{},"——确实在维护、依赖也轻。但它是坐标级库，你又回到了换个包名继续写 ",[21,395,396],{},"SetXY"," 的老路。",[18,399,400,403,404,406,407,409],{},[30,401,402],{},"Maroto v2 是个 API 不错的网格优先 builder","。问题在于 ",[21,405,75],{}," 底下是 ",[21,408,36],{},"。fpdf 的性能天花板和 CJK 限制，就是 Maroto 的天花板。v3 可能摆脱它，但还没出来。",[18,411,412,415],{},[30,413,414],{},"unipdf 功能丰富，但对商业项目不是 MIT 兼容","。按席位或按部署收费。如果你的营收撑得起这个账单，它是合理选择；对 OSS 副业或早期创业公司，许可证数学算不过来。",[18,417,418,421],{},[30,419,420],{},"chromedp 能跑，但你是在发布一个浏览器","。100 MB 的基础镜像变成 1 GB+，Serverless 冷启动痛苦，字体还得单独装进容器。好处是可以复用 React 模板；坏处是为了出一张发票一直在跑 Chromium。",[18,423,424],{},"缺口很明显：一个纯 Go、零依赖、CJK 原生、网格优先、不用商业许可也不用浏览器运行时的库。gpdf 就是为此而生。",[13,426,428],{"id":427},"gpdf-是什么","gpdf 是什么",[18,430,431,432,435],{},"gpdf（",[21,433,434],{},"github.com/gpdf-dev/gpdf","）是一次干净重写，不是 fork。PDF 线格式写入、布局引擎、TrueType 子集化器——全部用纯 Go 从零写。",[18,437,438],{},"对大多数团队最重要的三个属性：",[440,441,442,455,468],"ul",{},[110,443,444,82,447,450,451,454],{},[30,445,446],{},"纯 Go，无 CGO",[21,448,449],{},"go build"," 是静态的。",[21,452,453],{},"GOOS=linux GOARCH=arm64 go build"," 在 MacBook 上不配工具链就能过。Docker 镜像保持小——12 MB 的 distroless 容器跑得动。",[110,456,457,82,460,463,464,467],{},[30,458,459],{},"零外部依赖",[21,461,462],{},"go get github.com/gpdf-dev/gpdf"," 之后 ",[21,465,466],{},"go mod graph"," 只有一行：gpdf 自己。核心只用标准库。（HTML→PDF 或数字签名的可选扩展会带少量依赖，但都是选择性的。）",[110,469,470,82,473,476,477,480],{},[30,471,472],{},"原生 CJK",[21,474,475],{},"WithFont"," 在构建 document 时注册一个 TrueType 字体。子集嵌入在渲染时自动发生。",[30,478,479],{},"一张 200 字的中文/日文发票里嵌入的字体约 30 KB 子集","，不是 5 MB 的完整字体。",[18,482,483],{},"API 形态是声明式的。你描述一棵行/列的树，布局引擎负责放置。网格是 12 列——Bootstrap 从 2011 年用到今天的同一个 idiom。写过哪怕一行 HTML/CSS，gpdf 的 API 都会让你觉得眼熟：",[485,486,491],"pre",{"className":487,"code":488,"language":489,"meta":490,"style":490},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","page := doc.AddPage()\npage.AutoRow(func(r *template.RowBuilder) {\n    r.Col(8, func(c *template.ColBuilder) {\n        c.Text(\"发票 #2026-0416\", template.FontSize(18), template.Bold())\n    })\n    r.Col(4, func(c *template.ColBuilder) {\n        c.Text(\"2026-04-16\", template.AlignRight())\n    })\n})\n","go","",[21,492,493,519,555,595,645,651,683,712,717],{"__ignoreMap":490},[494,495,498,502,506,509,512,516],"span",{"class":496,"line":497},"line",1,[494,499,501],{"class":500},"sTEyZ","page ",[494,503,505],{"class":504},"sMK4o",":=",[494,507,508],{"class":500}," doc",[494,510,511],{"class":504},".",[494,513,515],{"class":514},"s2Zo4","AddPage",[494,517,518],{"class":504},"()\n",[494,520,522,525,527,530,533,537,540,544,546,549,552],{"class":496,"line":521},2,[494,523,524],{"class":500},"page",[494,526,511],{"class":504},[494,528,529],{"class":514},"AutoRow",[494,531,532],{"class":504},"(func(",[494,534,536],{"class":535},"sHdIc","r",[494,538,539],{"class":504}," *",[494,541,543],{"class":542},"sBMFI","template",[494,545,511],{"class":504},[494,547,548],{"class":542},"RowBuilder",[494,550,551],{"class":504},")",[494,553,554],{"class":504}," {\n",[494,556,558,561,563,566,569,573,576,579,582,584,586,588,591,593],{"class":496,"line":557},3,[494,559,560],{"class":500},"    r",[494,562,511],{"class":504},[494,564,565],{"class":514},"Col",[494,567,568],{"class":504},"(",[494,570,572],{"class":571},"sbssI","8",[494,574,575],{"class":504},",",[494,577,578],{"class":504}," func(",[494,580,581],{"class":535},"c",[494,583,539],{"class":504},[494,585,543],{"class":542},[494,587,511],{"class":504},[494,589,590],{"class":542},"ColBuilder",[494,592,551],{"class":504},[494,594,554],{"class":504},[494,596,598,601,603,606,608,611,615,617,619,622,624,627,629,632,635,637,639,642],{"class":496,"line":597},4,[494,599,600],{"class":500},"        c",[494,602,511],{"class":504},[494,604,605],{"class":514},"Text",[494,607,568],{"class":504},[494,609,610],{"class":504},"\"",[494,612,614],{"class":613},"sfazB","发票 #2026-0416",[494,616,610],{"class":504},[494,618,575],{"class":504},[494,620,621],{"class":500}," template",[494,623,511],{"class":504},[494,625,626],{"class":514},"FontSize",[494,628,568],{"class":504},[494,630,631],{"class":571},"18",[494,633,634],{"class":504},"),",[494,636,621],{"class":500},[494,638,511],{"class":504},[494,640,641],{"class":514},"Bold",[494,643,644],{"class":504},"())\n",[494,646,648],{"class":496,"line":647},5,[494,649,650],{"class":504},"    })\n",[494,652,654,656,658,660,662,665,667,669,671,673,675,677,679,681],{"class":496,"line":653},6,[494,655,560],{"class":500},[494,657,511],{"class":504},[494,659,565],{"class":514},[494,661,568],{"class":504},[494,663,664],{"class":571},"4",[494,666,575],{"class":504},[494,668,578],{"class":504},[494,670,581],{"class":535},[494,672,539],{"class":504},[494,674,543],{"class":542},[494,676,511],{"class":504},[494,678,590],{"class":542},[494,680,551],{"class":504},[494,682,554],{"class":504},[494,684,686,688,690,692,694,696,699,701,703,705,707,710],{"class":496,"line":685},7,[494,687,600],{"class":500},[494,689,511],{"class":504},[494,691,605],{"class":514},[494,693,568],{"class":504},[494,695,610],{"class":504},[494,697,698],{"class":613},"2026-04-16",[494,700,610],{"class":504},[494,702,575],{"class":504},[494,704,621],{"class":500},[494,706,511],{"class":504},[494,708,709],{"class":514},"AlignRight",[494,711,644],{"class":504},[494,713,715],{"class":496,"line":714},8,[494,716,650],{"class":504},[494,718,720],{"class":496,"line":719},9,[494,721,722],{"class":504},"})\n",[18,724,725,726,730,731,734,735,738],{},"网格细节见 ",[91,727,729],{"href":728},"/zh/blog/12-column-grid","gpdf 的 12 列网格是怎么工作的？","。一句话版本：",[21,732,733],{},"Col(span, fn)"," 接受 1–12 的 span，",[21,736,737],{},"span / 12"," 是该列在行宽中的比例。",[13,740,742],{"id":741},"最小的-go-pdffpdf-gpdf-差分","最小的 go-pdf/fpdf → gpdf 差分",[18,744,745,746,748,749,751,752,754,755,758],{},"如果你是从 ",[21,747,36],{},"（而不是 ",[21,750,27],{},"）过来的，好消息：API 表面几乎一样——",[21,753,36],{}," 在调用层几乎没改过什么。迁移到 gpdf 的步骤和 ",[91,756,757],{"href":93},"gofpdf 指南","一致，从改一行 import 路径开始。",[18,760,761],{},"最小差分——一个\"生成 PDF\"的 HTTP handler：",[18,763,764],{},[30,765,766],{},"Before — go-pdf/fpdf:",[485,768,770],{"className":487,"code":769,"language":489,"meta":490,"style":490},"package main\n\nimport (\n    \"net/http\"\n\n    \"github.com/go-pdf/fpdf\"\n)\n\nfunc handler(w http.ResponseWriter, r *http.Request) {\n    pdf := fpdf.New(\"P\", \"mm\", \"A4\", \"\")\n    pdf.AddPage()\n    pdf.SetFont(\"Arial\", \"B\", 16)\n    pdf.Cell(40, 10, \"Hello, World!\")\n\n    w.Header().Set(\"Content-Type\", \"application/pdf\")\n    if err := pdf.Output(w); err != nil {\n        http.Error(w, err.Error(), 500)\n    }\n}\n",[21,771,772,780,786,795,806,810,819,824,828,868,919,931,966,997,1002,1039,1075,1107,1113],{"__ignoreMap":490},[494,773,774,777],{"class":496,"line":497},[494,775,776],{"class":504},"package",[494,778,779],{"class":542}," main\n",[494,781,782],{"class":496,"line":521},[494,783,785],{"emptyLinePlaceholder":784},true,"\n",[494,787,788,792],{"class":496,"line":557},[494,789,791],{"class":790},"s7zQu","import",[494,793,794],{"class":504}," (\n",[494,796,797,800,803],{"class":496,"line":597},[494,798,799],{"class":504},"    \"",[494,801,802],{"class":542},"net/http",[494,804,805],{"class":504},"\"\n",[494,807,808],{"class":496,"line":647},[494,809,785],{"emptyLinePlaceholder":784},[494,811,812,814,817],{"class":496,"line":653},[494,813,799],{"class":504},[494,815,816],{"class":542},"github.com/go-pdf/fpdf",[494,818,805],{"class":504},[494,820,821],{"class":496,"line":685},[494,822,823],{"class":504},")\n",[494,825,826],{"class":496,"line":714},[494,827,785],{"emptyLinePlaceholder":784},[494,829,830,833,836,838,841,844,846,849,851,854,856,859,861,864,866],{"class":496,"line":719},[494,831,832],{"class":504},"func",[494,834,835],{"class":514}," handler",[494,837,568],{"class":504},[494,839,840],{"class":535},"w",[494,842,843],{"class":542}," http",[494,845,511],{"class":504},[494,847,848],{"class":542},"ResponseWriter",[494,850,575],{"class":504},[494,852,853],{"class":535}," r",[494,855,539],{"class":504},[494,857,858],{"class":542},"http",[494,860,511],{"class":504},[494,862,863],{"class":542},"Request",[494,865,551],{"class":504},[494,867,554],{"class":504},[494,869,871,874,876,879,881,884,886,888,891,893,895,898,901,903,905,907,910,912,914,917],{"class":496,"line":870},10,[494,872,873],{"class":500},"    pdf ",[494,875,505],{"class":504},[494,877,878],{"class":500}," fpdf",[494,880,511],{"class":504},[494,882,883],{"class":514},"New",[494,885,568],{"class":504},[494,887,610],{"class":504},[494,889,890],{"class":613},"P",[494,892,610],{"class":504},[494,894,575],{"class":504},[494,896,897],{"class":504}," \"",[494,899,900],{"class":613},"mm",[494,902,610],{"class":504},[494,904,575],{"class":504},[494,906,897],{"class":504},[494,908,909],{"class":613},"A4",[494,911,610],{"class":504},[494,913,575],{"class":504},[494,915,916],{"class":504}," \"\"",[494,918,823],{"class":504},[494,920,922,925,927,929],{"class":496,"line":921},11,[494,923,924],{"class":500},"    pdf",[494,926,511],{"class":504},[494,928,515],{"class":514},[494,930,518],{"class":504},[494,932,934,936,938,941,943,945,948,950,952,954,957,959,961,964],{"class":496,"line":933},12,[494,935,924],{"class":500},[494,937,511],{"class":504},[494,939,940],{"class":514},"SetFont",[494,942,568],{"class":504},[494,944,610],{"class":504},[494,946,947],{"class":613},"Arial",[494,949,610],{"class":504},[494,951,575],{"class":504},[494,953,897],{"class":504},[494,955,956],{"class":613},"B",[494,958,610],{"class":504},[494,960,575],{"class":504},[494,962,963],{"class":571}," 16",[494,965,823],{"class":504},[494,967,969,971,973,976,978,981,983,986,988,990,993,995],{"class":496,"line":968},13,[494,970,924],{"class":500},[494,972,511],{"class":504},[494,974,975],{"class":514},"Cell",[494,977,568],{"class":504},[494,979,980],{"class":571},"40",[494,982,575],{"class":504},[494,984,985],{"class":571}," 10",[494,987,575],{"class":504},[494,989,897],{"class":504},[494,991,992],{"class":613},"Hello, World!",[494,994,610],{"class":504},[494,996,823],{"class":504},[494,998,1000],{"class":496,"line":999},14,[494,1001,785],{"emptyLinePlaceholder":784},[494,1003,1005,1008,1010,1013,1016,1019,1021,1023,1026,1028,1030,1032,1035,1037],{"class":496,"line":1004},15,[494,1006,1007],{"class":500},"    w",[494,1009,511],{"class":504},[494,1011,1012],{"class":514},"Header",[494,1014,1015],{"class":504},"().",[494,1017,1018],{"class":514},"Set",[494,1020,568],{"class":504},[494,1022,610],{"class":504},[494,1024,1025],{"class":613},"Content-Type",[494,1027,610],{"class":504},[494,1029,575],{"class":504},[494,1031,897],{"class":504},[494,1033,1034],{"class":613},"application/pdf",[494,1036,610],{"class":504},[494,1038,823],{"class":504},[494,1040,1042,1045,1048,1050,1053,1055,1058,1060,1062,1065,1067,1070,1073],{"class":496,"line":1041},16,[494,1043,1044],{"class":790},"    if",[494,1046,1047],{"class":500}," err ",[494,1049,505],{"class":504},[494,1051,1052],{"class":500}," pdf",[494,1054,511],{"class":504},[494,1056,1057],{"class":514},"Output",[494,1059,568],{"class":504},[494,1061,840],{"class":500},[494,1063,1064],{"class":504},");",[494,1066,1047],{"class":500},[494,1068,1069],{"class":504},"!=",[494,1071,1072],{"class":504}," nil",[494,1074,554],{"class":504},[494,1076,1078,1081,1083,1086,1088,1090,1092,1095,1097,1099,1102,1105],{"class":496,"line":1077},17,[494,1079,1080],{"class":500},"        http",[494,1082,511],{"class":504},[494,1084,1085],{"class":514},"Error",[494,1087,568],{"class":504},[494,1089,840],{"class":500},[494,1091,575],{"class":504},[494,1093,1094],{"class":500}," err",[494,1096,511],{"class":504},[494,1098,1085],{"class":514},[494,1100,1101],{"class":504},"(),",[494,1103,1104],{"class":571}," 500",[494,1106,823],{"class":504},[494,1108,1110],{"class":496,"line":1109},18,[494,1111,1112],{"class":504},"    }\n",[494,1114,1116],{"class":496,"line":1115},19,[494,1117,1118],{"class":504},"}\n",[18,1120,1121],{},[30,1122,1123],{},"After — gpdf:",[485,1125,1127],{"className":487,"code":1126,"language":489,"meta":490,"style":490},"package main\n\nimport (\n    \"net/http\"\n\n    \"github.com/gpdf-dev/gpdf\"\n    \"github.com/gpdf-dev/gpdf/document\"\n    \"github.com/gpdf-dev/gpdf/template\"\n)\n\nfunc handler(w http.ResponseWriter, r *http.Request) {\n    doc := gpdf.NewDocument(\n        gpdf.WithPageSize(document.A4),\n        gpdf.WithMargins(document.UniformEdges(document.Mm(20))),\n    )\n\n    page := doc.AddPage()\n    page.AutoRow(func(r *template.RowBuilder) {\n        r.Col(12, func(c *template.ColBuilder) {\n            c.Text(\"Hello, World!\", template.FontSize(16), template.Bold())\n        })\n    })\n\n    w.Header().Set(\"Content-Type\", \"application/pdf\")\n    if err := doc.Render(w); err != nil {\n        http.Error(w, err.Error(), 500)\n    }\n}\n",[21,1128,1129,1135,1139,1145,1153,1157,1165,1174,1183,1187,1191,1223,1241,1263,1298,1303,1307,1322,1347,1379,1420,1426,1431,1436,1467,1497,1524,1529],{"__ignoreMap":490},[494,1130,1131,1133],{"class":496,"line":497},[494,1132,776],{"class":504},[494,1134,779],{"class":542},[494,1136,1137],{"class":496,"line":521},[494,1138,785],{"emptyLinePlaceholder":784},[494,1140,1141,1143],{"class":496,"line":557},[494,1142,791],{"class":790},[494,1144,794],{"class":504},[494,1146,1147,1149,1151],{"class":496,"line":597},[494,1148,799],{"class":504},[494,1150,802],{"class":542},[494,1152,805],{"class":504},[494,1154,1155],{"class":496,"line":647},[494,1156,785],{"emptyLinePlaceholder":784},[494,1158,1159,1161,1163],{"class":496,"line":653},[494,1160,799],{"class":504},[494,1162,434],{"class":542},[494,1164,805],{"class":504},[494,1166,1167,1169,1172],{"class":496,"line":685},[494,1168,799],{"class":504},[494,1170,1171],{"class":542},"github.com/gpdf-dev/gpdf/document",[494,1173,805],{"class":504},[494,1175,1176,1178,1181],{"class":496,"line":714},[494,1177,799],{"class":504},[494,1179,1180],{"class":542},"github.com/gpdf-dev/gpdf/template",[494,1182,805],{"class":504},[494,1184,1185],{"class":496,"line":719},[494,1186,823],{"class":504},[494,1188,1189],{"class":496,"line":870},[494,1190,785],{"emptyLinePlaceholder":784},[494,1192,1193,1195,1197,1199,1201,1203,1205,1207,1209,1211,1213,1215,1217,1219,1221],{"class":496,"line":921},[494,1194,832],{"class":504},[494,1196,835],{"class":514},[494,1198,568],{"class":504},[494,1200,840],{"class":535},[494,1202,843],{"class":542},[494,1204,511],{"class":504},[494,1206,848],{"class":542},[494,1208,575],{"class":504},[494,1210,853],{"class":535},[494,1212,539],{"class":504},[494,1214,858],{"class":542},[494,1216,511],{"class":504},[494,1218,863],{"class":542},[494,1220,551],{"class":504},[494,1222,554],{"class":504},[494,1224,1225,1228,1230,1233,1235,1238],{"class":496,"line":933},[494,1226,1227],{"class":500},"    doc ",[494,1229,505],{"class":504},[494,1231,1232],{"class":500}," gpdf",[494,1234,511],{"class":504},[494,1236,1237],{"class":514},"NewDocument",[494,1239,1240],{"class":504},"(\n",[494,1242,1243,1246,1248,1251,1253,1256,1258,1260],{"class":496,"line":968},[494,1244,1245],{"class":500},"        gpdf",[494,1247,511],{"class":504},[494,1249,1250],{"class":514},"WithPageSize",[494,1252,568],{"class":504},[494,1254,1255],{"class":500},"document",[494,1257,511],{"class":504},[494,1259,909],{"class":500},[494,1261,1262],{"class":504},"),\n",[494,1264,1265,1267,1269,1272,1274,1276,1278,1281,1283,1285,1287,1290,1292,1295],{"class":496,"line":999},[494,1266,1245],{"class":500},[494,1268,511],{"class":504},[494,1270,1271],{"class":514},"WithMargins",[494,1273,568],{"class":504},[494,1275,1255],{"class":500},[494,1277,511],{"class":504},[494,1279,1280],{"class":514},"UniformEdges",[494,1282,568],{"class":504},[494,1284,1255],{"class":500},[494,1286,511],{"class":504},[494,1288,1289],{"class":514},"Mm",[494,1291,568],{"class":504},[494,1293,1294],{"class":571},"20",[494,1296,1297],{"class":504},"))),\n",[494,1299,1300],{"class":496,"line":1004},[494,1301,1302],{"class":504},"    )\n",[494,1304,1305],{"class":496,"line":1041},[494,1306,785],{"emptyLinePlaceholder":784},[494,1308,1309,1312,1314,1316,1318,1320],{"class":496,"line":1077},[494,1310,1311],{"class":500},"    page ",[494,1313,505],{"class":504},[494,1315,508],{"class":500},[494,1317,511],{"class":504},[494,1319,515],{"class":514},[494,1321,518],{"class":504},[494,1323,1324,1327,1329,1331,1333,1335,1337,1339,1341,1343,1345],{"class":496,"line":1109},[494,1325,1326],{"class":500},"    page",[494,1328,511],{"class":504},[494,1330,529],{"class":514},[494,1332,532],{"class":504},[494,1334,536],{"class":535},[494,1336,539],{"class":504},[494,1338,543],{"class":542},[494,1340,511],{"class":504},[494,1342,548],{"class":542},[494,1344,551],{"class":504},[494,1346,554],{"class":504},[494,1348,1349,1352,1354,1356,1358,1361,1363,1365,1367,1369,1371,1373,1375,1377],{"class":496,"line":1115},[494,1350,1351],{"class":500},"        r",[494,1353,511],{"class":504},[494,1355,565],{"class":514},[494,1357,568],{"class":504},[494,1359,1360],{"class":571},"12",[494,1362,575],{"class":504},[494,1364,578],{"class":504},[494,1366,581],{"class":535},[494,1368,539],{"class":504},[494,1370,543],{"class":542},[494,1372,511],{"class":504},[494,1374,590],{"class":542},[494,1376,551],{"class":504},[494,1378,554],{"class":504},[494,1380,1382,1385,1387,1389,1391,1393,1395,1397,1399,1401,1403,1405,1407,1410,1412,1414,1416,1418],{"class":496,"line":1381},20,[494,1383,1384],{"class":500},"            c",[494,1386,511],{"class":504},[494,1388,605],{"class":514},[494,1390,568],{"class":504},[494,1392,610],{"class":504},[494,1394,992],{"class":613},[494,1396,610],{"class":504},[494,1398,575],{"class":504},[494,1400,621],{"class":500},[494,1402,511],{"class":504},[494,1404,626],{"class":514},[494,1406,568],{"class":504},[494,1408,1409],{"class":571},"16",[494,1411,634],{"class":504},[494,1413,621],{"class":500},[494,1415,511],{"class":504},[494,1417,641],{"class":514},[494,1419,644],{"class":504},[494,1421,1423],{"class":496,"line":1422},21,[494,1424,1425],{"class":504},"        })\n",[494,1427,1429],{"class":496,"line":1428},22,[494,1430,650],{"class":504},[494,1432,1434],{"class":496,"line":1433},23,[494,1435,785],{"emptyLinePlaceholder":784},[494,1437,1439,1441,1443,1445,1447,1449,1451,1453,1455,1457,1459,1461,1463,1465],{"class":496,"line":1438},24,[494,1440,1007],{"class":500},[494,1442,511],{"class":504},[494,1444,1012],{"class":514},[494,1446,1015],{"class":504},[494,1448,1018],{"class":514},[494,1450,568],{"class":504},[494,1452,610],{"class":504},[494,1454,1025],{"class":613},[494,1456,610],{"class":504},[494,1458,575],{"class":504},[494,1460,897],{"class":504},[494,1462,1034],{"class":613},[494,1464,610],{"class":504},[494,1466,823],{"class":504},[494,1468,1470,1472,1474,1476,1478,1480,1483,1485,1487,1489,1491,1493,1495],{"class":496,"line":1469},25,[494,1471,1044],{"class":790},[494,1473,1047],{"class":500},[494,1475,505],{"class":504},[494,1477,508],{"class":500},[494,1479,511],{"class":504},[494,1481,1482],{"class":514},"Render",[494,1484,568],{"class":504},[494,1486,840],{"class":500},[494,1488,1064],{"class":504},[494,1490,1047],{"class":500},[494,1492,1069],{"class":504},[494,1494,1072],{"class":504},[494,1496,554],{"class":504},[494,1498,1500,1502,1504,1506,1508,1510,1512,1514,1516,1518,1520,1522],{"class":496,"line":1499},26,[494,1501,1080],{"class":500},[494,1503,511],{"class":504},[494,1505,1085],{"class":514},[494,1507,568],{"class":504},[494,1509,840],{"class":500},[494,1511,575],{"class":504},[494,1513,1094],{"class":500},[494,1515,511],{"class":504},[494,1517,1085],{"class":514},[494,1519,1101],{"class":504},[494,1521,1104],{"class":571},[494,1523,823],{"class":504},[494,1525,1527],{"class":496,"line":1526},27,[494,1528,1112],{"class":504},[494,1530,1532],{"class":496,"line":1531},28,[494,1533,1118],{"class":504},[18,1535,1536,1537,1539,1540,1543,1544,1547,1548,82],{},"三行游标代码变成三次 builder 调用。结构直接呈现在源码里——不再藏在 ",[21,1538,975],{}," 调用顺序中。CJK 只需再加 ",[21,1541,1542],{},"gpdf.WithFont(\"NotoSansJP\", ttfBytes)"," ——不需要 ",[21,1545,1546],{},"AddUTF8Font","，不需要文件系统路径，不需要 UTF-8 标志。完整流程见 ",[91,1549,1551],{"href":1550},"/zh/blog/embed-japanese-font","如何在 gpdf 中嵌入日文字体？",[18,1553,1554,1557,1558,1560],{},[91,1555,1556],{"href":93},"gofpdf 迁移指南"," 中还有 5 组 before/after：表格、重复页眉页脚、页码、绝对定位。那些内容对 ",[21,1559,36],{}," 用户一字不差地适用——只需改 import 路径。",[13,1562,1563],{"id":1563},"基准数据",[18,1565,1566,1567,1570],{},"\"快\"很容易说出口，很难说清楚。下表来自 ",[21,1568,1569],{},"gpdf/_benchmark/benchmark_test.go","，在 Apple M1、Go 1.25 上测得。工作负载是生产代码真正会做的——不是专门挑来讨好某个库的 micro-benchmark。",[199,1572,1573,1591],{},[202,1574,1575],{},[205,1576,1577,1580,1582,1585,1588],{},[208,1578,1579],{},"基准",[208,1581,43],{},[208,1583,1584],{},"gofpdf",[208,1586,1587],{},"gopdf",[208,1589,1590],{},"Maroto v2",[227,1592,1593,1612,1631,1649],{},[205,1594,1595,1598,1603,1606,1609],{},[232,1596,1597],{},"单页 (hello)",[232,1599,1600],{},[30,1601,1602],{},"13 µs",[232,1604,1605],{},"132 µs",[232,1607,1608],{},"423 µs",[232,1610,1611],{},"237 µs",[205,1613,1614,1617,1622,1625,1628],{},[232,1615,1616],{},"4×10 明细表",[232,1618,1619],{},[30,1620,1621],{},"108 µs",[232,1623,1624],{},"241 µs",[232,1626,1627],{},"835 µs",[232,1629,1630],{},"8.6 ms",[205,1632,1633,1636,1641,1644,1646],{},[232,1634,1635],{},"100 页报告",[232,1637,1638],{},[30,1639,1640],{},"683 µs",[232,1642,1643],{},"11.7 ms",[232,1645,1630],{},[232,1647,1648],{},"19.8 ms",[205,1650,1651,1654,1659,1662,1665],{},[232,1652,1653],{},"复杂 CJK 发票",[232,1655,1656],{},[30,1657,1658],{},"133 µs",[232,1660,1661],{},"254 µs",[232,1663,1664],{},"997 µs",[232,1666,1667],{},"10.4 ms",[18,1669,1670,1671,1674],{},"单页 13 µs 意味着单核每秒可以产出约 75,000 份 hello-world PDF；108 µs 的发票意味着每秒约 9,000 份。",[30,1672,1673],{},"重点不是跑分自吹","——而是你可以不再纠结\"PDF 生成要不要缓存、要不要塞进异步队列\"。对大多数工作负载，请求路径上直接生成就够了。",[18,1676,1677,1678,1680],{},"表格基准里 Maroto v2 之所以慢，是因为它底层驱动 ",[21,1679,36],{}," 又在上面加了一层自己的布局。这不是在批评 Maroto 的 API——API 是好的——而是坐在 fpdf 地基上的结构性成本。等 Maroto v3 甩掉 fpdf 依赖时，这一列的数字会变。",[18,1682,1683],{},"100 页基准值得多说两句。gpdf 的流式写入会随着行的布局过程同时输出内容；gofpdf 每页缓冲更多状态。对分页密集的工作负载（月度报告、目录、合规导出），在文档体量上限处差距是\"分钟 vs 秒\"的数量级。",[13,1685,1687,1688,1691],{"id":1686},"什么时候-不该-选-gpdf","什么时候 ",[56,1689,1690],{},"不该"," 选 gpdf",[18,1693,1694],{},"迁移类文章必须诚实回答 \"什么时候不迁\"：",[440,1696,1697,1710,1719,1732],{},[110,1698,1699,1702,1703,1706,1707,1709],{},[30,1700,1701],{},"AcroForm / 可填写表单","。如果你要生成让用户在 Acrobat 里填写的 PDF，gpdf 的表单字段支持还很少。",[21,1704,1705],{},"unidoc"," 在这块更完整；",[21,1708,279],{}," 有部分 AcroForm 支持。未来会补上，但今天是缺口。",[110,1711,1712,82,1715,1718],{},[30,1713,1714],{},"任意矢量路径、复杂绘图",[21,1716,1717],{},"c.Line()"," 在列内画一条横线。如果你要贝塞尔曲线、自定义路径、渐变填充来画图表或技术图，gpdf 现在到不了。（预渲染的图表图片嵌入没问题——这里说的是绘图原语本身。）",[110,1720,1721,1727,1728,1731],{},[30,1722,1723,1724,1726],{},"大量使用 ",[21,1725,396],{}," 的现成 gofpdf 代码库","。如果你的代码是 2000 行游标操作，迁移更像重写而不是替换。重写后的代码几乎总是更短，但在 deadline 当天 \"几乎\" 是很冷的安慰。",[91,1729,1730],{"href":93},"迁移指南"," 里有诚实的工作量估算。",[110,1733,1734,1737,1738,1741,1742,1744],{},[30,1735,1736],{},"现在就要全 CSS 支持的 HTML → PDF","。gpdf 的 ",[21,1739,1740],{},"gpdf-pro"," 扩展有 HTML 子集，但与 Chromium 的完整 CSS 对等不是目标。如果模板是复杂的 React 组件，",[21,1743,343],{}," 或商业 API 更直接。",[18,1746,1747,1748,1751],{},"以上都不刺到你，gpdf 就是默认选择。有一项刺到了，正常的做法是",[30,1749,1750],{},"两个库并存","——新 PDF 用 gpdf，边缘场景留在原库，等 gpdf 追上后再迁。",[13,1753,1754],{"id":1754},"合规视角",[18,1756,1757,1758,1761],{},"生态文章里比较少有人讲这个：",[30,1759,1760],{},"归档的依赖会出现在 SOC 2 和 ISO 27001 的审计报告里","。审计官想确认供应链里的三方代码在积极维护。\"2021 年归档\" 会触发 finding，\"2025 年归档\" 也会。\"内部 fork\" 会触发关于 0day 怎么打补丁的追问。",[18,1763,1764,1765,82,1768,1770],{},"这就是为什么一些在大公司过安全评审的团队悄悄问我们，\"gpdf 什么时候出稳定 v1\"。答案是：",[30,1766,1767],{},"已经出了",[21,1769,434],{}," 有 semver tag，v1 API 面已冻结。项目有安全联系人、负责任披露政策，CI 会在 Go 1.22 到 1.26 全范围跑测试。",[18,1772,1773,1774,82],{},"你不是为了过审才迁——",[30,1775,1776],{},"是在审计开口要求之前先动",[13,1778,1780],{"id":1779},"faq","FAQ",[18,1782,1783,1786,1787,1789,1790,1792],{},[30,1784,1785],{},"\"现代 Go PDF 栈\" 是 gpdf 一个库，还是多个库组合？","\n对大多数团队就是 gpdf 一个。单库覆盖文档生成、CJK、表格、网格、分页、输出。有可填写表单需求的团队会给那类文档单独搭上 ",[21,1788,279],{}," 或 ",[21,1791,1705],{},"；图表密集的团队会把图表预渲染成 PNG 再嵌入。这里\"栈\"指的是一张短清单，不是分层架构。",[18,1794,1795,1798],{},[30,1796,1797],{},"迁移期间能把 gpdf 和 go-pdf/fpdf 并存吗？","\n可以。import 路径和类型都不一样。新接口走 gpdf，旧接口留在 go-pdf/fpdf，等有时间再重写。运行时没有冲突。",[18,1800,1801,1804,1805,1808],{},[30,1802,1803],{},"会有 go-pdf/fpdf v3 或新 fork 吗？","\n也许。gpdf 的赌注不是\"那个 fork 永远不会 unarchive\"——而是",[30,1806,1807],{},"架构跟不上现在要造的东西","。新 fork 如果不改布局模型，会继承同样的限制；如果改了，那它就更接近 gpdf 而不是 fpdf。",[18,1810,1811,1816,1817,165,1820,165,1823,1826],{},[30,1812,1813,1815],{},[21,1814,279],{}," 作为现代替代怎么样？","\n真的在维护、真的零依赖。API 是坐标级的——",[21,1818,1819],{},"SetX",[21,1821,1822],{},"SetY",[21,1824,1825],{},"CellWithOption","——适合表单叠加和固定模板。对于带表格和重复页眉页脚的发票类文档，你最后还是得在上面写一层布局辅助，掉进 gofpdf 用户掉过的同一个坑。gpdf 和 gopdf 其实不真正竞争——解决的是相邻问题。",[18,1828,1829,1832,1835],{},[30,1830,1831],{},"gpdf 有商业/托管版吗？",[21,1833,1834],{},"gpdf-api"," 正在做——一个接收 JSON 模板、返回 PDF 的托管 API。还没公开。上线时这里会发文章。OSS 库会继续保持 MIT、零依赖、独立可用。",[18,1837,1838,1841],{},[30,1839,1840],{},"路线图的优先级？","\n2026-04 公开路线图：(1) AcroForm 表单字段；(2) 完整 PDF/A-3 合规；(3) gpdf-pro 的 HTML→PDF 覆盖扩展；(4) RTL 文本支持（阿拉伯语、希伯来语）。优先级反馈欢迎在 GitHub issue 里提。",[13,1843,1845],{"id":1844},"试用-gpdf","试用 gpdf",[18,1847,1848],{},"gpdf 是一个 Go 语言的 PDF 生成库。MIT 许可、零外部依赖、原生 CJK 支持。",[485,1850,1854],{"className":1851,"code":1852,"language":1853,"meta":490,"style":490},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","go get github.com/gpdf-dev/gpdf\n","bash",[21,1855,1856],{"__ignoreMap":490},[494,1857,1858,1860,1863],{"class":496,"line":497},[494,1859,489],{"class":542},[494,1861,1862],{"class":613}," get",[494,1864,1865],{"class":613}," github.com/gpdf-dev/gpdf\n",[18,1867,1868,1874,1875],{},[91,1869,1873],{"href":1870,"rel":1871},"https://github.com/gpdf-dev/gpdf",[1872],"nofollow","⭐ 在 GitHub 加星"," · ",[91,1876,1879],{"href":1877,"rel":1878},"https://gpdf.dev/zh/docs/quickstart",[1872],"查看文档",[13,1881,1882],{"id":1882},"延伸阅读",[440,1884,1885,1891,1898,1903],{},[110,1886,1887,1890],{},[91,1888,1889],{"href":93},"gofpdf 已归档。如何迁移到 gpdf。"," — 逐 API 对照",[110,1892,1893,1897],{},[91,1894,1896],{"href":1895},"/zh/blog/go-pdf-library-showdown-2026","Go PDF 库横评 2026"," — 更深入的对比基准与特性表",[110,1899,1900,1902],{},[91,1901,729],{"href":728}," — 取代游标操作的 builder 习语",[110,1904,1905,1907,1908,1910],{},[91,1906,1551],{"href":1550}," — 不用 ",[21,1909,1546],{}," 的 CJK",[1912,1913,1914],"style",{},"html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}",{"title":490,"searchDepth":521,"depth":521,"links":1916},[1917,1918,1919,1920,1921,1922,1923,1924,1925,1927,1928,1929,1930],{"id":15,"depth":521,"text":16},{"id":47,"depth":521,"text":47},{"id":101,"depth":521,"text":102},{"id":149,"depth":521,"text":150},{"id":193,"depth":521,"text":194},{"id":427,"depth":521,"text":428},{"id":741,"depth":521,"text":742},{"id":1563,"depth":521,"text":1563},{"id":1686,"depth":521,"text":1926},"什么时候 不该 选 gpdf",{"id":1754,"depth":521,"text":1754},{"id":1779,"depth":521,"text":1780},{"id":1844,"depth":521,"text":1845},{"id":1882,"depth":521,"text":1882},"jung-kurt/gofpdf 2021 年归档，go-pdf/fpdf 2025 年跟进。2026 年我们实际在用的 Go PDF 栈是 gpdf — 原因、权衡与迁移路径。",false,"md",null,{},"/zh/blog/go-pdf-fpdf-archived",{"title":5,"description":1931},"zh/blog/006.go-pdf-fpdf-archived",[1940,1941,1942],"migration","comparison","benchmark","4SZ-8PgoRS0KICBmNt9aOdHaR_NxJblqX_2WL5rscSc",1776529262274]