[{"data":1,"prerenderedAt":5090},["ShallowReactive",2],{"blog-en-gofpdf-migration":3},{"id":4,"title":5,"author":6,"body":9,"date":5052,"description":5053,"draft":5054,"extension":5055,"howTo":5056,"image":5080,"meta":5081,"navigation":513,"path":5082,"seo":5083,"stem":5084,"tags":5085,"updated":5080,"__hash__":5089},"blog/blog/001.gofpdf-migration.md","gofpdf is archived. Here's how to migrate to gpdf.",{"name":7,"url":8},"gpdf team","https://gpdf.dev",{"type":10,"value":11,"toc":5036},"minimark",[12,17,38,49,52,66,69,73,79,86,93,96,100,109,137,143,147,150,430,444,474,478,481,486,717,722,1186,1196,1209,1213,1223,1227,1979,1982,1986,2367,2384,2387,2391,2397,2401,2564,2570,2574,3027,3030,3041,3044,3047,3051,3070,3074,3396,3402,3406,4082,4097,4101,4115,4119,4397,4401,4721,4739,4743,4753,4849,4852,4855,4859,4862,4903,4906,4910,4916,4938,4948,4960,4966,4970,4973,4990,5005,5009,5032],[13,14,16],"h2",{"id":15},"tldr","TL;DR",[18,19,20,24,25,29,30,33,34,37],"p",{},[21,22,23],"strong",{},"gpdf"," is a pure-Go, zero-dependency PDF library that handles CJK natively (no ",[26,27,28],"code",{},"AddUTF8Font"," dance), uses a 12-column grid instead of pixel-pushing with ",[26,31,32],{},"SetXY",", and runs roughly ",[21,35,36],{},"10× faster than gofpdf"," on the same workloads. The migration is mostly about replacing imperative cursor calls with declarative builders. This guide walks the mapping with five before/after pairs.",[18,39,40,41,44,45,48],{},"A teammate opened a fresh Go project last week, ran ",[26,42,43],{},"go get github.com/jung-kurt/gofpdf",", and pinged me ten minutes later with a screenshot of the GitHub banner: ",[21,46,47],{},"\"This repository has been archived by the owner. It is now read-only.\""," Then a follow-up: \"Wait, the fork is archived too?\"",[18,50,51],{},"Yes. Both of them.",[18,53,54,57,58,61,62,65],{},[26,55,56],{},"jung-kurt/gofpdf"," was archived on ",[21,59,60],{},"September 8, 2021",". The community fork at ",[26,63,64],{},"go-pdf/fpdf"," shipped its last release in 2023 and was archived in 2025. The Go PDF library that two thirds of Stack Overflow answers still point to has been read-only for over four years, and the fork that was supposed to replace it is gone too.",[18,67,68],{},"If you have a gofpdf codebase in production, this post is a migration map. If you're starting a new project and reflexively reached for gofpdf because that's what the search results showed, this is the alternative.",[13,70,72],{"id":71},"why-gofpdf-is-actually-staying-dead","Why gofpdf is actually staying dead",[18,74,75,76,78],{},"Open-source libraries don't always die. Sometimes the maintainer steps back and someone else picks it up. That's what most people assumed would happen with gofpdf — and for a while, it did. The community fork at ",[26,77,64],{}," reorganized the code, fixed a few long-standing bugs, accepted PRs, and felt like a genuine continuation.",[18,80,81,82],{},"Then in early 2025 the fork was archived too. The README now reads, in part: ",[83,84,85],"em",{},"\"This project is no longer actively maintained. Consider using a different library.\"",[18,87,88,89,92],{},"The reason matters less than the consequence: every Go project that depends on gofpdf is now sitting on ",[21,90,91],{},"two layers"," of unmaintained code. Security issues won't be patched. The PDF 2.0 spec landed in 2020 and gofpdf still doesn't support most of what changed. Go 1.25's loop variable semantics work fine with gofpdf today, but anything that breaks tomorrow is on you to fix in a fork.",[18,94,95],{},"This isn't a \"the library has bugs\" problem. It's a supply chain problem.",[13,97,99],{"id":98},"what-people-actually-use-gofpdf-for","What people actually use gofpdf for",[18,101,102,103,105,106,108],{},"Before getting into the mapping, it helps to be specific about the workloads that actually get migrated. From the issue trackers and Stack Overflow questions on both ",[26,104,56],{}," and ",[26,107,64],{},", the dominant uses are:",[110,111,112,119,125,131],"ol",{},[113,114,115,118],"li",{},[21,116,117],{},"Invoices and receipts"," — header, customer block, line items table, totals, footer.",[113,120,121,124],{},[21,122,123],{},"Reports"," — multi-page documents with repeating headers, page numbers, charts as images.",[113,126,127,130],{},[21,128,129],{},"Forms and certificates"," — fixed-position text overlaid on a template.",[113,132,133,136],{},[21,134,135],{},"CJK documents"," — invoices and shipping labels in Japanese, Chinese, Korean.",[18,138,139,140,142],{},"The first three are well-served by gpdf's builder API. The fourth — CJK — is where gpdf has the largest gap over gofpdf. gofpdf required you to call ",[26,141,28],{},", manage a TTF file path, and hope your text didn't contain characters outside the basic plane. gpdf treats CJK as a first-class case: register a TrueType font, write Japanese, get a PDF.",[13,144,146],{"id":145},"the-api-mapping-table","The API mapping table",[18,148,149],{},"The table below is the cheat sheet. Sections after it walk five concrete before/after pairs.",[151,152,153,168],"table",{},[154,155,156],"thead",{},[157,158,159,163,166],"tr",{},[160,161,162],"th",{},"What you want to do",[160,164,165],{},"gofpdf",[160,167,23],{},[169,170,171,187,210,233,251,266,284,302,317,332,350,365,380,400,415],"tbody",{},[157,172,173,177,182],{},[174,175,176],"td",{},"Create a document",[174,178,179],{},[26,180,181],{},"gofpdf.New(\"P\", \"mm\", \"A4\", \"\")",[174,183,184],{},[26,185,186],{},"gpdf.NewDocument(gpdf.WithPageSize(document.A4))",[157,188,189,192,197],{},[174,190,191],{},"Add a page",[174,193,194],{},[26,195,196],{},"pdf.AddPage()",[174,198,199,202,203],{},[26,200,201],{},"doc.AddPage()"," ",[83,204,205,206,209],{},"(returns a ",[26,207,208],{},"*PageBuilder",")",[157,211,212,215,220],{},[174,213,214],{},"Set a font",[174,216,217],{},[26,218,219],{},"pdf.SetFont(\"Arial\", \"B\", 16)",[174,221,222,225,226,225,229,232],{},[26,223,224],{},"template.FontFamily(...)",", ",[26,227,228],{},"template.Bold()",[26,230,231],{},"template.FontSize(16)"," as text options",[157,234,235,238,243],{},[174,236,237],{},"Register a TTF (CJK)",[174,239,240],{},[26,241,242],{},"pdf.AddUTF8Font(\"noto\", \"\", \"NotoSansJP-Regular.ttf\")",[174,244,245,202,248],{},[26,246,247],{},"gpdf.WithFont(\"NotoSansJP\", ttfBytes)",[83,249,250],{},"(at construction)",[157,252,253,256,261],{},[174,254,255],{},"Write a single line",[174,257,258],{},[26,259,260],{},"pdf.Cell(40, 10, \"hi\")",[174,262,263],{},[26,264,265],{},"c.Text(\"hi\")",[157,267,268,271,276],{},[174,269,270],{},"Write wrapped text",[174,272,273],{},[26,274,275],{},"pdf.MultiCell(0, 10, body, \"\", \"L\", false)",[174,277,278,202,281],{},[26,279,280],{},"c.Text(body)",[83,282,283],{},"(wraps automatically)",[157,285,286,289,294],{},[174,287,288],{},"Set text color",[174,290,291],{},[26,292,293],{},"pdf.SetTextColor(255, 0, 0)",[174,295,296,202,299],{},[26,297,298],{},"template.TextColor(pdf.Red)",[83,300,301],{},"(per-text option)",[157,303,304,307,312],{},[174,305,306],{},"Draw a horizontal rule",[174,308,309],{},[26,310,311],{},"pdf.Line(x1, y1, x2, y2)",[174,313,314],{},[26,315,316],{},"c.Line(template.LineThickness(document.Pt(1)))",[157,318,319,322,327],{},[174,320,321],{},"Embed an image",[174,323,324],{},[26,325,326],{},"pdf.ImageOptions(\"logo.png\", x, y, w, h, ...)",[174,328,329],{},[26,330,331],{},"c.Image(imgBytes, template.FitWidth(document.Mm(50)))",[157,333,334,337,342],{},[174,335,336],{},"Set XY cursor",[174,338,339],{},[26,340,341],{},"pdf.SetXY(x, y)",[174,343,344],{},[83,345,346,347,209],{},"(no equivalent — use rows/cols, or ",[26,348,349],{},"page.Absolute(x, y, fn)",[157,351,352,355,360],{},[174,353,354],{},"Repeating header",[174,356,357],{},[26,358,359],{},"pdf.SetHeaderFunc(fn)",[174,361,362],{},[26,363,364],{},"doc.Header(fn)",[157,366,367,370,375],{},[174,368,369],{},"Repeating footer",[174,371,372],{},[26,373,374],{},"pdf.SetFooterFunc(fn)",[174,376,377],{},[26,378,379],{},"doc.Footer(fn)",[157,381,382,385,391],{},[174,383,384],{},"Page number",[174,386,387,388],{},"manual: ",[26,389,390],{},"pdf.PageNo()",[174,392,393,396,397],{},[26,394,395],{},"c.PageNumber()"," / ",[26,398,399],{},"c.TotalPages()",[157,401,402,405,410],{},[174,403,404],{},"Output to file",[174,406,407],{},[26,408,409],{},"pdf.OutputFileAndClose(\"out.pdf\")",[174,411,412],{},[26,413,414],{},"data, _ := doc.Generate(); os.WriteFile(\"out.pdf\", data, 0o644)",[157,416,417,420,425],{},[174,418,419],{},"Output to writer",[174,421,422],{},[26,423,424],{},"pdf.Output(w)",[174,426,427],{},[26,428,429],{},"doc.Render(w)",[18,431,432,433,436,437,440,441,443],{},"The shape change is the biggest thing: gofpdf is ",[21,434,435],{},"imperative",", gpdf is ",[21,438,439],{},"declarative",". In gofpdf you push a cursor around the page and write whatever it points at. In gpdf you describe a tree of rows and columns and let the layout engine place things. The first few snippets feel longer in gpdf. By the third you stop missing ",[26,442,32],{},".",[18,445,446,447,225,450,225,453,456,457,225,460,225,463,225,466,469,470,473],{},"A note on units. gofpdf lets you pick a base unit at construction (",[26,448,449],{},"\"mm\"",[26,451,452],{},"\"pt\"",[26,454,455],{},"\"in\"","). gpdf is always points internally and gives you helpers — ",[26,458,459],{},"document.Mm(20)",[26,461,462],{},"document.Pt(12)",[26,464,465],{},"document.Cm(1)",[26,467,468],{},"document.In(0.5)"," — for whichever you prefer at the call site. This is closer to CSS than to gofpdf, and once you have a header on every page using ",[26,471,472],{},"document.Mm(15)"," margins, you stop thinking about it.",[13,475,477],{"id":476},"before-after-1-the-simplest-possible-pdf","Before / After 1: the simplest possible PDF",[18,479,480],{},"The \"hello world\" pair. gofpdf's brevity is what made it so quotable. gpdf's version is a few more lines because it's building a tree, not driving a cursor.",[18,482,483],{},[21,484,485],{},"Before — gofpdf:",[487,488,493],"pre",{"className":489,"code":490,"language":491,"meta":492,"style":492},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","package main\n\nimport \"github.com/jung-kurt/gofpdf\"\n\nfunc main() {\n    pdf := gofpdf.New(\"P\", \"mm\", \"A4\", \"\")\n    pdf.AddPage()\n    pdf.SetFont(\"Arial\", \"B\", 24)\n    pdf.Cell(40, 10, \"Hello, World!\")\n    pdf.OutputFileAndClose(\"hello.pdf\")\n}\n","go","",[26,494,495,508,515,531,536,552,609,623,659,690,711],{"__ignoreMap":492},[496,497,500,504],"span",{"class":498,"line":499},"line",1,[496,501,503],{"class":502},"sMK4o","package",[496,505,507],{"class":506},"sBMFI"," main\n",[496,509,511],{"class":498,"line":510},2,[496,512,514],{"emptyLinePlaceholder":513},true,"\n",[496,516,518,522,525,528],{"class":498,"line":517},3,[496,519,521],{"class":520},"s7zQu","import",[496,523,524],{"class":502}," \"",[496,526,527],{"class":506},"github.com/jung-kurt/gofpdf",[496,529,530],{"class":502},"\"\n",[496,532,534],{"class":498,"line":533},4,[496,535,514],{"emptyLinePlaceholder":513},[496,537,539,542,546,549],{"class":498,"line":538},5,[496,540,541],{"class":502},"func",[496,543,545],{"class":544},"s2Zo4"," main",[496,547,548],{"class":502},"()",[496,550,551],{"class":502}," {\n",[496,553,555,559,562,565,567,570,573,576,580,582,585,587,590,592,594,596,599,601,603,606],{"class":498,"line":554},6,[496,556,558],{"class":557},"sTEyZ","    pdf ",[496,560,561],{"class":502},":=",[496,563,564],{"class":557}," gofpdf",[496,566,443],{"class":502},[496,568,569],{"class":544},"New",[496,571,572],{"class":502},"(",[496,574,575],{"class":502},"\"",[496,577,579],{"class":578},"sfazB","P",[496,581,575],{"class":502},[496,583,584],{"class":502},",",[496,586,524],{"class":502},[496,588,589],{"class":578},"mm",[496,591,575],{"class":502},[496,593,584],{"class":502},[496,595,524],{"class":502},[496,597,598],{"class":578},"A4",[496,600,575],{"class":502},[496,602,584],{"class":502},[496,604,605],{"class":502}," \"\"",[496,607,608],{"class":502},")\n",[496,610,612,615,617,620],{"class":498,"line":611},7,[496,613,614],{"class":557},"    pdf",[496,616,443],{"class":502},[496,618,619],{"class":544},"AddPage",[496,621,622],{"class":502},"()\n",[496,624,626,628,630,633,635,637,640,642,644,646,649,651,653,657],{"class":498,"line":625},8,[496,627,614],{"class":557},[496,629,443],{"class":502},[496,631,632],{"class":544},"SetFont",[496,634,572],{"class":502},[496,636,575],{"class":502},[496,638,639],{"class":578},"Arial",[496,641,575],{"class":502},[496,643,584],{"class":502},[496,645,524],{"class":502},[496,647,648],{"class":578},"B",[496,650,575],{"class":502},[496,652,584],{"class":502},[496,654,656],{"class":655},"sbssI"," 24",[496,658,608],{"class":502},[496,660,662,664,666,669,671,674,676,679,681,683,686,688],{"class":498,"line":661},9,[496,663,614],{"class":557},[496,665,443],{"class":502},[496,667,668],{"class":544},"Cell",[496,670,572],{"class":502},[496,672,673],{"class":655},"40",[496,675,584],{"class":502},[496,677,678],{"class":655}," 10",[496,680,584],{"class":502},[496,682,524],{"class":502},[496,684,685],{"class":578},"Hello, World!",[496,687,575],{"class":502},[496,689,608],{"class":502},[496,691,693,695,697,700,702,704,707,709],{"class":498,"line":692},10,[496,694,614],{"class":557},[496,696,443],{"class":502},[496,698,699],{"class":544},"OutputFileAndClose",[496,701,572],{"class":502},[496,703,575],{"class":502},[496,705,706],{"class":578},"hello.pdf",[496,708,575],{"class":502},[496,710,608],{"class":502},[496,712,714],{"class":498,"line":713},11,[496,715,716],{"class":502},"}\n",[18,718,719],{},[21,720,721],{},"After — gpdf:",[487,723,725],{"className":489,"code":724,"language":491,"meta":492,"style":492},"package main\n\nimport (\n    \"log\"\n    \"os\"\n\n    \"github.com/gpdf-dev/gpdf\"\n    \"github.com/gpdf-dev/gpdf/document\"\n    \"github.com/gpdf-dev/gpdf/template\"\n)\n\nfunc main() {\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(24), template.Bold())\n        })\n    })\n\n    data, err := doc.Generate()\n    if err != nil {\n        log.Fatal(err)\n    }\n    if err := os.WriteFile(\"hello.pdf\", data, 0o644); err != nil {\n        log.Fatal(err)\n    }\n}\n",[26,726,727,733,737,744,754,763,767,776,785,794,798,802,813,832,855,891,897,902,919,952,989,1036,1042,1048,1053,1075,1091,1109,1115,1161,1176,1181],{"__ignoreMap":492},[496,728,729,731],{"class":498,"line":499},[496,730,503],{"class":502},[496,732,507],{"class":506},[496,734,735],{"class":498,"line":510},[496,736,514],{"emptyLinePlaceholder":513},[496,738,739,741],{"class":498,"line":517},[496,740,521],{"class":520},[496,742,743],{"class":502}," (\n",[496,745,746,749,752],{"class":498,"line":533},[496,747,748],{"class":502},"    \"",[496,750,751],{"class":506},"log",[496,753,530],{"class":502},[496,755,756,758,761],{"class":498,"line":538},[496,757,748],{"class":502},[496,759,760],{"class":506},"os",[496,762,530],{"class":502},[496,764,765],{"class":498,"line":554},[496,766,514],{"emptyLinePlaceholder":513},[496,768,769,771,774],{"class":498,"line":611},[496,770,748],{"class":502},[496,772,773],{"class":506},"github.com/gpdf-dev/gpdf",[496,775,530],{"class":502},[496,777,778,780,783],{"class":498,"line":625},[496,779,748],{"class":502},[496,781,782],{"class":506},"github.com/gpdf-dev/gpdf/document",[496,784,530],{"class":502},[496,786,787,789,792],{"class":498,"line":661},[496,788,748],{"class":502},[496,790,791],{"class":506},"github.com/gpdf-dev/gpdf/template",[496,793,530],{"class":502},[496,795,796],{"class":498,"line":692},[496,797,608],{"class":502},[496,799,800],{"class":498,"line":713},[496,801,514],{"emptyLinePlaceholder":513},[496,803,805,807,809,811],{"class":498,"line":804},12,[496,806,541],{"class":502},[496,808,545],{"class":544},[496,810,548],{"class":502},[496,812,551],{"class":502},[496,814,816,819,821,824,826,829],{"class":498,"line":815},13,[496,817,818],{"class":557},"    doc ",[496,820,561],{"class":502},[496,822,823],{"class":557}," gpdf",[496,825,443],{"class":502},[496,827,828],{"class":544},"NewDocument",[496,830,831],{"class":502},"(\n",[496,833,835,838,840,843,845,848,850,852],{"class":498,"line":834},14,[496,836,837],{"class":557},"        gpdf",[496,839,443],{"class":502},[496,841,842],{"class":544},"WithPageSize",[496,844,572],{"class":502},[496,846,847],{"class":557},"document",[496,849,443],{"class":502},[496,851,598],{"class":557},[496,853,854],{"class":502},"),\n",[496,856,858,860,862,865,867,869,871,874,876,878,880,883,885,888],{"class":498,"line":857},15,[496,859,837],{"class":557},[496,861,443],{"class":502},[496,863,864],{"class":544},"WithMargins",[496,866,572],{"class":502},[496,868,847],{"class":557},[496,870,443],{"class":502},[496,872,873],{"class":544},"UniformEdges",[496,875,572],{"class":502},[496,877,847],{"class":557},[496,879,443],{"class":502},[496,881,882],{"class":544},"Mm",[496,884,572],{"class":502},[496,886,887],{"class":655},"20",[496,889,890],{"class":502},"))),\n",[496,892,894],{"class":498,"line":893},16,[496,895,896],{"class":502},"    )\n",[496,898,900],{"class":498,"line":899},17,[496,901,514],{"emptyLinePlaceholder":513},[496,903,905,908,910,913,915,917],{"class":498,"line":904},18,[496,906,907],{"class":557},"    page ",[496,909,561],{"class":502},[496,911,912],{"class":557}," doc",[496,914,443],{"class":502},[496,916,619],{"class":544},[496,918,622],{"class":502},[496,920,922,925,927,930,933,937,940,943,945,948,950],{"class":498,"line":921},19,[496,923,924],{"class":557},"    page",[496,926,443],{"class":502},[496,928,929],{"class":544},"AutoRow",[496,931,932],{"class":502},"(func(",[496,934,936],{"class":935},"sHdIc","r",[496,938,939],{"class":502}," *",[496,941,942],{"class":506},"template",[496,944,443],{"class":502},[496,946,947],{"class":506},"RowBuilder",[496,949,209],{"class":502},[496,951,551],{"class":502},[496,953,955,958,960,963,965,968,970,973,976,978,980,982,985,987],{"class":498,"line":954},20,[496,956,957],{"class":557},"        r",[496,959,443],{"class":502},[496,961,962],{"class":544},"Col",[496,964,572],{"class":502},[496,966,967],{"class":655},"12",[496,969,584],{"class":502},[496,971,972],{"class":502}," func(",[496,974,975],{"class":935},"c",[496,977,939],{"class":502},[496,979,942],{"class":506},[496,981,443],{"class":502},[496,983,984],{"class":506},"ColBuilder",[496,986,209],{"class":502},[496,988,551],{"class":502},[496,990,992,995,997,1000,1002,1004,1006,1008,1010,1013,1015,1018,1020,1023,1026,1028,1030,1033],{"class":498,"line":991},21,[496,993,994],{"class":557},"            c",[496,996,443],{"class":502},[496,998,999],{"class":544},"Text",[496,1001,572],{"class":502},[496,1003,575],{"class":502},[496,1005,685],{"class":578},[496,1007,575],{"class":502},[496,1009,584],{"class":502},[496,1011,1012],{"class":557}," template",[496,1014,443],{"class":502},[496,1016,1017],{"class":544},"FontSize",[496,1019,572],{"class":502},[496,1021,1022],{"class":655},"24",[496,1024,1025],{"class":502},"),",[496,1027,1012],{"class":557},[496,1029,443],{"class":502},[496,1031,1032],{"class":544},"Bold",[496,1034,1035],{"class":502},"())\n",[496,1037,1039],{"class":498,"line":1038},22,[496,1040,1041],{"class":502},"        })\n",[496,1043,1045],{"class":498,"line":1044},23,[496,1046,1047],{"class":502},"    })\n",[496,1049,1051],{"class":498,"line":1050},24,[496,1052,514],{"emptyLinePlaceholder":513},[496,1054,1056,1059,1061,1064,1066,1068,1070,1073],{"class":498,"line":1055},25,[496,1057,1058],{"class":557},"    data",[496,1060,584],{"class":502},[496,1062,1063],{"class":557}," err ",[496,1065,561],{"class":502},[496,1067,912],{"class":557},[496,1069,443],{"class":502},[496,1071,1072],{"class":544},"Generate",[496,1074,622],{"class":502},[496,1076,1078,1081,1083,1086,1089],{"class":498,"line":1077},26,[496,1079,1080],{"class":520},"    if",[496,1082,1063],{"class":557},[496,1084,1085],{"class":502},"!=",[496,1087,1088],{"class":502}," nil",[496,1090,551],{"class":502},[496,1092,1094,1097,1099,1102,1104,1107],{"class":498,"line":1093},27,[496,1095,1096],{"class":557},"        log",[496,1098,443],{"class":502},[496,1100,1101],{"class":544},"Fatal",[496,1103,572],{"class":502},[496,1105,1106],{"class":557},"err",[496,1108,608],{"class":502},[496,1110,1112],{"class":498,"line":1111},28,[496,1113,1114],{"class":502},"    }\n",[496,1116,1118,1120,1122,1124,1127,1129,1132,1134,1136,1138,1140,1142,1145,1147,1150,1153,1155,1157,1159],{"class":498,"line":1117},29,[496,1119,1080],{"class":520},[496,1121,1063],{"class":557},[496,1123,561],{"class":502},[496,1125,1126],{"class":557}," os",[496,1128,443],{"class":502},[496,1130,1131],{"class":544},"WriteFile",[496,1133,572],{"class":502},[496,1135,575],{"class":502},[496,1137,706],{"class":578},[496,1139,575],{"class":502},[496,1141,584],{"class":502},[496,1143,1144],{"class":557}," data",[496,1146,584],{"class":502},[496,1148,1149],{"class":655}," 0o644",[496,1151,1152],{"class":502},");",[496,1154,1063],{"class":557},[496,1156,1085],{"class":502},[496,1158,1088],{"class":502},[496,1160,551],{"class":502},[496,1162,1164,1166,1168,1170,1172,1174],{"class":498,"line":1163},30,[496,1165,1096],{"class":557},[496,1167,443],{"class":502},[496,1169,1101],{"class":544},[496,1171,572],{"class":502},[496,1173,1106],{"class":557},[496,1175,608],{"class":502},[496,1177,1179],{"class":498,"line":1178},31,[496,1180,1114],{"class":502},[496,1182,1184],{"class":498,"line":1183},32,[496,1185,716],{"class":502},[18,1187,1188,1189,1191,1192,1195],{},"The grid does the work. ",[26,1190,929],{}," adds a row whose height is determined by its content; ",[26,1193,1194],{},"r.Col(12, ...)"," says \"this column spans all 12 grid columns.\" Same idea as Bootstrap, applied to a PDF page.",[18,1197,1198,1200,1201,1204,1205,1208],{},[26,1199,1072],{}," returns the bytes; ",[26,1202,1203],{},"Render(w)"," streams to an ",[26,1206,1207],{},"io.Writer"," if you'd rather not allocate. There's no \"close the file\" step because gpdf doesn't own a file handle.",[13,1210,1212],{"id":1211},"before-after-2-a-table-of-line-items","Before / After 2: a table of line items",[18,1214,1215,1216,1218,1219,1222],{},"Tables are where gofpdf gets verbose. There's no built-in table; you call ",[26,1217,668],{}," in nested loops, manage your own column widths, and do ",[26,1220,1221],{},"Ln(-1)"," to move to the next row. Half the gofpdf invoice tutorials on the internet are mostly table boilerplate.",[18,1224,1225],{},[21,1226,485],{},[487,1228,1230],{"className":489,"code":1229,"language":491,"meta":492,"style":492},"pdf.SetFont(\"Arial\", \"B\", 11)\npdf.SetFillColor(220, 220, 220)\npdf.CellFormat(80, 8, \"Description\", \"1\", 0, \"L\", true, 0, \"\")\npdf.CellFormat(20, 8, \"Qty\",         \"1\", 0, \"C\", true, 0, \"\")\npdf.CellFormat(30, 8, \"Unit\",        \"1\", 0, \"R\", true, 0, \"\")\npdf.CellFormat(30, 8, \"Amount\",      \"1\", 1, \"R\", true, 0, \"\")\n\npdf.SetFont(\"Arial\", \"\", 11)\nitems := [][]string{\n    {\"Frontend dev\", \"40 hrs\", \"$150.00\", \"$6,000.00\"},\n    {\"Backend dev\",  \"60 hrs\", \"$150.00\", \"$9,000.00\"},\n    {\"UI design\",    \"20 hrs\", \"$120.00\", \"$2,400.00\"},\n}\nfor _, row := range items {\n    pdf.CellFormat(80, 8, row[0], \"1\", 0, \"L\", false, 0, \"\")\n    pdf.CellFormat(20, 8, row[1], \"1\", 0, \"C\", false, 0, \"\")\n    pdf.CellFormat(30, 8, row[2], \"1\", 0, \"R\", false, 0, \"\")\n    pdf.CellFormat(30, 8, row[3], \"1\", 1, \"R\", false, 0, \"\")\n}\n",[26,1231,1232,1264,1289,1356,1417,1479,1540,1544,1570,1587,1629,1669,1709,1713,1736,1799,1857,1916,1975],{"__ignoreMap":492},[496,1233,1234,1237,1239,1241,1243,1245,1247,1249,1251,1253,1255,1257,1259,1262],{"class":498,"line":499},[496,1235,1236],{"class":557},"pdf",[496,1238,443],{"class":502},[496,1240,632],{"class":544},[496,1242,572],{"class":502},[496,1244,575],{"class":502},[496,1246,639],{"class":578},[496,1248,575],{"class":502},[496,1250,584],{"class":502},[496,1252,524],{"class":502},[496,1254,648],{"class":578},[496,1256,575],{"class":502},[496,1258,584],{"class":502},[496,1260,1261],{"class":655}," 11",[496,1263,608],{"class":502},[496,1265,1266,1268,1270,1273,1275,1278,1280,1283,1285,1287],{"class":498,"line":510},[496,1267,1236],{"class":557},[496,1269,443],{"class":502},[496,1271,1272],{"class":544},"SetFillColor",[496,1274,572],{"class":502},[496,1276,1277],{"class":655},"220",[496,1279,584],{"class":502},[496,1281,1282],{"class":655}," 220",[496,1284,584],{"class":502},[496,1286,1282],{"class":655},[496,1288,608],{"class":502},[496,1290,1291,1293,1295,1298,1300,1303,1305,1308,1310,1312,1315,1317,1319,1321,1324,1326,1328,1331,1333,1335,1338,1340,1342,1346,1348,1350,1352,1354],{"class":498,"line":517},[496,1292,1236],{"class":557},[496,1294,443],{"class":502},[496,1296,1297],{"class":544},"CellFormat",[496,1299,572],{"class":502},[496,1301,1302],{"class":655},"80",[496,1304,584],{"class":502},[496,1306,1307],{"class":655}," 8",[496,1309,584],{"class":502},[496,1311,524],{"class":502},[496,1313,1314],{"class":578},"Description",[496,1316,575],{"class":502},[496,1318,584],{"class":502},[496,1320,524],{"class":502},[496,1322,1323],{"class":578},"1",[496,1325,575],{"class":502},[496,1327,584],{"class":502},[496,1329,1330],{"class":655}," 0",[496,1332,584],{"class":502},[496,1334,524],{"class":502},[496,1336,1337],{"class":578},"L",[496,1339,575],{"class":502},[496,1341,584],{"class":502},[496,1343,1345],{"class":1344},"sfNiH"," true",[496,1347,584],{"class":502},[496,1349,1330],{"class":655},[496,1351,584],{"class":502},[496,1353,605],{"class":502},[496,1355,608],{"class":502},[496,1357,1358,1360,1362,1364,1366,1368,1370,1372,1374,1376,1379,1381,1383,1386,1388,1390,1392,1394,1396,1398,1401,1403,1405,1407,1409,1411,1413,1415],{"class":498,"line":533},[496,1359,1236],{"class":557},[496,1361,443],{"class":502},[496,1363,1297],{"class":544},[496,1365,572],{"class":502},[496,1367,887],{"class":655},[496,1369,584],{"class":502},[496,1371,1307],{"class":655},[496,1373,584],{"class":502},[496,1375,524],{"class":502},[496,1377,1378],{"class":578},"Qty",[496,1380,575],{"class":502},[496,1382,584],{"class":502},[496,1384,1385],{"class":502},"         \"",[496,1387,1323],{"class":578},[496,1389,575],{"class":502},[496,1391,584],{"class":502},[496,1393,1330],{"class":655},[496,1395,584],{"class":502},[496,1397,524],{"class":502},[496,1399,1400],{"class":578},"C",[496,1402,575],{"class":502},[496,1404,584],{"class":502},[496,1406,1345],{"class":1344},[496,1408,584],{"class":502},[496,1410,1330],{"class":655},[496,1412,584],{"class":502},[496,1414,605],{"class":502},[496,1416,608],{"class":502},[496,1418,1419,1421,1423,1425,1427,1430,1432,1434,1436,1438,1441,1443,1445,1448,1450,1452,1454,1456,1458,1460,1463,1465,1467,1469,1471,1473,1475,1477],{"class":498,"line":538},[496,1420,1236],{"class":557},[496,1422,443],{"class":502},[496,1424,1297],{"class":544},[496,1426,572],{"class":502},[496,1428,1429],{"class":655},"30",[496,1431,584],{"class":502},[496,1433,1307],{"class":655},[496,1435,584],{"class":502},[496,1437,524],{"class":502},[496,1439,1440],{"class":578},"Unit",[496,1442,575],{"class":502},[496,1444,584],{"class":502},[496,1446,1447],{"class":502},"        \"",[496,1449,1323],{"class":578},[496,1451,575],{"class":502},[496,1453,584],{"class":502},[496,1455,1330],{"class":655},[496,1457,584],{"class":502},[496,1459,524],{"class":502},[496,1461,1462],{"class":578},"R",[496,1464,575],{"class":502},[496,1466,584],{"class":502},[496,1468,1345],{"class":1344},[496,1470,584],{"class":502},[496,1472,1330],{"class":655},[496,1474,584],{"class":502},[496,1476,605],{"class":502},[496,1478,608],{"class":502},[496,1480,1481,1483,1485,1487,1489,1491,1493,1495,1497,1499,1502,1504,1506,1509,1511,1513,1515,1518,1520,1522,1524,1526,1528,1530,1532,1534,1536,1538],{"class":498,"line":554},[496,1482,1236],{"class":557},[496,1484,443],{"class":502},[496,1486,1297],{"class":544},[496,1488,572],{"class":502},[496,1490,1429],{"class":655},[496,1492,584],{"class":502},[496,1494,1307],{"class":655},[496,1496,584],{"class":502},[496,1498,524],{"class":502},[496,1500,1501],{"class":578},"Amount",[496,1503,575],{"class":502},[496,1505,584],{"class":502},[496,1507,1508],{"class":502},"      \"",[496,1510,1323],{"class":578},[496,1512,575],{"class":502},[496,1514,584],{"class":502},[496,1516,1517],{"class":655}," 1",[496,1519,584],{"class":502},[496,1521,524],{"class":502},[496,1523,1462],{"class":578},[496,1525,575],{"class":502},[496,1527,584],{"class":502},[496,1529,1345],{"class":1344},[496,1531,584],{"class":502},[496,1533,1330],{"class":655},[496,1535,584],{"class":502},[496,1537,605],{"class":502},[496,1539,608],{"class":502},[496,1541,1542],{"class":498,"line":611},[496,1543,514],{"emptyLinePlaceholder":513},[496,1545,1546,1548,1550,1552,1554,1556,1558,1560,1562,1564,1566,1568],{"class":498,"line":625},[496,1547,1236],{"class":557},[496,1549,443],{"class":502},[496,1551,632],{"class":544},[496,1553,572],{"class":502},[496,1555,575],{"class":502},[496,1557,639],{"class":578},[496,1559,575],{"class":502},[496,1561,584],{"class":502},[496,1563,605],{"class":502},[496,1565,584],{"class":502},[496,1567,1261],{"class":655},[496,1569,608],{"class":502},[496,1571,1572,1575,1577,1580,1584],{"class":498,"line":661},[496,1573,1574],{"class":557},"items ",[496,1576,561],{"class":502},[496,1578,1579],{"class":502}," [][]",[496,1581,1583],{"class":1582},"spNyl","string",[496,1585,1586],{"class":502},"{\n",[496,1588,1589,1592,1594,1597,1599,1601,1603,1606,1608,1610,1612,1615,1617,1619,1621,1624,1626],{"class":498,"line":692},[496,1590,1591],{"class":502},"    {",[496,1593,575],{"class":502},[496,1595,1596],{"class":578},"Frontend dev",[496,1598,575],{"class":502},[496,1600,584],{"class":502},[496,1602,524],{"class":502},[496,1604,1605],{"class":578},"40 hrs",[496,1607,575],{"class":502},[496,1609,584],{"class":502},[496,1611,524],{"class":502},[496,1613,1614],{"class":578},"$150.00",[496,1616,575],{"class":502},[496,1618,584],{"class":502},[496,1620,524],{"class":502},[496,1622,1623],{"class":578},"$6,000.00",[496,1625,575],{"class":502},[496,1627,1628],{"class":502},"},\n",[496,1630,1631,1633,1635,1638,1640,1642,1645,1648,1650,1652,1654,1656,1658,1660,1662,1665,1667],{"class":498,"line":713},[496,1632,1591],{"class":502},[496,1634,575],{"class":502},[496,1636,1637],{"class":578},"Backend dev",[496,1639,575],{"class":502},[496,1641,584],{"class":502},[496,1643,1644],{"class":502},"  \"",[496,1646,1647],{"class":578},"60 hrs",[496,1649,575],{"class":502},[496,1651,584],{"class":502},[496,1653,524],{"class":502},[496,1655,1614],{"class":578},[496,1657,575],{"class":502},[496,1659,584],{"class":502},[496,1661,524],{"class":502},[496,1663,1664],{"class":578},"$9,000.00",[496,1666,575],{"class":502},[496,1668,1628],{"class":502},[496,1670,1671,1673,1675,1678,1680,1682,1684,1687,1689,1691,1693,1696,1698,1700,1702,1705,1707],{"class":498,"line":804},[496,1672,1591],{"class":502},[496,1674,575],{"class":502},[496,1676,1677],{"class":578},"UI design",[496,1679,575],{"class":502},[496,1681,584],{"class":502},[496,1683,748],{"class":502},[496,1685,1686],{"class":578},"20 hrs",[496,1688,575],{"class":502},[496,1690,584],{"class":502},[496,1692,524],{"class":502},[496,1694,1695],{"class":578},"$120.00",[496,1697,575],{"class":502},[496,1699,584],{"class":502},[496,1701,524],{"class":502},[496,1703,1704],{"class":578},"$2,400.00",[496,1706,575],{"class":502},[496,1708,1628],{"class":502},[496,1710,1711],{"class":498,"line":815},[496,1712,716],{"class":502},[496,1714,1715,1718,1721,1723,1726,1728,1731,1734],{"class":498,"line":834},[496,1716,1717],{"class":520},"for",[496,1719,1720],{"class":557}," _",[496,1722,584],{"class":502},[496,1724,1725],{"class":557}," row ",[496,1727,561],{"class":502},[496,1729,1730],{"class":520}," range",[496,1732,1733],{"class":557}," items ",[496,1735,1586],{"class":502},[496,1737,1738,1740,1742,1744,1746,1748,1750,1752,1754,1757,1760,1763,1766,1768,1770,1772,1774,1776,1778,1780,1782,1784,1786,1789,1791,1793,1795,1797],{"class":498,"line":857},[496,1739,614],{"class":557},[496,1741,443],{"class":502},[496,1743,1297],{"class":544},[496,1745,572],{"class":502},[496,1747,1302],{"class":655},[496,1749,584],{"class":502},[496,1751,1307],{"class":655},[496,1753,584],{"class":502},[496,1755,1756],{"class":557}," row",[496,1758,1759],{"class":502},"[",[496,1761,1762],{"class":655},"0",[496,1764,1765],{"class":502},"],",[496,1767,524],{"class":502},[496,1769,1323],{"class":578},[496,1771,575],{"class":502},[496,1773,584],{"class":502},[496,1775,1330],{"class":655},[496,1777,584],{"class":502},[496,1779,524],{"class":502},[496,1781,1337],{"class":578},[496,1783,575],{"class":502},[496,1785,584],{"class":502},[496,1787,1788],{"class":1344}," false",[496,1790,584],{"class":502},[496,1792,1330],{"class":655},[496,1794,584],{"class":502},[496,1796,605],{"class":502},[496,1798,608],{"class":502},[496,1800,1801,1803,1805,1807,1809,1811,1813,1815,1817,1819,1821,1823,1825,1827,1829,1831,1833,1835,1837,1839,1841,1843,1845,1847,1849,1851,1853,1855],{"class":498,"line":893},[496,1802,614],{"class":557},[496,1804,443],{"class":502},[496,1806,1297],{"class":544},[496,1808,572],{"class":502},[496,1810,887],{"class":655},[496,1812,584],{"class":502},[496,1814,1307],{"class":655},[496,1816,584],{"class":502},[496,1818,1756],{"class":557},[496,1820,1759],{"class":502},[496,1822,1323],{"class":655},[496,1824,1765],{"class":502},[496,1826,524],{"class":502},[496,1828,1323],{"class":578},[496,1830,575],{"class":502},[496,1832,584],{"class":502},[496,1834,1330],{"class":655},[496,1836,584],{"class":502},[496,1838,524],{"class":502},[496,1840,1400],{"class":578},[496,1842,575],{"class":502},[496,1844,584],{"class":502},[496,1846,1788],{"class":1344},[496,1848,584],{"class":502},[496,1850,1330],{"class":655},[496,1852,584],{"class":502},[496,1854,605],{"class":502},[496,1856,608],{"class":502},[496,1858,1859,1861,1863,1865,1867,1869,1871,1873,1875,1877,1879,1882,1884,1886,1888,1890,1892,1894,1896,1898,1900,1902,1904,1906,1908,1910,1912,1914],{"class":498,"line":899},[496,1860,614],{"class":557},[496,1862,443],{"class":502},[496,1864,1297],{"class":544},[496,1866,572],{"class":502},[496,1868,1429],{"class":655},[496,1870,584],{"class":502},[496,1872,1307],{"class":655},[496,1874,584],{"class":502},[496,1876,1756],{"class":557},[496,1878,1759],{"class":502},[496,1880,1881],{"class":655},"2",[496,1883,1765],{"class":502},[496,1885,524],{"class":502},[496,1887,1323],{"class":578},[496,1889,575],{"class":502},[496,1891,584],{"class":502},[496,1893,1330],{"class":655},[496,1895,584],{"class":502},[496,1897,524],{"class":502},[496,1899,1462],{"class":578},[496,1901,575],{"class":502},[496,1903,584],{"class":502},[496,1905,1788],{"class":1344},[496,1907,584],{"class":502},[496,1909,1330],{"class":655},[496,1911,584],{"class":502},[496,1913,605],{"class":502},[496,1915,608],{"class":502},[496,1917,1918,1920,1922,1924,1926,1928,1930,1932,1934,1936,1938,1941,1943,1945,1947,1949,1951,1953,1955,1957,1959,1961,1963,1965,1967,1969,1971,1973],{"class":498,"line":904},[496,1919,614],{"class":557},[496,1921,443],{"class":502},[496,1923,1297],{"class":544},[496,1925,572],{"class":502},[496,1927,1429],{"class":655},[496,1929,584],{"class":502},[496,1931,1307],{"class":655},[496,1933,584],{"class":502},[496,1935,1756],{"class":557},[496,1937,1759],{"class":502},[496,1939,1940],{"class":655},"3",[496,1942,1765],{"class":502},[496,1944,524],{"class":502},[496,1946,1323],{"class":578},[496,1948,575],{"class":502},[496,1950,584],{"class":502},[496,1952,1517],{"class":655},[496,1954,584],{"class":502},[496,1956,524],{"class":502},[496,1958,1462],{"class":578},[496,1960,575],{"class":502},[496,1962,584],{"class":502},[496,1964,1788],{"class":1344},[496,1966,584],{"class":502},[496,1968,1330],{"class":655},[496,1970,584],{"class":502},[496,1972,605],{"class":502},[496,1974,608],{"class":502},[496,1976,1977],{"class":498,"line":921},[496,1978,716],{"class":502},[18,1980,1981],{},"Counts widths in your head, and good luck if a description wraps.",[18,1983,1984],{},[21,1985,721],{},[487,1987,1989],{"className":489,"code":1988,"language":491,"meta":492,"style":492},"page.AutoRow(func(r *template.RowBuilder) {\n    r.Col(12, func(c *template.ColBuilder) {\n        c.Table(\n            []string{\"Description\", \"Qty\", \"Unit\", \"Amount\"},\n            [][]string{\n                {\"Frontend dev\", \"40 hrs\", \"$150.00\", \"$6,000.00\"},\n                {\"Backend dev\",  \"60 hrs\", \"$150.00\", \"$9,000.00\"},\n                {\"UI design\",    \"20 hrs\", \"$120.00\", \"$2,400.00\"},\n            },\n            template.ColumnWidths(50, 15, 15, 20),\n            template.TableHeaderStyle(\n                template.Bold(),\n                template.TextColor(pdf.White),\n                template.BgColor(pdf.RGBHex(0x1A237E)),\n            ),\n            template.TableStripe(pdf.RGBHex(0xF5F5F5)),\n        )\n    })\n})\n",[26,1990,1991,2016,2047,2059,2101,2110,2147,2183,2219,2224,2255,2266,2278,2298,2324,2329,2353,2358,2362],{"__ignoreMap":492},[496,1992,1993,1996,1998,2000,2002,2004,2006,2008,2010,2012,2014],{"class":498,"line":499},[496,1994,1995],{"class":557},"page",[496,1997,443],{"class":502},[496,1999,929],{"class":544},[496,2001,932],{"class":502},[496,2003,936],{"class":935},[496,2005,939],{"class":502},[496,2007,942],{"class":506},[496,2009,443],{"class":502},[496,2011,947],{"class":506},[496,2013,209],{"class":502},[496,2015,551],{"class":502},[496,2017,2018,2021,2023,2025,2027,2029,2031,2033,2035,2037,2039,2041,2043,2045],{"class":498,"line":510},[496,2019,2020],{"class":557},"    r",[496,2022,443],{"class":502},[496,2024,962],{"class":544},[496,2026,572],{"class":502},[496,2028,967],{"class":655},[496,2030,584],{"class":502},[496,2032,972],{"class":502},[496,2034,975],{"class":935},[496,2036,939],{"class":502},[496,2038,942],{"class":506},[496,2040,443],{"class":502},[496,2042,984],{"class":506},[496,2044,209],{"class":502},[496,2046,551],{"class":502},[496,2048,2049,2052,2054,2057],{"class":498,"line":517},[496,2050,2051],{"class":557},"        c",[496,2053,443],{"class":502},[496,2055,2056],{"class":544},"Table",[496,2058,831],{"class":502},[496,2060,2061,2064,2066,2069,2071,2073,2075,2077,2079,2081,2083,2085,2087,2089,2091,2093,2095,2097,2099],{"class":498,"line":533},[496,2062,2063],{"class":502},"            []",[496,2065,1583],{"class":1582},[496,2067,2068],{"class":502},"{",[496,2070,575],{"class":502},[496,2072,1314],{"class":578},[496,2074,575],{"class":502},[496,2076,584],{"class":502},[496,2078,524],{"class":502},[496,2080,1378],{"class":578},[496,2082,575],{"class":502},[496,2084,584],{"class":502},[496,2086,524],{"class":502},[496,2088,1440],{"class":578},[496,2090,575],{"class":502},[496,2092,584],{"class":502},[496,2094,524],{"class":502},[496,2096,1501],{"class":578},[496,2098,575],{"class":502},[496,2100,1628],{"class":502},[496,2102,2103,2106,2108],{"class":498,"line":538},[496,2104,2105],{"class":502},"            [][]",[496,2107,1583],{"class":1582},[496,2109,1586],{"class":502},[496,2111,2112,2115,2117,2119,2121,2123,2125,2127,2129,2131,2133,2135,2137,2139,2141,2143,2145],{"class":498,"line":554},[496,2113,2114],{"class":502},"                {",[496,2116,575],{"class":502},[496,2118,1596],{"class":578},[496,2120,575],{"class":502},[496,2122,584],{"class":502},[496,2124,524],{"class":502},[496,2126,1605],{"class":578},[496,2128,575],{"class":502},[496,2130,584],{"class":502},[496,2132,524],{"class":502},[496,2134,1614],{"class":578},[496,2136,575],{"class":502},[496,2138,584],{"class":502},[496,2140,524],{"class":502},[496,2142,1623],{"class":578},[496,2144,575],{"class":502},[496,2146,1628],{"class":502},[496,2148,2149,2151,2153,2155,2157,2159,2161,2163,2165,2167,2169,2171,2173,2175,2177,2179,2181],{"class":498,"line":611},[496,2150,2114],{"class":502},[496,2152,575],{"class":502},[496,2154,1637],{"class":578},[496,2156,575],{"class":502},[496,2158,584],{"class":502},[496,2160,1644],{"class":502},[496,2162,1647],{"class":578},[496,2164,575],{"class":502},[496,2166,584],{"class":502},[496,2168,524],{"class":502},[496,2170,1614],{"class":578},[496,2172,575],{"class":502},[496,2174,584],{"class":502},[496,2176,524],{"class":502},[496,2178,1664],{"class":578},[496,2180,575],{"class":502},[496,2182,1628],{"class":502},[496,2184,2185,2187,2189,2191,2193,2195,2197,2199,2201,2203,2205,2207,2209,2211,2213,2215,2217],{"class":498,"line":625},[496,2186,2114],{"class":502},[496,2188,575],{"class":502},[496,2190,1677],{"class":578},[496,2192,575],{"class":502},[496,2194,584],{"class":502},[496,2196,748],{"class":502},[496,2198,1686],{"class":578},[496,2200,575],{"class":502},[496,2202,584],{"class":502},[496,2204,524],{"class":502},[496,2206,1695],{"class":578},[496,2208,575],{"class":502},[496,2210,584],{"class":502},[496,2212,524],{"class":502},[496,2214,1704],{"class":578},[496,2216,575],{"class":502},[496,2218,1628],{"class":502},[496,2220,2221],{"class":498,"line":661},[496,2222,2223],{"class":502},"            },\n",[496,2225,2226,2229,2231,2234,2236,2239,2241,2244,2246,2248,2250,2253],{"class":498,"line":692},[496,2227,2228],{"class":557},"            template",[496,2230,443],{"class":502},[496,2232,2233],{"class":544},"ColumnWidths",[496,2235,572],{"class":502},[496,2237,2238],{"class":655},"50",[496,2240,584],{"class":502},[496,2242,2243],{"class":655}," 15",[496,2245,584],{"class":502},[496,2247,2243],{"class":655},[496,2249,584],{"class":502},[496,2251,2252],{"class":655}," 20",[496,2254,854],{"class":502},[496,2256,2257,2259,2261,2264],{"class":498,"line":713},[496,2258,2228],{"class":557},[496,2260,443],{"class":502},[496,2262,2263],{"class":544},"TableHeaderStyle",[496,2265,831],{"class":502},[496,2267,2268,2271,2273,2275],{"class":498,"line":804},[496,2269,2270],{"class":557},"                template",[496,2272,443],{"class":502},[496,2274,1032],{"class":544},[496,2276,2277],{"class":502},"(),\n",[496,2279,2280,2282,2284,2287,2289,2291,2293,2296],{"class":498,"line":815},[496,2281,2270],{"class":557},[496,2283,443],{"class":502},[496,2285,2286],{"class":544},"TextColor",[496,2288,572],{"class":502},[496,2290,1236],{"class":557},[496,2292,443],{"class":502},[496,2294,2295],{"class":557},"White",[496,2297,854],{"class":502},[496,2299,2300,2302,2304,2307,2309,2311,2313,2316,2318,2321],{"class":498,"line":834},[496,2301,2270],{"class":557},[496,2303,443],{"class":502},[496,2305,2306],{"class":544},"BgColor",[496,2308,572],{"class":502},[496,2310,1236],{"class":557},[496,2312,443],{"class":502},[496,2314,2315],{"class":544},"RGBHex",[496,2317,572],{"class":502},[496,2319,2320],{"class":655},"0x1A237E",[496,2322,2323],{"class":502},")),\n",[496,2325,2326],{"class":498,"line":857},[496,2327,2328],{"class":502},"            ),\n",[496,2330,2331,2333,2335,2338,2340,2342,2344,2346,2348,2351],{"class":498,"line":893},[496,2332,2228],{"class":557},[496,2334,443],{"class":502},[496,2336,2337],{"class":544},"TableStripe",[496,2339,572],{"class":502},[496,2341,1236],{"class":557},[496,2343,443],{"class":502},[496,2345,2315],{"class":544},[496,2347,572],{"class":502},[496,2349,2350],{"class":655},"0xF5F5F5",[496,2352,2323],{"class":502},[496,2354,2355],{"class":498,"line":899},[496,2356,2357],{"class":502},"        )\n",[496,2359,2360],{"class":498,"line":904},[496,2361,1047],{"class":502},[496,2363,2364],{"class":498,"line":921},[496,2365,2366],{"class":502},"})\n",[18,2368,2369,2372,2373,2376,2377,2380,2381,2383],{},[26,2370,2371],{},"ColumnWidths(50, 15, 15, 20)"," is ",[21,2374,2375],{},"percentages of the column the table lives in",", not absolute millimeters. Drop the table into a ",[26,2378,2379],{},"r.Col(6, ...)"," and the same percentages still work. That's the kind of thing you can't get out of ",[26,2382,1297],{}," without a wrapper.",[18,2385,2386],{},"Wrapping is automatic. Page breaks are automatic — if the table runs past the bottom margin, the header repeats on the next page.",[13,2388,2390],{"id":2389},"before-after-3-japanese-text-without-the-dance","Before / After 3: Japanese text without the dance",[18,2392,2393,2394,2396],{},"This is the one that pushed me off gofpdf. To render Japanese in gofpdf you call ",[26,2395,28],{},", point it at a TTF on disk, set the font, and pray. Subsetting works most of the time. Some TTFs trigger glyph-id collisions and emit garbled output. The error messages don't help.",[18,2398,2399],{},[21,2400,485],{},[487,2402,2404],{"className":489,"code":2403,"language":491,"meta":492,"style":492},"pdf := gofpdf.New(\"P\", \"mm\", \"A4\", \"\")\npdf.AddUTF8Font(\"notosansjp\", \"\", \"NotoSansJP-Regular.ttf\")\npdf.AddPage()\npdf.SetFont(\"notosansjp\", \"\", 14)\npdf.Cell(0, 10, \"こんにちは、世界。\")\npdf.OutputFileAndClose(\"ja.pdf\")\n",[26,2405,2406,2449,2481,2491,2518,2545],{"__ignoreMap":492},[496,2407,2408,2411,2413,2415,2417,2419,2421,2423,2425,2427,2429,2431,2433,2435,2437,2439,2441,2443,2445,2447],{"class":498,"line":499},[496,2409,2410],{"class":557},"pdf ",[496,2412,561],{"class":502},[496,2414,564],{"class":557},[496,2416,443],{"class":502},[496,2418,569],{"class":544},[496,2420,572],{"class":502},[496,2422,575],{"class":502},[496,2424,579],{"class":578},[496,2426,575],{"class":502},[496,2428,584],{"class":502},[496,2430,524],{"class":502},[496,2432,589],{"class":578},[496,2434,575],{"class":502},[496,2436,584],{"class":502},[496,2438,524],{"class":502},[496,2440,598],{"class":578},[496,2442,575],{"class":502},[496,2444,584],{"class":502},[496,2446,605],{"class":502},[496,2448,608],{"class":502},[496,2450,2451,2453,2455,2457,2459,2461,2464,2466,2468,2470,2472,2474,2477,2479],{"class":498,"line":510},[496,2452,1236],{"class":557},[496,2454,443],{"class":502},[496,2456,28],{"class":544},[496,2458,572],{"class":502},[496,2460,575],{"class":502},[496,2462,2463],{"class":578},"notosansjp",[496,2465,575],{"class":502},[496,2467,584],{"class":502},[496,2469,605],{"class":502},[496,2471,584],{"class":502},[496,2473,524],{"class":502},[496,2475,2476],{"class":578},"NotoSansJP-Regular.ttf",[496,2478,575],{"class":502},[496,2480,608],{"class":502},[496,2482,2483,2485,2487,2489],{"class":498,"line":517},[496,2484,1236],{"class":557},[496,2486,443],{"class":502},[496,2488,619],{"class":544},[496,2490,622],{"class":502},[496,2492,2493,2495,2497,2499,2501,2503,2505,2507,2509,2511,2513,2516],{"class":498,"line":533},[496,2494,1236],{"class":557},[496,2496,443],{"class":502},[496,2498,632],{"class":544},[496,2500,572],{"class":502},[496,2502,575],{"class":502},[496,2504,2463],{"class":578},[496,2506,575],{"class":502},[496,2508,584],{"class":502},[496,2510,605],{"class":502},[496,2512,584],{"class":502},[496,2514,2515],{"class":655}," 14",[496,2517,608],{"class":502},[496,2519,2520,2522,2524,2526,2528,2530,2532,2534,2536,2538,2541,2543],{"class":498,"line":538},[496,2521,1236],{"class":557},[496,2523,443],{"class":502},[496,2525,668],{"class":544},[496,2527,572],{"class":502},[496,2529,1762],{"class":655},[496,2531,584],{"class":502},[496,2533,678],{"class":655},[496,2535,584],{"class":502},[496,2537,524],{"class":502},[496,2539,2540],{"class":578},"こんにちは、世界。",[496,2542,575],{"class":502},[496,2544,608],{"class":502},[496,2546,2547,2549,2551,2553,2555,2557,2560,2562],{"class":498,"line":554},[496,2548,1236],{"class":557},[496,2550,443],{"class":502},[496,2552,699],{"class":544},[496,2554,572],{"class":502},[496,2556,575],{"class":502},[496,2558,2559],{"class":578},"ja.pdf",[496,2561,575],{"class":502},[496,2563,608],{"class":502},[18,2565,2566,2567,2569],{},"Two land mines: the TTF must exist at the path you give, at runtime, on the host that runs your binary (so your Docker image has to ship the font). And ",[26,2568,668],{}," of \"0\" width means \"to the right margin,\" which for CJK text often clips because the width estimator doesn't account for full-width glyphs correctly.",[18,2571,2572],{},[21,2573,721],{},[487,2575,2577],{"className":489,"code":2576,"language":491,"meta":492,"style":492},"package main\n\nimport (\n    \"log\"\n    \"os\"\n\n    \"github.com/gpdf-dev/gpdf\"\n    \"github.com/gpdf-dev/gpdf/document\"\n    \"github.com/gpdf-dev/gpdf/template\"\n)\n\nfunc main() {\n    fontData, err := os.ReadFile(\"NotoSansJP-Regular.ttf\")\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    doc := gpdf.NewDocument(\n        gpdf.WithPageSize(document.A4),\n        gpdf.WithMargins(document.UniformEdges(document.Mm(20))),\n        gpdf.WithFont(\"NotoSansJP\", fontData),\n        gpdf.WithDefaultFont(\"NotoSansJP\", 14),\n    )\n\n    page := doc.AddPage()\n    page.AutoRow(func(r *template.RowBuilder) {\n        r.Col(12, func(c *template.ColBuilder) {\n            c.Text(\"こんにちは、世界。\")\n            c.Text(\"吾輩は猫である。名前はまだ無い。\")\n            c.Text(\"東京都渋谷区神宮前1-2-3\")\n        })\n    })\n\n    data, _ := doc.Generate()\n    os.WriteFile(\"ja.pdf\", data, 0o644)\n}\n",[26,2578,2579,2585,2589,2595,2603,2611,2615,2623,2631,2639,2643,2647,2657,2685,2697,2711,2715,2719,2733,2751,2781,2806,2829,2833,2837,2851,2875,2905,2923,2942,2961,2965,2969,2974,2994,3022],{"__ignoreMap":492},[496,2580,2581,2583],{"class":498,"line":499},[496,2582,503],{"class":502},[496,2584,507],{"class":506},[496,2586,2587],{"class":498,"line":510},[496,2588,514],{"emptyLinePlaceholder":513},[496,2590,2591,2593],{"class":498,"line":517},[496,2592,521],{"class":520},[496,2594,743],{"class":502},[496,2596,2597,2599,2601],{"class":498,"line":533},[496,2598,748],{"class":502},[496,2600,751],{"class":506},[496,2602,530],{"class":502},[496,2604,2605,2607,2609],{"class":498,"line":538},[496,2606,748],{"class":502},[496,2608,760],{"class":506},[496,2610,530],{"class":502},[496,2612,2613],{"class":498,"line":554},[496,2614,514],{"emptyLinePlaceholder":513},[496,2616,2617,2619,2621],{"class":498,"line":611},[496,2618,748],{"class":502},[496,2620,773],{"class":506},[496,2622,530],{"class":502},[496,2624,2625,2627,2629],{"class":498,"line":625},[496,2626,748],{"class":502},[496,2628,782],{"class":506},[496,2630,530],{"class":502},[496,2632,2633,2635,2637],{"class":498,"line":661},[496,2634,748],{"class":502},[496,2636,791],{"class":506},[496,2638,530],{"class":502},[496,2640,2641],{"class":498,"line":692},[496,2642,608],{"class":502},[496,2644,2645],{"class":498,"line":713},[496,2646,514],{"emptyLinePlaceholder":513},[496,2648,2649,2651,2653,2655],{"class":498,"line":804},[496,2650,541],{"class":502},[496,2652,545],{"class":544},[496,2654,548],{"class":502},[496,2656,551],{"class":502},[496,2658,2659,2662,2664,2666,2668,2670,2672,2675,2677,2679,2681,2683],{"class":498,"line":815},[496,2660,2661],{"class":557},"    fontData",[496,2663,584],{"class":502},[496,2665,1063],{"class":557},[496,2667,561],{"class":502},[496,2669,1126],{"class":557},[496,2671,443],{"class":502},[496,2673,2674],{"class":544},"ReadFile",[496,2676,572],{"class":502},[496,2678,575],{"class":502},[496,2680,2476],{"class":578},[496,2682,575],{"class":502},[496,2684,608],{"class":502},[496,2686,2687,2689,2691,2693,2695],{"class":498,"line":834},[496,2688,1080],{"class":520},[496,2690,1063],{"class":557},[496,2692,1085],{"class":502},[496,2694,1088],{"class":502},[496,2696,551],{"class":502},[496,2698,2699,2701,2703,2705,2707,2709],{"class":498,"line":857},[496,2700,1096],{"class":557},[496,2702,443],{"class":502},[496,2704,1101],{"class":544},[496,2706,572],{"class":502},[496,2708,1106],{"class":557},[496,2710,608],{"class":502},[496,2712,2713],{"class":498,"line":893},[496,2714,1114],{"class":502},[496,2716,2717],{"class":498,"line":899},[496,2718,514],{"emptyLinePlaceholder":513},[496,2720,2721,2723,2725,2727,2729,2731],{"class":498,"line":904},[496,2722,818],{"class":557},[496,2724,561],{"class":502},[496,2726,823],{"class":557},[496,2728,443],{"class":502},[496,2730,828],{"class":544},[496,2732,831],{"class":502},[496,2734,2735,2737,2739,2741,2743,2745,2747,2749],{"class":498,"line":921},[496,2736,837],{"class":557},[496,2738,443],{"class":502},[496,2740,842],{"class":544},[496,2742,572],{"class":502},[496,2744,847],{"class":557},[496,2746,443],{"class":502},[496,2748,598],{"class":557},[496,2750,854],{"class":502},[496,2752,2753,2755,2757,2759,2761,2763,2765,2767,2769,2771,2773,2775,2777,2779],{"class":498,"line":954},[496,2754,837],{"class":557},[496,2756,443],{"class":502},[496,2758,864],{"class":544},[496,2760,572],{"class":502},[496,2762,847],{"class":557},[496,2764,443],{"class":502},[496,2766,873],{"class":544},[496,2768,572],{"class":502},[496,2770,847],{"class":557},[496,2772,443],{"class":502},[496,2774,882],{"class":544},[496,2776,572],{"class":502},[496,2778,887],{"class":655},[496,2780,890],{"class":502},[496,2782,2783,2785,2787,2790,2792,2794,2797,2799,2801,2804],{"class":498,"line":991},[496,2784,837],{"class":557},[496,2786,443],{"class":502},[496,2788,2789],{"class":544},"WithFont",[496,2791,572],{"class":502},[496,2793,575],{"class":502},[496,2795,2796],{"class":578},"NotoSansJP",[496,2798,575],{"class":502},[496,2800,584],{"class":502},[496,2802,2803],{"class":557}," fontData",[496,2805,854],{"class":502},[496,2807,2808,2810,2812,2815,2817,2819,2821,2823,2825,2827],{"class":498,"line":1038},[496,2809,837],{"class":557},[496,2811,443],{"class":502},[496,2813,2814],{"class":544},"WithDefaultFont",[496,2816,572],{"class":502},[496,2818,575],{"class":502},[496,2820,2796],{"class":578},[496,2822,575],{"class":502},[496,2824,584],{"class":502},[496,2826,2515],{"class":655},[496,2828,854],{"class":502},[496,2830,2831],{"class":498,"line":1044},[496,2832,896],{"class":502},[496,2834,2835],{"class":498,"line":1050},[496,2836,514],{"emptyLinePlaceholder":513},[496,2838,2839,2841,2843,2845,2847,2849],{"class":498,"line":1055},[496,2840,907],{"class":557},[496,2842,561],{"class":502},[496,2844,912],{"class":557},[496,2846,443],{"class":502},[496,2848,619],{"class":544},[496,2850,622],{"class":502},[496,2852,2853,2855,2857,2859,2861,2863,2865,2867,2869,2871,2873],{"class":498,"line":1077},[496,2854,924],{"class":557},[496,2856,443],{"class":502},[496,2858,929],{"class":544},[496,2860,932],{"class":502},[496,2862,936],{"class":935},[496,2864,939],{"class":502},[496,2866,942],{"class":506},[496,2868,443],{"class":502},[496,2870,947],{"class":506},[496,2872,209],{"class":502},[496,2874,551],{"class":502},[496,2876,2877,2879,2881,2883,2885,2887,2889,2891,2893,2895,2897,2899,2901,2903],{"class":498,"line":1093},[496,2878,957],{"class":557},[496,2880,443],{"class":502},[496,2882,962],{"class":544},[496,2884,572],{"class":502},[496,2886,967],{"class":655},[496,2888,584],{"class":502},[496,2890,972],{"class":502},[496,2892,975],{"class":935},[496,2894,939],{"class":502},[496,2896,942],{"class":506},[496,2898,443],{"class":502},[496,2900,984],{"class":506},[496,2902,209],{"class":502},[496,2904,551],{"class":502},[496,2906,2907,2909,2911,2913,2915,2917,2919,2921],{"class":498,"line":1111},[496,2908,994],{"class":557},[496,2910,443],{"class":502},[496,2912,999],{"class":544},[496,2914,572],{"class":502},[496,2916,575],{"class":502},[496,2918,2540],{"class":578},[496,2920,575],{"class":502},[496,2922,608],{"class":502},[496,2924,2925,2927,2929,2931,2933,2935,2938,2940],{"class":498,"line":1117},[496,2926,994],{"class":557},[496,2928,443],{"class":502},[496,2930,999],{"class":544},[496,2932,572],{"class":502},[496,2934,575],{"class":502},[496,2936,2937],{"class":578},"吾輩は猫である。名前はまだ無い。",[496,2939,575],{"class":502},[496,2941,608],{"class":502},[496,2943,2944,2946,2948,2950,2952,2954,2957,2959],{"class":498,"line":1163},[496,2945,994],{"class":557},[496,2947,443],{"class":502},[496,2949,999],{"class":544},[496,2951,572],{"class":502},[496,2953,575],{"class":502},[496,2955,2956],{"class":578},"東京都渋谷区神宮前1-2-3",[496,2958,575],{"class":502},[496,2960,608],{"class":502},[496,2962,2963],{"class":498,"line":1178},[496,2964,1041],{"class":502},[496,2966,2967],{"class":498,"line":1183},[496,2968,1047],{"class":502},[496,2970,2972],{"class":498,"line":2971},33,[496,2973,514],{"emptyLinePlaceholder":513},[496,2975,2977,2979,2981,2984,2986,2988,2990,2992],{"class":498,"line":2976},34,[496,2978,1058],{"class":557},[496,2980,584],{"class":502},[496,2982,2983],{"class":557}," _ ",[496,2985,561],{"class":502},[496,2987,912],{"class":557},[496,2989,443],{"class":502},[496,2991,1072],{"class":544},[496,2993,622],{"class":502},[496,2995,2997,3000,3002,3004,3006,3008,3010,3012,3014,3016,3018,3020],{"class":498,"line":2996},35,[496,2998,2999],{"class":557},"    os",[496,3001,443],{"class":502},[496,3003,1131],{"class":544},[496,3005,572],{"class":502},[496,3007,575],{"class":502},[496,3009,2559],{"class":578},[496,3011,575],{"class":502},[496,3013,584],{"class":502},[496,3015,1144],{"class":557},[496,3017,584],{"class":502},[496,3019,1149],{"class":655},[496,3021,608],{"class":502},[496,3023,3025],{"class":498,"line":3024},36,[496,3026,716],{"class":502},[18,3028,3029],{},"Two things are different.",[18,3031,3032,3033,3036,3037,3040],{},"First, you pass ",[21,3034,3035],{},"bytes",", not a path. Embed the TTF with ",[26,3038,3039],{},"//go:embed"," and your binary becomes self-contained. No \"font not found\" in production because someone forgot to mount a volume.",[18,3042,3043],{},"Second, gpdf's TrueType subsetter understands CJK cmap formats (4, 6, 12) and Identity-H encoding. The output PDF only carries the glyphs you actually used — embedding NotoSansJP for a 200-character invoice produces a ~30 KB font subset, not a 4 MB full embed. If you've ever watched gofpdf write a 5 MB PDF for one page of Japanese, this is the thing you'll notice first.",[18,3045,3046],{},"For a deeper walkthrough of CJK-specific options — IPAex Gothic, Source Han Sans, fallback chains — see the upcoming companion post on Japanese fonts.",[13,3048,3050],{"id":3049},"before-after-4-header-on-every-page-page-numbers-in-the-footer","Before / After 4: header on every page, page numbers in the footer",[18,3052,3053,3054,105,3057,3060,3061,3064,3065,105,3067,443],{},"The gofpdf pattern for repeating chrome is ",[26,3055,3056],{},"SetHeaderFunc",[26,3058,3059],{},"SetFooterFunc"," — both take a ",[26,3062,3063],{},"func()"," that runs against the current cursor. Page numbers come from ",[26,3066,390],{},[26,3068,3069],{},"pdf.AliasNbPages()",[18,3071,3072],{},[21,3073,485],{},[487,3075,3077],{"className":489,"code":3076,"language":491,"meta":492,"style":492},"pdf := gofpdf.New(\"P\", \"mm\", \"A4\", \"\")\npdf.SetHeaderFunc(func() {\n    pdf.SetFont(\"Arial\", \"B\", 12)\n    pdf.Cell(0, 10, \"ACME Corporation\")\n    pdf.Ln(15)\n})\npdf.SetFooterFunc(func() {\n    pdf.SetY(-15)\n    pdf.SetFont(\"Arial\", \"I\", 8)\n    pdf.CellFormat(0, 10,\n        fmt.Sprintf(\"Page %d/{nb}\", pdf.PageNo()),\n        \"\", 0, \"C\", false, 0, \"\")\n})\npdf.AliasNbPages(\"\")\npdf.AddPage()\n// ... body ...\n",[26,3078,3079,3121,3134,3165,3192,3208,3212,3224,3240,3271,3290,3329,3360,3364,3380,3390],{"__ignoreMap":492},[496,3080,3081,3083,3085,3087,3089,3091,3093,3095,3097,3099,3101,3103,3105,3107,3109,3111,3113,3115,3117,3119],{"class":498,"line":499},[496,3082,2410],{"class":557},[496,3084,561],{"class":502},[496,3086,564],{"class":557},[496,3088,443],{"class":502},[496,3090,569],{"class":544},[496,3092,572],{"class":502},[496,3094,575],{"class":502},[496,3096,579],{"class":578},[496,3098,575],{"class":502},[496,3100,584],{"class":502},[496,3102,524],{"class":502},[496,3104,589],{"class":578},[496,3106,575],{"class":502},[496,3108,584],{"class":502},[496,3110,524],{"class":502},[496,3112,598],{"class":578},[496,3114,575],{"class":502},[496,3116,584],{"class":502},[496,3118,605],{"class":502},[496,3120,608],{"class":502},[496,3122,3123,3125,3127,3129,3132],{"class":498,"line":510},[496,3124,1236],{"class":557},[496,3126,443],{"class":502},[496,3128,3056],{"class":544},[496,3130,3131],{"class":502},"(func()",[496,3133,551],{"class":502},[496,3135,3136,3138,3140,3142,3144,3146,3148,3150,3152,3154,3156,3158,3160,3163],{"class":498,"line":517},[496,3137,614],{"class":557},[496,3139,443],{"class":502},[496,3141,632],{"class":544},[496,3143,572],{"class":502},[496,3145,575],{"class":502},[496,3147,639],{"class":578},[496,3149,575],{"class":502},[496,3151,584],{"class":502},[496,3153,524],{"class":502},[496,3155,648],{"class":578},[496,3157,575],{"class":502},[496,3159,584],{"class":502},[496,3161,3162],{"class":655}," 12",[496,3164,608],{"class":502},[496,3166,3167,3169,3171,3173,3175,3177,3179,3181,3183,3185,3188,3190],{"class":498,"line":533},[496,3168,614],{"class":557},[496,3170,443],{"class":502},[496,3172,668],{"class":544},[496,3174,572],{"class":502},[496,3176,1762],{"class":655},[496,3178,584],{"class":502},[496,3180,678],{"class":655},[496,3182,584],{"class":502},[496,3184,524],{"class":502},[496,3186,3187],{"class":578},"ACME Corporation",[496,3189,575],{"class":502},[496,3191,608],{"class":502},[496,3193,3194,3196,3198,3201,3203,3206],{"class":498,"line":538},[496,3195,614],{"class":557},[496,3197,443],{"class":502},[496,3199,3200],{"class":544},"Ln",[496,3202,572],{"class":502},[496,3204,3205],{"class":655},"15",[496,3207,608],{"class":502},[496,3209,3210],{"class":498,"line":554},[496,3211,2366],{"class":502},[496,3213,3214,3216,3218,3220,3222],{"class":498,"line":611},[496,3215,1236],{"class":557},[496,3217,443],{"class":502},[496,3219,3059],{"class":544},[496,3221,3131],{"class":502},[496,3223,551],{"class":502},[496,3225,3226,3228,3230,3233,3236,3238],{"class":498,"line":625},[496,3227,614],{"class":557},[496,3229,443],{"class":502},[496,3231,3232],{"class":544},"SetY",[496,3234,3235],{"class":502},"(-",[496,3237,3205],{"class":655},[496,3239,608],{"class":502},[496,3241,3242,3244,3246,3248,3250,3252,3254,3256,3258,3260,3263,3265,3267,3269],{"class":498,"line":661},[496,3243,614],{"class":557},[496,3245,443],{"class":502},[496,3247,632],{"class":544},[496,3249,572],{"class":502},[496,3251,575],{"class":502},[496,3253,639],{"class":578},[496,3255,575],{"class":502},[496,3257,584],{"class":502},[496,3259,524],{"class":502},[496,3261,3262],{"class":578},"I",[496,3264,575],{"class":502},[496,3266,584],{"class":502},[496,3268,1307],{"class":655},[496,3270,608],{"class":502},[496,3272,3273,3275,3277,3279,3281,3283,3285,3287],{"class":498,"line":692},[496,3274,614],{"class":557},[496,3276,443],{"class":502},[496,3278,1297],{"class":544},[496,3280,572],{"class":502},[496,3282,1762],{"class":655},[496,3284,584],{"class":502},[496,3286,678],{"class":655},[496,3288,3289],{"class":502},",\n",[496,3291,3292,3295,3297,3300,3302,3304,3307,3311,3314,3316,3318,3321,3323,3326],{"class":498,"line":713},[496,3293,3294],{"class":557},"        fmt",[496,3296,443],{"class":502},[496,3298,3299],{"class":544},"Sprintf",[496,3301,572],{"class":502},[496,3303,575],{"class":502},[496,3305,3306],{"class":578},"Page ",[496,3308,3310],{"class":3309},"swJcz","%d",[496,3312,3313],{"class":578},"/{nb}",[496,3315,575],{"class":502},[496,3317,584],{"class":502},[496,3319,3320],{"class":557}," pdf",[496,3322,443],{"class":502},[496,3324,3325],{"class":544},"PageNo",[496,3327,3328],{"class":502},"()),\n",[496,3330,3331,3334,3336,3338,3340,3342,3344,3346,3348,3350,3352,3354,3356,3358],{"class":498,"line":804},[496,3332,3333],{"class":502},"        \"\"",[496,3335,584],{"class":502},[496,3337,1330],{"class":655},[496,3339,584],{"class":502},[496,3341,524],{"class":502},[496,3343,1400],{"class":578},[496,3345,575],{"class":502},[496,3347,584],{"class":502},[496,3349,1788],{"class":1344},[496,3351,584],{"class":502},[496,3353,1330],{"class":655},[496,3355,584],{"class":502},[496,3357,605],{"class":502},[496,3359,608],{"class":502},[496,3361,3362],{"class":498,"line":815},[496,3363,2366],{"class":502},[496,3365,3366,3368,3370,3373,3375,3378],{"class":498,"line":834},[496,3367,1236],{"class":557},[496,3369,443],{"class":502},[496,3371,3372],{"class":544},"AliasNbPages",[496,3374,572],{"class":502},[496,3376,3377],{"class":502},"\"\"",[496,3379,608],{"class":502},[496,3381,3382,3384,3386,3388],{"class":498,"line":857},[496,3383,1236],{"class":557},[496,3385,443],{"class":502},[496,3387,619],{"class":544},[496,3389,622],{"class":502},[496,3391,3392],{"class":498,"line":893},[496,3393,3395],{"class":3394},"sHwdD","// ... body ...\n",[18,3397,3398,3401],{},[26,3399,3400],{},"{nb}"," is a sentinel that gofpdf rewrites at output time with the total page count. It works, it's just one of those things you have to know.",[18,3403,3404],{},[21,3405,721],{},[487,3407,3409],{"className":489,"code":3408,"language":491,"meta":492,"style":492},"doc := gpdf.NewDocument(\n    gpdf.WithPageSize(document.A4),\n    gpdf.WithMargins(document.UniformEdges(document.Mm(20))),\n)\n\ndoc.Header(func(p *template.PageBuilder) {\n    p.AutoRow(func(r *template.RowBuilder) {\n        r.Col(12, func(c *template.ColBuilder) {\n            c.Text(\"ACME Corporation\", template.Bold(), template.FontSize(12))\n            c.Line(template.LineColor(pdf.Gray(0.7)))\n            c.Spacer(document.Mm(4))\n        })\n    })\n})\n\ndoc.Footer(func(p *template.PageBuilder) {\n    p.AutoRow(func(r *template.RowBuilder) {\n        r.Col(6, func(c *template.ColBuilder) {\n            c.Text(\"ACME Corporation\",\n                template.FontSize(8), template.TextColor(pdf.Gray(0.5)))\n        })\n        r.Col(6, func(c *template.ColBuilder) {\n            // \"Page X / Y\" — both pieces are placeholders resolved\n            // by the layout engine after pagination.\n            c.PageNumber(template.AlignRight(),\n                template.FontSize(8), template.TextColor(pdf.Gray(0.5)))\n        })\n    })\n})\n\nfor i := 0; i \u003C 10; i++ {\n    page := doc.AddPage()\n    page.AutoRow(func(r *template.RowBuilder) {\n        r.Col(12, func(c *template.ColBuilder) {\n            c.Text(fmt.Sprintf(\"Body content for page %d.\", i+1))\n        })\n    })\n}\n",[26,3410,3411,3426,3445,3475,3479,3483,3510,3535,3565,3605,3640,3664,3668,3672,3676,3680,3705,3729,3760,3778,3814,3818,3848,3853,3858,3878,3912,3916,3920,3924,3928,3959,3973,3997,4027,4068,4072,4077],{"__ignoreMap":492},[496,3412,3413,3416,3418,3420,3422,3424],{"class":498,"line":499},[496,3414,3415],{"class":557},"doc ",[496,3417,561],{"class":502},[496,3419,823],{"class":557},[496,3421,443],{"class":502},[496,3423,828],{"class":544},[496,3425,831],{"class":502},[496,3427,3428,3431,3433,3435,3437,3439,3441,3443],{"class":498,"line":510},[496,3429,3430],{"class":557},"    gpdf",[496,3432,443],{"class":502},[496,3434,842],{"class":544},[496,3436,572],{"class":502},[496,3438,847],{"class":557},[496,3440,443],{"class":502},[496,3442,598],{"class":557},[496,3444,854],{"class":502},[496,3446,3447,3449,3451,3453,3455,3457,3459,3461,3463,3465,3467,3469,3471,3473],{"class":498,"line":517},[496,3448,3430],{"class":557},[496,3450,443],{"class":502},[496,3452,864],{"class":544},[496,3454,572],{"class":502},[496,3456,847],{"class":557},[496,3458,443],{"class":502},[496,3460,873],{"class":544},[496,3462,572],{"class":502},[496,3464,847],{"class":557},[496,3466,443],{"class":502},[496,3468,882],{"class":544},[496,3470,572],{"class":502},[496,3472,887],{"class":655},[496,3474,890],{"class":502},[496,3476,3477],{"class":498,"line":533},[496,3478,608],{"class":502},[496,3480,3481],{"class":498,"line":538},[496,3482,514],{"emptyLinePlaceholder":513},[496,3484,3485,3488,3490,3493,3495,3497,3499,3501,3503,3506,3508],{"class":498,"line":554},[496,3486,3487],{"class":557},"doc",[496,3489,443],{"class":502},[496,3491,3492],{"class":544},"Header",[496,3494,932],{"class":502},[496,3496,18],{"class":935},[496,3498,939],{"class":502},[496,3500,942],{"class":506},[496,3502,443],{"class":502},[496,3504,3505],{"class":506},"PageBuilder",[496,3507,209],{"class":502},[496,3509,551],{"class":502},[496,3511,3512,3515,3517,3519,3521,3523,3525,3527,3529,3531,3533],{"class":498,"line":611},[496,3513,3514],{"class":557},"    p",[496,3516,443],{"class":502},[496,3518,929],{"class":544},[496,3520,932],{"class":502},[496,3522,936],{"class":935},[496,3524,939],{"class":502},[496,3526,942],{"class":506},[496,3528,443],{"class":502},[496,3530,947],{"class":506},[496,3532,209],{"class":502},[496,3534,551],{"class":502},[496,3536,3537,3539,3541,3543,3545,3547,3549,3551,3553,3555,3557,3559,3561,3563],{"class":498,"line":625},[496,3538,957],{"class":557},[496,3540,443],{"class":502},[496,3542,962],{"class":544},[496,3544,572],{"class":502},[496,3546,967],{"class":655},[496,3548,584],{"class":502},[496,3550,972],{"class":502},[496,3552,975],{"class":935},[496,3554,939],{"class":502},[496,3556,942],{"class":506},[496,3558,443],{"class":502},[496,3560,984],{"class":506},[496,3562,209],{"class":502},[496,3564,551],{"class":502},[496,3566,3567,3569,3571,3573,3575,3577,3579,3581,3583,3585,3587,3589,3592,3594,3596,3598,3600,3602],{"class":498,"line":661},[496,3568,994],{"class":557},[496,3570,443],{"class":502},[496,3572,999],{"class":544},[496,3574,572],{"class":502},[496,3576,575],{"class":502},[496,3578,3187],{"class":578},[496,3580,575],{"class":502},[496,3582,584],{"class":502},[496,3584,1012],{"class":557},[496,3586,443],{"class":502},[496,3588,1032],{"class":544},[496,3590,3591],{"class":502},"(),",[496,3593,1012],{"class":557},[496,3595,443],{"class":502},[496,3597,1017],{"class":544},[496,3599,572],{"class":502},[496,3601,967],{"class":655},[496,3603,3604],{"class":502},"))\n",[496,3606,3607,3609,3611,3614,3616,3618,3620,3623,3625,3627,3629,3632,3634,3637],{"class":498,"line":692},[496,3608,994],{"class":557},[496,3610,443],{"class":502},[496,3612,3613],{"class":544},"Line",[496,3615,572],{"class":502},[496,3617,942],{"class":557},[496,3619,443],{"class":502},[496,3621,3622],{"class":544},"LineColor",[496,3624,572],{"class":502},[496,3626,1236],{"class":557},[496,3628,443],{"class":502},[496,3630,3631],{"class":544},"Gray",[496,3633,572],{"class":502},[496,3635,3636],{"class":655},"0.7",[496,3638,3639],{"class":502},")))\n",[496,3641,3642,3644,3646,3649,3651,3653,3655,3657,3659,3662],{"class":498,"line":713},[496,3643,994],{"class":557},[496,3645,443],{"class":502},[496,3647,3648],{"class":544},"Spacer",[496,3650,572],{"class":502},[496,3652,847],{"class":557},[496,3654,443],{"class":502},[496,3656,882],{"class":544},[496,3658,572],{"class":502},[496,3660,3661],{"class":655},"4",[496,3663,3604],{"class":502},[496,3665,3666],{"class":498,"line":804},[496,3667,1041],{"class":502},[496,3669,3670],{"class":498,"line":815},[496,3671,1047],{"class":502},[496,3673,3674],{"class":498,"line":834},[496,3675,2366],{"class":502},[496,3677,3678],{"class":498,"line":857},[496,3679,514],{"emptyLinePlaceholder":513},[496,3681,3682,3684,3686,3689,3691,3693,3695,3697,3699,3701,3703],{"class":498,"line":893},[496,3683,3487],{"class":557},[496,3685,443],{"class":502},[496,3687,3688],{"class":544},"Footer",[496,3690,932],{"class":502},[496,3692,18],{"class":935},[496,3694,939],{"class":502},[496,3696,942],{"class":506},[496,3698,443],{"class":502},[496,3700,3505],{"class":506},[496,3702,209],{"class":502},[496,3704,551],{"class":502},[496,3706,3707,3709,3711,3713,3715,3717,3719,3721,3723,3725,3727],{"class":498,"line":899},[496,3708,3514],{"class":557},[496,3710,443],{"class":502},[496,3712,929],{"class":544},[496,3714,932],{"class":502},[496,3716,936],{"class":935},[496,3718,939],{"class":502},[496,3720,942],{"class":506},[496,3722,443],{"class":502},[496,3724,947],{"class":506},[496,3726,209],{"class":502},[496,3728,551],{"class":502},[496,3730,3731,3733,3735,3737,3739,3742,3744,3746,3748,3750,3752,3754,3756,3758],{"class":498,"line":904},[496,3732,957],{"class":557},[496,3734,443],{"class":502},[496,3736,962],{"class":544},[496,3738,572],{"class":502},[496,3740,3741],{"class":655},"6",[496,3743,584],{"class":502},[496,3745,972],{"class":502},[496,3747,975],{"class":935},[496,3749,939],{"class":502},[496,3751,942],{"class":506},[496,3753,443],{"class":502},[496,3755,984],{"class":506},[496,3757,209],{"class":502},[496,3759,551],{"class":502},[496,3761,3762,3764,3766,3768,3770,3772,3774,3776],{"class":498,"line":921},[496,3763,994],{"class":557},[496,3765,443],{"class":502},[496,3767,999],{"class":544},[496,3769,572],{"class":502},[496,3771,575],{"class":502},[496,3773,3187],{"class":578},[496,3775,575],{"class":502},[496,3777,3289],{"class":502},[496,3779,3780,3782,3784,3786,3788,3791,3793,3795,3797,3799,3801,3803,3805,3807,3809,3812],{"class":498,"line":954},[496,3781,2270],{"class":557},[496,3783,443],{"class":502},[496,3785,1017],{"class":544},[496,3787,572],{"class":502},[496,3789,3790],{"class":655},"8",[496,3792,1025],{"class":502},[496,3794,1012],{"class":557},[496,3796,443],{"class":502},[496,3798,2286],{"class":544},[496,3800,572],{"class":502},[496,3802,1236],{"class":557},[496,3804,443],{"class":502},[496,3806,3631],{"class":544},[496,3808,572],{"class":502},[496,3810,3811],{"class":655},"0.5",[496,3813,3639],{"class":502},[496,3815,3816],{"class":498,"line":991},[496,3817,1041],{"class":502},[496,3819,3820,3822,3824,3826,3828,3830,3832,3834,3836,3838,3840,3842,3844,3846],{"class":498,"line":1038},[496,3821,957],{"class":557},[496,3823,443],{"class":502},[496,3825,962],{"class":544},[496,3827,572],{"class":502},[496,3829,3741],{"class":655},[496,3831,584],{"class":502},[496,3833,972],{"class":502},[496,3835,975],{"class":935},[496,3837,939],{"class":502},[496,3839,942],{"class":506},[496,3841,443],{"class":502},[496,3843,984],{"class":506},[496,3845,209],{"class":502},[496,3847,551],{"class":502},[496,3849,3850],{"class":498,"line":1044},[496,3851,3852],{"class":3394},"            // \"Page X / Y\" — both pieces are placeholders resolved\n",[496,3854,3855],{"class":498,"line":1050},[496,3856,3857],{"class":3394},"            // by the layout engine after pagination.\n",[496,3859,3860,3862,3864,3867,3869,3871,3873,3876],{"class":498,"line":1055},[496,3861,994],{"class":557},[496,3863,443],{"class":502},[496,3865,3866],{"class":544},"PageNumber",[496,3868,572],{"class":502},[496,3870,942],{"class":557},[496,3872,443],{"class":502},[496,3874,3875],{"class":544},"AlignRight",[496,3877,2277],{"class":502},[496,3879,3880,3882,3884,3886,3888,3890,3892,3894,3896,3898,3900,3902,3904,3906,3908,3910],{"class":498,"line":1077},[496,3881,2270],{"class":557},[496,3883,443],{"class":502},[496,3885,1017],{"class":544},[496,3887,572],{"class":502},[496,3889,3790],{"class":655},[496,3891,1025],{"class":502},[496,3893,1012],{"class":557},[496,3895,443],{"class":502},[496,3897,2286],{"class":544},[496,3899,572],{"class":502},[496,3901,1236],{"class":557},[496,3903,443],{"class":502},[496,3905,3631],{"class":544},[496,3907,572],{"class":502},[496,3909,3811],{"class":655},[496,3911,3639],{"class":502},[496,3913,3914],{"class":498,"line":1093},[496,3915,1041],{"class":502},[496,3917,3918],{"class":498,"line":1111},[496,3919,1047],{"class":502},[496,3921,3922],{"class":498,"line":1117},[496,3923,2366],{"class":502},[496,3925,3926],{"class":498,"line":1163},[496,3927,514],{"emptyLinePlaceholder":513},[496,3929,3930,3932,3935,3937,3939,3942,3944,3947,3949,3951,3954,3957],{"class":498,"line":1178},[496,3931,1717],{"class":520},[496,3933,3934],{"class":557}," i ",[496,3936,561],{"class":502},[496,3938,1330],{"class":655},[496,3940,3941],{"class":502},";",[496,3943,3934],{"class":557},[496,3945,3946],{"class":502},"\u003C",[496,3948,678],{"class":655},[496,3950,3941],{"class":502},[496,3952,3953],{"class":557}," i",[496,3955,3956],{"class":502},"++",[496,3958,551],{"class":502},[496,3960,3961,3963,3965,3967,3969,3971],{"class":498,"line":1183},[496,3962,907],{"class":557},[496,3964,561],{"class":502},[496,3966,912],{"class":557},[496,3968,443],{"class":502},[496,3970,619],{"class":544},[496,3972,622],{"class":502},[496,3974,3975,3977,3979,3981,3983,3985,3987,3989,3991,3993,3995],{"class":498,"line":2971},[496,3976,924],{"class":557},[496,3978,443],{"class":502},[496,3980,929],{"class":544},[496,3982,932],{"class":502},[496,3984,936],{"class":935},[496,3986,939],{"class":502},[496,3988,942],{"class":506},[496,3990,443],{"class":502},[496,3992,947],{"class":506},[496,3994,209],{"class":502},[496,3996,551],{"class":502},[496,3998,3999,4001,4003,4005,4007,4009,4011,4013,4015,4017,4019,4021,4023,4025],{"class":498,"line":2976},[496,4000,957],{"class":557},[496,4002,443],{"class":502},[496,4004,962],{"class":544},[496,4006,572],{"class":502},[496,4008,967],{"class":655},[496,4010,584],{"class":502},[496,4012,972],{"class":502},[496,4014,975],{"class":935},[496,4016,939],{"class":502},[496,4018,942],{"class":506},[496,4020,443],{"class":502},[496,4022,984],{"class":506},[496,4024,209],{"class":502},[496,4026,551],{"class":502},[496,4028,4029,4031,4033,4035,4037,4040,4042,4044,4046,4048,4051,4053,4055,4057,4059,4061,4064,4066],{"class":498,"line":2996},[496,4030,994],{"class":557},[496,4032,443],{"class":502},[496,4034,999],{"class":544},[496,4036,572],{"class":502},[496,4038,4039],{"class":557},"fmt",[496,4041,443],{"class":502},[496,4043,3299],{"class":544},[496,4045,572],{"class":502},[496,4047,575],{"class":502},[496,4049,4050],{"class":578},"Body content for page ",[496,4052,3310],{"class":3309},[496,4054,443],{"class":578},[496,4056,575],{"class":502},[496,4058,584],{"class":502},[496,4060,3953],{"class":557},[496,4062,4063],{"class":502},"+",[496,4065,1323],{"class":655},[496,4067,3604],{"class":502},[496,4069,4070],{"class":498,"line":3024},[496,4071,1041],{"class":502},[496,4073,4075],{"class":498,"line":4074},37,[496,4076,1047],{"class":502},[496,4078,4080],{"class":498,"line":4079},38,[496,4081,716],{"class":502},[18,4083,4084,105,4086,4089,4090,4092,4093,4096],{},[26,4085,3866],{},[26,4087,4088],{},"TotalPages"," are placeholders. They get expanded after pagination, when the layout engine knows how many pages exist. No ",[26,4091,3400],{}," sentinel, no manual ",[26,4094,4095],{},"SetY(-15)"," to peg the footer to the bottom — the footer is just a tree, and the engine reserves space for it on every page automatically.",[13,4098,4100],{"id":4099},"before-after-5-producing-bytes-for-an-http-handler","Before / After 5: producing bytes for an HTTP handler",[18,4102,4103,4104,4106,4107,4110,4111,4114],{},"Most production gofpdf code doesn't write to a file. It writes to an ",[26,4105,1207],{}," — usually a ",[26,4108,4109],{},"http.ResponseWriter"," returning ",[26,4112,4113],{},"application/pdf"," to a browser. This is the pair where gpdf's API is closest to gofpdf's.",[18,4116,4117],{},[21,4118,485],{},[487,4120,4122],{"className":489,"code":4121,"language":491,"meta":492,"style":492},"func handler(w http.ResponseWriter, r *http.Request) {\n    pdf := gofpdf.New(\"P\", \"mm\", \"A4\", \"\")\n    pdf.AddPage()\n    pdf.SetFont(\"Arial\", \"\", 12)\n    pdf.Cell(0, 10, \"Generated at \"+time.Now().Format(time.RFC3339))\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",[26,4123,4124,4163,4205,4215,4241,4293,4297,4330,4359,4389,4393],{"__ignoreMap":492},[496,4125,4126,4128,4131,4133,4136,4139,4141,4144,4146,4149,4151,4154,4156,4159,4161],{"class":498,"line":499},[496,4127,541],{"class":502},[496,4129,4130],{"class":544}," handler",[496,4132,572],{"class":502},[496,4134,4135],{"class":935},"w",[496,4137,4138],{"class":506}," http",[496,4140,443],{"class":502},[496,4142,4143],{"class":506},"ResponseWriter",[496,4145,584],{"class":502},[496,4147,4148],{"class":935}," r",[496,4150,939],{"class":502},[496,4152,4153],{"class":506},"http",[496,4155,443],{"class":502},[496,4157,4158],{"class":506},"Request",[496,4160,209],{"class":502},[496,4162,551],{"class":502},[496,4164,4165,4167,4169,4171,4173,4175,4177,4179,4181,4183,4185,4187,4189,4191,4193,4195,4197,4199,4201,4203],{"class":498,"line":510},[496,4166,558],{"class":557},[496,4168,561],{"class":502},[496,4170,564],{"class":557},[496,4172,443],{"class":502},[496,4174,569],{"class":544},[496,4176,572],{"class":502},[496,4178,575],{"class":502},[496,4180,579],{"class":578},[496,4182,575],{"class":502},[496,4184,584],{"class":502},[496,4186,524],{"class":502},[496,4188,589],{"class":578},[496,4190,575],{"class":502},[496,4192,584],{"class":502},[496,4194,524],{"class":502},[496,4196,598],{"class":578},[496,4198,575],{"class":502},[496,4200,584],{"class":502},[496,4202,605],{"class":502},[496,4204,608],{"class":502},[496,4206,4207,4209,4211,4213],{"class":498,"line":517},[496,4208,614],{"class":557},[496,4210,443],{"class":502},[496,4212,619],{"class":544},[496,4214,622],{"class":502},[496,4216,4217,4219,4221,4223,4225,4227,4229,4231,4233,4235,4237,4239],{"class":498,"line":533},[496,4218,614],{"class":557},[496,4220,443],{"class":502},[496,4222,632],{"class":544},[496,4224,572],{"class":502},[496,4226,575],{"class":502},[496,4228,639],{"class":578},[496,4230,575],{"class":502},[496,4232,584],{"class":502},[496,4234,605],{"class":502},[496,4236,584],{"class":502},[496,4238,3162],{"class":655},[496,4240,608],{"class":502},[496,4242,4243,4245,4247,4249,4251,4253,4255,4257,4259,4261,4264,4266,4268,4271,4273,4276,4279,4282,4284,4286,4288,4291],{"class":498,"line":538},[496,4244,614],{"class":557},[496,4246,443],{"class":502},[496,4248,668],{"class":544},[496,4250,572],{"class":502},[496,4252,1762],{"class":655},[496,4254,584],{"class":502},[496,4256,678],{"class":655},[496,4258,584],{"class":502},[496,4260,524],{"class":502},[496,4262,4263],{"class":578},"Generated at ",[496,4265,575],{"class":502},[496,4267,4063],{"class":502},[496,4269,4270],{"class":557},"time",[496,4272,443],{"class":502},[496,4274,4275],{"class":544},"Now",[496,4277,4278],{"class":502},"().",[496,4280,4281],{"class":544},"Format",[496,4283,572],{"class":502},[496,4285,4270],{"class":557},[496,4287,443],{"class":502},[496,4289,4290],{"class":557},"RFC3339",[496,4292,3604],{"class":502},[496,4294,4295],{"class":498,"line":554},[496,4296,514],{"emptyLinePlaceholder":513},[496,4298,4299,4302,4304,4306,4308,4311,4313,4315,4318,4320,4322,4324,4326,4328],{"class":498,"line":611},[496,4300,4301],{"class":557},"    w",[496,4303,443],{"class":502},[496,4305,3492],{"class":544},[496,4307,4278],{"class":502},[496,4309,4310],{"class":544},"Set",[496,4312,572],{"class":502},[496,4314,575],{"class":502},[496,4316,4317],{"class":578},"Content-Type",[496,4319,575],{"class":502},[496,4321,584],{"class":502},[496,4323,524],{"class":502},[496,4325,4113],{"class":578},[496,4327,575],{"class":502},[496,4329,608],{"class":502},[496,4331,4332,4334,4336,4338,4340,4342,4345,4347,4349,4351,4353,4355,4357],{"class":498,"line":625},[496,4333,1080],{"class":520},[496,4335,1063],{"class":557},[496,4337,561],{"class":502},[496,4339,3320],{"class":557},[496,4341,443],{"class":502},[496,4343,4344],{"class":544},"Output",[496,4346,572],{"class":502},[496,4348,4135],{"class":557},[496,4350,1152],{"class":502},[496,4352,1063],{"class":557},[496,4354,1085],{"class":502},[496,4356,1088],{"class":502},[496,4358,551],{"class":502},[496,4360,4361,4364,4366,4369,4371,4373,4375,4378,4380,4382,4384,4387],{"class":498,"line":661},[496,4362,4363],{"class":557},"        http",[496,4365,443],{"class":502},[496,4367,4368],{"class":544},"Error",[496,4370,572],{"class":502},[496,4372,4135],{"class":557},[496,4374,584],{"class":502},[496,4376,4377],{"class":557}," err",[496,4379,443],{"class":502},[496,4381,4368],{"class":544},[496,4383,3591],{"class":502},[496,4385,4386],{"class":655}," 500",[496,4388,608],{"class":502},[496,4390,4391],{"class":498,"line":692},[496,4392,1114],{"class":502},[496,4394,4395],{"class":498,"line":713},[496,4396,716],{"class":502},[18,4398,4399],{},[21,4400,721],{},[487,4402,4404],{"className":489,"code":4403,"language":491,"meta":492,"style":492},"func 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(\"Generated at \" + time.Now().Format(time.RFC3339))\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",[26,4405,4406,4438,4452,4470,4500,4504,4508,4522,4546,4576,4616,4620,4624,4628,4658,4687,4713,4717],{"__ignoreMap":492},[496,4407,4408,4410,4412,4414,4416,4418,4420,4422,4424,4426,4428,4430,4432,4434,4436],{"class":498,"line":499},[496,4409,541],{"class":502},[496,4411,4130],{"class":544},[496,4413,572],{"class":502},[496,4415,4135],{"class":935},[496,4417,4138],{"class":506},[496,4419,443],{"class":502},[496,4421,4143],{"class":506},[496,4423,584],{"class":502},[496,4425,4148],{"class":935},[496,4427,939],{"class":502},[496,4429,4153],{"class":506},[496,4431,443],{"class":502},[496,4433,4158],{"class":506},[496,4435,209],{"class":502},[496,4437,551],{"class":502},[496,4439,4440,4442,4444,4446,4448,4450],{"class":498,"line":510},[496,4441,818],{"class":557},[496,4443,561],{"class":502},[496,4445,823],{"class":557},[496,4447,443],{"class":502},[496,4449,828],{"class":544},[496,4451,831],{"class":502},[496,4453,4454,4456,4458,4460,4462,4464,4466,4468],{"class":498,"line":517},[496,4455,837],{"class":557},[496,4457,443],{"class":502},[496,4459,842],{"class":544},[496,4461,572],{"class":502},[496,4463,847],{"class":557},[496,4465,443],{"class":502},[496,4467,598],{"class":557},[496,4469,854],{"class":502},[496,4471,4472,4474,4476,4478,4480,4482,4484,4486,4488,4490,4492,4494,4496,4498],{"class":498,"line":533},[496,4473,837],{"class":557},[496,4475,443],{"class":502},[496,4477,864],{"class":544},[496,4479,572],{"class":502},[496,4481,847],{"class":557},[496,4483,443],{"class":502},[496,4485,873],{"class":544},[496,4487,572],{"class":502},[496,4489,847],{"class":557},[496,4491,443],{"class":502},[496,4493,882],{"class":544},[496,4495,572],{"class":502},[496,4497,887],{"class":655},[496,4499,890],{"class":502},[496,4501,4502],{"class":498,"line":538},[496,4503,896],{"class":502},[496,4505,4506],{"class":498,"line":554},[496,4507,514],{"emptyLinePlaceholder":513},[496,4509,4510,4512,4514,4516,4518,4520],{"class":498,"line":611},[496,4511,907],{"class":557},[496,4513,561],{"class":502},[496,4515,912],{"class":557},[496,4517,443],{"class":502},[496,4519,619],{"class":544},[496,4521,622],{"class":502},[496,4523,4524,4526,4528,4530,4532,4534,4536,4538,4540,4542,4544],{"class":498,"line":625},[496,4525,924],{"class":557},[496,4527,443],{"class":502},[496,4529,929],{"class":544},[496,4531,932],{"class":502},[496,4533,936],{"class":935},[496,4535,939],{"class":502},[496,4537,942],{"class":506},[496,4539,443],{"class":502},[496,4541,947],{"class":506},[496,4543,209],{"class":502},[496,4545,551],{"class":502},[496,4547,4548,4550,4552,4554,4556,4558,4560,4562,4564,4566,4568,4570,4572,4574],{"class":498,"line":661},[496,4549,957],{"class":557},[496,4551,443],{"class":502},[496,4553,962],{"class":544},[496,4555,572],{"class":502},[496,4557,967],{"class":655},[496,4559,584],{"class":502},[496,4561,972],{"class":502},[496,4563,975],{"class":935},[496,4565,939],{"class":502},[496,4567,942],{"class":506},[496,4569,443],{"class":502},[496,4571,984],{"class":506},[496,4573,209],{"class":502},[496,4575,551],{"class":502},[496,4577,4578,4580,4582,4584,4586,4588,4590,4592,4595,4598,4600,4602,4604,4606,4608,4610,4612,4614],{"class":498,"line":692},[496,4579,994],{"class":557},[496,4581,443],{"class":502},[496,4583,999],{"class":544},[496,4585,572],{"class":502},[496,4587,575],{"class":502},[496,4589,4263],{"class":578},[496,4591,575],{"class":502},[496,4593,4594],{"class":502}," +",[496,4596,4597],{"class":557}," time",[496,4599,443],{"class":502},[496,4601,4275],{"class":544},[496,4603,4278],{"class":502},[496,4605,4281],{"class":544},[496,4607,572],{"class":502},[496,4609,4270],{"class":557},[496,4611,443],{"class":502},[496,4613,4290],{"class":557},[496,4615,3604],{"class":502},[496,4617,4618],{"class":498,"line":713},[496,4619,1041],{"class":502},[496,4621,4622],{"class":498,"line":804},[496,4623,1047],{"class":502},[496,4625,4626],{"class":498,"line":815},[496,4627,514],{"emptyLinePlaceholder":513},[496,4629,4630,4632,4634,4636,4638,4640,4642,4644,4646,4648,4650,4652,4654,4656],{"class":498,"line":834},[496,4631,4301],{"class":557},[496,4633,443],{"class":502},[496,4635,3492],{"class":544},[496,4637,4278],{"class":502},[496,4639,4310],{"class":544},[496,4641,572],{"class":502},[496,4643,575],{"class":502},[496,4645,4317],{"class":578},[496,4647,575],{"class":502},[496,4649,584],{"class":502},[496,4651,524],{"class":502},[496,4653,4113],{"class":578},[496,4655,575],{"class":502},[496,4657,608],{"class":502},[496,4659,4660,4662,4664,4666,4668,4670,4673,4675,4677,4679,4681,4683,4685],{"class":498,"line":857},[496,4661,1080],{"class":520},[496,4663,1063],{"class":557},[496,4665,561],{"class":502},[496,4667,912],{"class":557},[496,4669,443],{"class":502},[496,4671,4672],{"class":544},"Render",[496,4674,572],{"class":502},[496,4676,4135],{"class":557},[496,4678,1152],{"class":502},[496,4680,1063],{"class":557},[496,4682,1085],{"class":502},[496,4684,1088],{"class":502},[496,4686,551],{"class":502},[496,4688,4689,4691,4693,4695,4697,4699,4701,4703,4705,4707,4709,4711],{"class":498,"line":893},[496,4690,4363],{"class":557},[496,4692,443],{"class":502},[496,4694,4368],{"class":544},[496,4696,572],{"class":502},[496,4698,4135],{"class":557},[496,4700,584],{"class":502},[496,4702,4377],{"class":557},[496,4704,443],{"class":502},[496,4706,4368],{"class":544},[496,4708,3591],{"class":502},[496,4710,4386],{"class":655},[496,4712,608],{"class":502},[496,4714,4715],{"class":498,"line":899},[496,4716,1114],{"class":502},[496,4718,4719],{"class":498,"line":904},[496,4720,716],{"class":502},[18,4722,4723,4724,4726,4727,4730,4731,4734,4735,4738],{},"Same shape. ",[26,4725,429],{}," streams the PDF directly into the response. If you want to set ",[26,4728,4729],{},"Content-Length",", call ",[26,4732,4733],{},"Generate()"," first to get the byte slice, then ",[26,4736,4737],{},"len()"," it.",[13,4740,4742],{"id":4741},"how-fast-is-fast-enough","How fast is \"fast enough\"?",[18,4744,4745,4746,4748,4749,4752],{},"gpdf is roughly ",[21,4747,36],{}," on the workloads people actually run. The numbers below are from ",[26,4750,4751],{},"_benchmark/benchmark_test.go"," on an Apple M1 with Go 1.25.",[151,4754,4755,4772],{},[154,4756,4757],{},[157,4758,4759,4762,4764,4766,4769],{},[160,4760,4761],{},"Benchmark",[160,4763,23],{},[160,4765,165],{},[160,4767,4768],{},"gopdf",[160,4770,4771],{},"Maroto v2",[169,4773,4774,4793,4812,4830],{},[157,4775,4776,4779,4784,4787,4790],{},[174,4777,4778],{},"Single page",[174,4780,4781],{},[21,4782,4783],{},"13 µs",[174,4785,4786],{},"132 µs",[174,4788,4789],{},"423 µs",[174,4791,4792],{},"237 µs",[157,4794,4795,4798,4803,4806,4809],{},[174,4796,4797],{},"4×10 table",[174,4799,4800],{},[21,4801,4802],{},"108 µs",[174,4804,4805],{},"241 µs",[174,4807,4808],{},"835 µs",[174,4810,4811],{},"8.6 ms",[157,4813,4814,4817,4822,4825,4827],{},[174,4815,4816],{},"100-page document",[174,4818,4819],{},[21,4820,4821],{},"683 µs",[174,4823,4824],{},"11.7 ms",[174,4826,4811],{},[174,4828,4829],{},"19.8 ms",[157,4831,4832,4835,4840,4843,4846],{},[174,4833,4834],{},"Complex CJK invoice",[174,4836,4837],{},[21,4838,4839],{},"133 µs",[174,4841,4842],{},"254 µs",[174,4844,4845],{},"997 µs",[174,4847,4848],{},"10.4 ms",[18,4850,4851],{},"These aren't synthetic — the table benchmark is a 4-column, 10-row invoice line-items table; the 100-page benchmark is a paginated report with a repeating header and page numbers. The shape matches what production code actually does.",[18,4853,4854],{},"A small note on what these numbers mean. At 13 µs per single page, a single core can produce ~75,000 hello-world PDFs per second. At 108 µs per table-rich page, ~9,000 invoices per second. The point isn't bragging rights — it's that you can stop thinking about whether to cache or async-queue PDF generation. For most workloads, generating on the request path is fine.",[13,4856,4858],{"id":4857},"what-youre-giving-up","What you're giving up",[18,4860,4861],{},"Nothing in this guide is interesting if it papers over real gaps. Here's what gpdf doesn't do that gofpdf does:",[4863,4864,4865,4874,4891,4897],"ul",{},[113,4866,4867,202,4870,4873],{},[21,4868,4869],{},"Arbitrary line angles, beziers, and complex paths.",[26,4871,4872],{},"c.Line()"," draws a horizontal rule across a column. If you're producing technical drawings or charts with custom geometry, gpdf isn't there yet. (Charts as pre-rendered images: works fine.)",[113,4875,4876,4881,4882,4884,4885,4887,4888,4890],{},[21,4877,4878,4880],{},[26,4879,32],{}," and absolute cursor work."," You can do absolute positioning with ",[26,4883,349],{},", but if your existing code is 2,000 lines of ",[26,4886,32],{}," followed by ",[26,4889,668],{},", the migration is more like a rewrite. The upside is the rewritten code is usually half the size.",[113,4892,4893,4896],{},[21,4894,4895],{},"Form fields (AcroForm)."," gpdf doesn't yet generate fillable form fields. If your PDFs are form templates that users fill in a viewer, stay on a library that supports AcroForm — for now.",[113,4898,4899,4902],{},[21,4900,4901],{},"Annotations and bookmarks."," Basic outline support exists; rich annotations don't.",[18,4904,4905],{},"If none of those bite, the migration is straight-through. If one of them does, file an issue — the roadmap is driven by what people ask for.",[13,4907,4909],{"id":4908},"faq","FAQ",[18,4911,4912,4915],{},[21,4913,4914],{},"Is gpdf a fork of gofpdf?","\nNo. gpdf is a clean reimplementation. The PDF wire-format work, the layout engine, the TrueType subsetter — all written from scratch in pure Go. There's no shared lineage with gofpdf or its forks. The reason it has to be a clean rewrite is that gofpdf's architecture is built around a single mutable cursor; you can't get a declarative grid out of that without breaking every existing call site.",[18,4917,4918,4921,4922,4925,4926,4929,4930,4933,4934,4937],{},[21,4919,4920],{},"Does gpdf have any external dependencies?","\nThe core library has zero. Run ",[26,4923,4924],{},"go mod graph | grep gpdf"," after ",[26,4927,4928],{},"go get github.com/gpdf-dev/gpdf"," and you'll see one line. The ",[26,4931,4932],{},"gpdf-pro"," add-on (HTML→PDF, AES encryption, signatures, PDF/A) pulls in ",[26,4935,4936],{},"golang.org/x/net"," for HTML parsing, but that's opt-in and not required for migration.",[18,4939,4940,4943,4944,4947],{},[21,4941,4942],{},"What about CGO? gofpdf was CGO-free, what about gpdf?","\nSame. Pure Go, no CGO. Cross-compile with ",[26,4945,4946],{},"GOOS=linux GOARCH=arm64 go build"," and ship a static binary. This matters for distroless and Alpine images, where dragging in a CGO toolchain doubles your container size.",[18,4949,4950,4956,4957,4959],{},[21,4951,4952,4953,4955],{},"My existing gofpdf code uses ",[26,4954,32],{}," for absolute positioning everywhere. Can I migrate without rewriting?","\nYou can wrap ",[26,4958,349],{}," and get something that feels similar. But if your code is structured around cursor manipulation, the layout-engine model is a mental shift, not a syntactic one. Read the 12-column grid post (link to come) before estimating the work — most teams find the rewrite is shorter than the original.",[18,4961,4962,4965],{},[21,4963,4964],{},"What if go-pdf/fpdf gets unarchived?","\nThen you have one more option. The bet behind gpdf isn't that gofpdf will stay archived forever — it's that the architecture (cursor-based, single-byte fonts, no native CJK) is a dead end regardless of who maintains it. PDF generation in 2026 looks more like building a web page than driving a plotter, and the API should reflect that.",[13,4967,4969],{"id":4968},"try-gpdf","Try gpdf",[18,4971,4972],{},"gpdf is a Go library for generating PDFs. MIT licensed, zero external dependencies, native CJK support.",[487,4974,4978],{"className":4975,"code":4976,"language":4977,"meta":492,"style":492},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","go get github.com/gpdf-dev/gpdf\n","bash",[26,4979,4980],{"__ignoreMap":492},[496,4981,4982,4984,4987],{"class":498,"line":499},[496,4983,491],{"class":506},[496,4985,4986],{"class":578}," get",[496,4988,4989],{"class":578}," github.com/gpdf-dev/gpdf\n",[18,4991,4992,4999,5000],{},[4993,4994,4998],"a",{"href":4995,"rel":4996},"https://github.com/gpdf-dev/gpdf",[4997],"nofollow","⭐ Star on GitHub"," · ",[4993,5001,5004],{"href":5002,"rel":5003},"https://gpdf.dev/docs/quickstart",[4997],"Read the docs",[13,5006,5008],{"id":5007},"next-reads","Next reads",[4863,5010,5011,5017,5022],{},[113,5012,5013,5014],{},"How does the 12-column grid work in gpdf? ",[83,5015,5016],{},"(coming soon)",[113,5018,5019,5020],{},"How do I embed a Japanese font in gpdf? ",[83,5021,5016],{},[113,5023,5024,5028,5029],{},[4993,5025,5027],{"href":5002,"rel":5026},[4997],"Quickstart"," — five-minute setup, including ",[26,5030,5031],{},"go.mod",[5033,5034,5035],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}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}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}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 .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 .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":492,"searchDepth":510,"depth":510,"links":5037},[5038,5039,5040,5041,5042,5043,5044,5045,5046,5047,5048,5049,5050,5051],{"id":15,"depth":510,"text":16},{"id":71,"depth":510,"text":72},{"id":98,"depth":510,"text":99},{"id":145,"depth":510,"text":146},{"id":476,"depth":510,"text":477},{"id":1211,"depth":510,"text":1212},{"id":2389,"depth":510,"text":2390},{"id":3049,"depth":510,"text":3050},{"id":4099,"depth":510,"text":4100},{"id":4741,"depth":510,"text":4742},{"id":4857,"depth":510,"text":4858},{"id":4908,"depth":510,"text":4909},{"id":4968,"depth":510,"text":4969},{"id":5007,"depth":510,"text":5008},"2026-04-14","jung-kurt/gofpdf was archived in 2021. This guide maps every gofpdf API to gpdf — a pure-Go replacement with native CJK support and zero dependencies.",false,"md",{"name":5057,"totalTime":5058,"tools":5059,"steps":5061},"Migrate a Go project from gofpdf to gpdf","PT30M",[5060],"Go 1.22+",[5062,5065,5068,5071,5074,5077],{"name":5063,"text":5064},"Replace the import path","Swap github.com/jung-kurt/gofpdf (archived 2021) and github.com/go-pdf/fpdf (archived 2025) for github.com/gpdf-dev/gpdf, github.com/gpdf-dev/gpdf/document, and github.com/gpdf-dev/gpdf/template.",{"name":5066,"text":5067},"Construct the document with builders instead of cursors","Call gpdf.NewDocument with WithPageSize, WithMargins, and optional WithFont. Instead of driving a cursor with SetXY, add pages via doc.AddPage() and describe content with RowBuilder and ColBuilder.",{"name":5069,"text":5070},"Convert Cell and MultiCell calls to declarative Text","Replace pdf.Cell and pdf.MultiCell with c.Text(...) inside a column. Text wraps at the column boundary automatically, so MultiCell's trailing flag disappears. Font size, weight, and color become per-text options.",{"name":5072,"text":5073},"Register CJK fonts through WithFont","For Japanese, Chinese, or Korean text, replace pdf.AddUTF8Font with gpdf.WithFont(name, ttfBytes) at document construction. No more TTF path bookkeeping or UTF-8 flag — subset embedding happens automatically.",{"name":5075,"text":5076},"Rewrite tables with rows and columns","Drop the nested Cell loops with manual column widths. Use row.Col(n, fn) inside an AutoRow to build table rows; the 12-column grid computes widths and handles page breaks.",{"name":5078,"text":5079},"Switch the output call","Replace pdf.OutputFileAndClose(path) with doc.Generate() plus os.WriteFile(path, data, 0o644), or use doc.Render(w) to stream to an io.Writer.",null,{},"/blog/gofpdf-migration",{"title":5,"description":5053},"blog/001.gofpdf-migration",[5086,5087,5088],"migration","comparison","tutorial","rwfhEq6jxLzrt6NECIA6pJM2d2cu0CQxTMRm2Pt1Znk",1776526785037]