[{"data":1,"prerenderedAt":2511},["ShallowReactive",2],{"blog-pt-invoice-pdf-go-under-50-lines":3},{"id":4,"title":5,"author":6,"body":10,"date":2477,"description":2478,"draft":2479,"extension":2480,"howTo":2481,"image":2502,"meta":2503,"navigation":131,"path":2504,"seo":2505,"stem":2506,"tags":2507,"updated":2502,"__hash__":2510},"blogPt/pt/blog/012.invoice-pdf-go-under-50-lines.md","Gere uma fatura em PDF em Go em menos de 50 linhas",{"name":7,"url":8,"avatar":9},"Taiki Noda","https://nadai.dev/en/about","https://nadai.dev/og-default.png",{"type":11,"value":12,"toc":2458},"minimark",[13,18,36,39,64,70,74,77,80,96,99,104,107,111,1145,1154,1158,1163,1166,1233,1248,1252,1288,1301,1305,1412,1427,1436,1447,1451,1614,1623,1632,1636,1687,1697,1701,1808,1825,1829,1839,1963,1973,2079,2088,2094,2178,2182,2249,2253,2305,2308,2312,2318,2338,2348,2366,2380,2394,2398,2401,2413,2427,2431,2454],[14,15,17],"h2",{"id":16},"tldr","TL;DR",[19,20,21,22,26,27,31,32,35],"p",{},"Uma fatura PDF funcional em Go, de ponta a ponta, em ",[23,24,25],"strong",{},"50 linhas",". Um ",[28,29,30],"code",{},"main.go",", um ",[28,33,34],{},"go get",", sem Chromium, sem CGO, sem linguagem de template, sem HTML. Tabela, linhas com zebrado, totais alinhados à direita. Roda. O código está abaixo; o resto do post explica o que cada bloco faz e onde o padrão deixa de escalar.",[19,37,38],{},"Se quiser ler o código primeiro:",[40,41,46],"pre",{"className":42,"code":43,"language":44,"meta":45,"style":45},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","go get github.com/gpdf-dev/gpdf\n","bash","",[28,47,48],{"__ignoreMap":45},[49,50,53,57,61],"span",{"class":51,"line":52},"line",1,[49,54,56],{"class":55},"sBMFI","go",[49,58,60],{"class":59},"sfazB"," get",[49,62,63],{"class":59}," github.com/gpdf-dev/gpdf\n",[19,65,66,67,69],{},"E cole o ",[28,68,30],{}," da próxima seção.",[14,71,73],{"id":72},"por-que-menos-de-50-linhas-é-o-limite-que-importa","Por que \"menos de 50 linhas\" é o limite que importa",[19,75,76],{},"A razão honesta pela qual este post existe: a maioria das pessoas que pesquisa \"gerar fatura pdf em go\" encontra artigos que (a) recomendam subir Chromium headless, ou (b) mostram 400 linhas de operadores PDF de baixo nível para renderizar uma única tabela. Tecnicamente as duas estão certas. Nenhuma é o formato que a tarefa tem.",[19,78,79],{},"Uma fatura razoável tem:",[81,82,83,87,90,93],"ul",{},[84,85,86],"li",{},"Cabeçalho com sua empresa e a do cliente",[84,88,89],{},"Número da fatura e data de vencimento",[84,91,92],{},"Tabela de itens",[84,94,95],{},"Um total",[19,97,98],{},"Quatro coisas. Deveriam ser quatro blocos de código. Se não cabe em uma tela, a biblioteca foi escolhida errada.",[19,100,101,103],{},[23,102,25],{}," é mais ou menos o limite em que o código ainda cabe em uma tela de editor normal. É também o patamar em que um revisor lê do começo ao fim em vez de pular para os testes. Atingir esse patamar significa que você pode colar o resultado numa mensagem de Slack e alguém aprende a biblioteca só por aquela mensagem.",[19,105,106],{},"O código abaixo está formatado com gofmt, imports totalmente expandidos, todos os caminhos de erro tratados. Sem truques, sem pacote helper escondido. O que você vê é o que compila.",[14,108,110],{"id":109},"as-50-linhas","As 50 linhas",[40,112,115],{"className":113,"code":114,"language":56,"meta":45,"style":45},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","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/pdf\"\n    \"github.com/gpdf-dev/gpdf/template\"\n)\n\nfunc main() {\n    doc := gpdf.NewDocument(template.WithPageSize(document.A4))\n    page := doc.AddPage()\n    page.AutoRow(func(r *template.RowBuilder) {\n        r.Col(6, func(c *template.ColBuilder) {\n            c.Text(\"ACME Ltda.\", template.FontSize(22), template.Bold())\n            c.Text(\"Av. Paulista 1000, São Paulo 01310\")\n        })\n        r.Col(6, func(c *template.ColBuilder) {\n            c.Text(\"FATURA #INV-2026-001\", template.Bold(), template.AlignRight())\n            c.Text(\"Vencimento: 2026-03-31\", template.AlignRight())\n        })\n    })\n    page.AutoRow(func(r *template.RowBuilder) {\n        r.Col(12, func(c *template.ColBuilder) {\n            c.Spacer(document.Mm(6))\n            c.Table(\n                []string{\"Descrição\", \"Qtd.\", \"Valor unit.\", \"Valor\"},\n                [][]string{\n                    {\"Desenvolvimento frontend\", \"40 h\", \"R$ 750,00\", \"R$ 30.000,00\"},\n                    {\"Desenvolvimento backend\", \"60 h\", \"R$ 750,00\", \"R$ 45.000,00\"},\n                    {\"Design UI/UX\", \"20 h\", \"R$ 600,00\", \"R$ 12.000,00\"},\n                },\n                template.ColumnWidths(40, 15, 20, 25),\n                template.TableHeaderStyle(template.Bold(), template.BgColor(pdf.RGBHex(0xF0F0F0))),\n                template.TableStripe(pdf.RGBHex(0xFAFAFA)),\n            )\n            c.Text(\"Total: R$ 87.000,00\", template.AlignRight(), template.Bold(), template.FontSize(14))\n        })\n    })\n    b, err := doc.Generate()\n    if err != nil {\n        log.Fatal(err)\n    }\n    if err := os.WriteFile(\"invoice.pdf\", b, 0644); err != nil {\n        log.Fatal(err)\n    }\n}\n",[28,116,117,126,133,143,155,165,170,180,190,200,210,216,221,237,280,299,332,371,420,440,446,477,515,543,548,554,579,611,636,649,700,711,753,793,834,840,874,919,945,951,1000,1005,1010,1032,1048,1066,1072,1119,1134,1139],{"__ignoreMap":45},[49,118,119,123],{"class":51,"line":52},[49,120,122],{"class":121},"sMK4o","package",[49,124,125],{"class":55}," main\n",[49,127,129],{"class":51,"line":128},2,[49,130,132],{"emptyLinePlaceholder":131},true,"\n",[49,134,136,140],{"class":51,"line":135},3,[49,137,139],{"class":138},"s7zQu","import",[49,141,142],{"class":121}," (\n",[49,144,146,149,152],{"class":51,"line":145},4,[49,147,148],{"class":121},"    \"",[49,150,151],{"class":55},"log",[49,153,154],{"class":121},"\"\n",[49,156,158,160,163],{"class":51,"line":157},5,[49,159,148],{"class":121},[49,161,162],{"class":55},"os",[49,164,154],{"class":121},[49,166,168],{"class":51,"line":167},6,[49,169,132],{"emptyLinePlaceholder":131},[49,171,173,175,178],{"class":51,"line":172},7,[49,174,148],{"class":121},[49,176,177],{"class":55},"github.com/gpdf-dev/gpdf",[49,179,154],{"class":121},[49,181,183,185,188],{"class":51,"line":182},8,[49,184,148],{"class":121},[49,186,187],{"class":55},"github.com/gpdf-dev/gpdf/document",[49,189,154],{"class":121},[49,191,193,195,198],{"class":51,"line":192},9,[49,194,148],{"class":121},[49,196,197],{"class":55},"github.com/gpdf-dev/gpdf/pdf",[49,199,154],{"class":121},[49,201,203,205,208],{"class":51,"line":202},10,[49,204,148],{"class":121},[49,206,207],{"class":55},"github.com/gpdf-dev/gpdf/template",[49,209,154],{"class":121},[49,211,213],{"class":51,"line":212},11,[49,214,215],{"class":121},")\n",[49,217,219],{"class":51,"line":218},12,[49,220,132],{"emptyLinePlaceholder":131},[49,222,224,227,231,234],{"class":51,"line":223},13,[49,225,226],{"class":121},"func",[49,228,230],{"class":229},"s2Zo4"," main",[49,232,233],{"class":121},"()",[49,235,236],{"class":121}," {\n",[49,238,240,244,247,250,253,256,259,262,264,267,269,272,274,277],{"class":51,"line":239},14,[49,241,243],{"class":242},"sTEyZ","    doc ",[49,245,246],{"class":121},":=",[49,248,249],{"class":242}," gpdf",[49,251,252],{"class":121},".",[49,254,255],{"class":229},"NewDocument",[49,257,258],{"class":121},"(",[49,260,261],{"class":242},"template",[49,263,252],{"class":121},[49,265,266],{"class":229},"WithPageSize",[49,268,258],{"class":121},[49,270,271],{"class":242},"document",[49,273,252],{"class":121},[49,275,276],{"class":242},"A4",[49,278,279],{"class":121},"))\n",[49,281,283,286,288,291,293,296],{"class":51,"line":282},15,[49,284,285],{"class":242},"    page ",[49,287,246],{"class":121},[49,289,290],{"class":242}," doc",[49,292,252],{"class":121},[49,294,295],{"class":229},"AddPage",[49,297,298],{"class":121},"()\n",[49,300,302,305,307,310,313,317,320,322,324,327,330],{"class":51,"line":301},16,[49,303,304],{"class":242},"    page",[49,306,252],{"class":121},[49,308,309],{"class":229},"AutoRow",[49,311,312],{"class":121},"(func(",[49,314,316],{"class":315},"sHdIc","r",[49,318,319],{"class":121}," *",[49,321,261],{"class":55},[49,323,252],{"class":121},[49,325,326],{"class":55},"RowBuilder",[49,328,329],{"class":121},")",[49,331,236],{"class":121},[49,333,335,338,340,343,345,349,352,355,358,360,362,364,367,369],{"class":51,"line":334},17,[49,336,337],{"class":242},"        r",[49,339,252],{"class":121},[49,341,342],{"class":229},"Col",[49,344,258],{"class":121},[49,346,348],{"class":347},"sbssI","6",[49,350,351],{"class":121},",",[49,353,354],{"class":121}," func(",[49,356,357],{"class":315},"c",[49,359,319],{"class":121},[49,361,261],{"class":55},[49,363,252],{"class":121},[49,365,366],{"class":55},"ColBuilder",[49,368,329],{"class":121},[49,370,236],{"class":121},[49,372,374,377,379,382,384,387,390,392,394,397,399,402,404,407,410,412,414,417],{"class":51,"line":373},18,[49,375,376],{"class":242},"            c",[49,378,252],{"class":121},[49,380,381],{"class":229},"Text",[49,383,258],{"class":121},[49,385,386],{"class":121},"\"",[49,388,389],{"class":59},"ACME Ltda.",[49,391,386],{"class":121},[49,393,351],{"class":121},[49,395,396],{"class":242}," template",[49,398,252],{"class":121},[49,400,401],{"class":229},"FontSize",[49,403,258],{"class":121},[49,405,406],{"class":347},"22",[49,408,409],{"class":121},"),",[49,411,396],{"class":242},[49,413,252],{"class":121},[49,415,416],{"class":229},"Bold",[49,418,419],{"class":121},"())\n",[49,421,423,425,427,429,431,433,436,438],{"class":51,"line":422},19,[49,424,376],{"class":242},[49,426,252],{"class":121},[49,428,381],{"class":229},[49,430,258],{"class":121},[49,432,386],{"class":121},[49,434,435],{"class":59},"Av. Paulista 1000, São Paulo 01310",[49,437,386],{"class":121},[49,439,215],{"class":121},[49,441,443],{"class":51,"line":442},20,[49,444,445],{"class":121},"        })\n",[49,447,449,451,453,455,457,459,461,463,465,467,469,471,473,475],{"class":51,"line":448},21,[49,450,337],{"class":242},[49,452,252],{"class":121},[49,454,342],{"class":229},[49,456,258],{"class":121},[49,458,348],{"class":347},[49,460,351],{"class":121},[49,462,354],{"class":121},[49,464,357],{"class":315},[49,466,319],{"class":121},[49,468,261],{"class":55},[49,470,252],{"class":121},[49,472,366],{"class":55},[49,474,329],{"class":121},[49,476,236],{"class":121},[49,478,480,482,484,486,488,490,493,495,497,499,501,503,506,508,510,513],{"class":51,"line":479},22,[49,481,376],{"class":242},[49,483,252],{"class":121},[49,485,381],{"class":229},[49,487,258],{"class":121},[49,489,386],{"class":121},[49,491,492],{"class":59},"FATURA #INV-2026-001",[49,494,386],{"class":121},[49,496,351],{"class":121},[49,498,396],{"class":242},[49,500,252],{"class":121},[49,502,416],{"class":229},[49,504,505],{"class":121},"(),",[49,507,396],{"class":242},[49,509,252],{"class":121},[49,511,512],{"class":229},"AlignRight",[49,514,419],{"class":121},[49,516,518,520,522,524,526,528,531,533,535,537,539,541],{"class":51,"line":517},23,[49,519,376],{"class":242},[49,521,252],{"class":121},[49,523,381],{"class":229},[49,525,258],{"class":121},[49,527,386],{"class":121},[49,529,530],{"class":59},"Vencimento: 2026-03-31",[49,532,386],{"class":121},[49,534,351],{"class":121},[49,536,396],{"class":242},[49,538,252],{"class":121},[49,540,512],{"class":229},[49,542,419],{"class":121},[49,544,546],{"class":51,"line":545},24,[49,547,445],{"class":121},[49,549,551],{"class":51,"line":550},25,[49,552,553],{"class":121},"    })\n",[49,555,557,559,561,563,565,567,569,571,573,575,577],{"class":51,"line":556},26,[49,558,304],{"class":242},[49,560,252],{"class":121},[49,562,309],{"class":229},[49,564,312],{"class":121},[49,566,316],{"class":315},[49,568,319],{"class":121},[49,570,261],{"class":55},[49,572,252],{"class":121},[49,574,326],{"class":55},[49,576,329],{"class":121},[49,578,236],{"class":121},[49,580,582,584,586,588,590,593,595,597,599,601,603,605,607,609],{"class":51,"line":581},27,[49,583,337],{"class":242},[49,585,252],{"class":121},[49,587,342],{"class":229},[49,589,258],{"class":121},[49,591,592],{"class":347},"12",[49,594,351],{"class":121},[49,596,354],{"class":121},[49,598,357],{"class":315},[49,600,319],{"class":121},[49,602,261],{"class":55},[49,604,252],{"class":121},[49,606,366],{"class":55},[49,608,329],{"class":121},[49,610,236],{"class":121},[49,612,614,616,618,621,623,625,627,630,632,634],{"class":51,"line":613},28,[49,615,376],{"class":242},[49,617,252],{"class":121},[49,619,620],{"class":229},"Spacer",[49,622,258],{"class":121},[49,624,271],{"class":242},[49,626,252],{"class":121},[49,628,629],{"class":229},"Mm",[49,631,258],{"class":121},[49,633,348],{"class":347},[49,635,279],{"class":121},[49,637,639,641,643,646],{"class":51,"line":638},29,[49,640,376],{"class":242},[49,642,252],{"class":121},[49,644,645],{"class":229},"Table",[49,647,648],{"class":121},"(\n",[49,650,652,655,659,662,664,667,669,671,674,677,679,681,683,686,688,690,692,695,697],{"class":51,"line":651},30,[49,653,654],{"class":121},"                []",[49,656,658],{"class":657},"spNyl","string",[49,660,661],{"class":121},"{",[49,663,386],{"class":121},[49,665,666],{"class":59},"Descrição",[49,668,386],{"class":121},[49,670,351],{"class":121},[49,672,673],{"class":121}," \"",[49,675,676],{"class":59},"Qtd.",[49,678,386],{"class":121},[49,680,351],{"class":121},[49,682,673],{"class":121},[49,684,685],{"class":59},"Valor unit.",[49,687,386],{"class":121},[49,689,351],{"class":121},[49,691,673],{"class":121},[49,693,694],{"class":59},"Valor",[49,696,386],{"class":121},[49,698,699],{"class":121},"},\n",[49,701,703,706,708],{"class":51,"line":702},31,[49,704,705],{"class":121},"                [][]",[49,707,658],{"class":657},[49,709,710],{"class":121},"{\n",[49,712,714,717,719,722,724,726,728,731,733,735,737,740,742,744,746,749,751],{"class":51,"line":713},32,[49,715,716],{"class":121},"                    {",[49,718,386],{"class":121},[49,720,721],{"class":59},"Desenvolvimento frontend",[49,723,386],{"class":121},[49,725,351],{"class":121},[49,727,673],{"class":121},[49,729,730],{"class":59},"40 h",[49,732,386],{"class":121},[49,734,351],{"class":121},[49,736,673],{"class":121},[49,738,739],{"class":59},"R$ 750,00",[49,741,386],{"class":121},[49,743,351],{"class":121},[49,745,673],{"class":121},[49,747,748],{"class":59},"R$ 30.000,00",[49,750,386],{"class":121},[49,752,699],{"class":121},[49,754,756,758,760,763,765,767,769,772,774,776,778,780,782,784,786,789,791],{"class":51,"line":755},33,[49,757,716],{"class":121},[49,759,386],{"class":121},[49,761,762],{"class":59},"Desenvolvimento backend",[49,764,386],{"class":121},[49,766,351],{"class":121},[49,768,673],{"class":121},[49,770,771],{"class":59},"60 h",[49,773,386],{"class":121},[49,775,351],{"class":121},[49,777,673],{"class":121},[49,779,739],{"class":59},[49,781,386],{"class":121},[49,783,351],{"class":121},[49,785,673],{"class":121},[49,787,788],{"class":59},"R$ 45.000,00",[49,790,386],{"class":121},[49,792,699],{"class":121},[49,794,796,798,800,803,805,807,809,812,814,816,818,821,823,825,827,830,832],{"class":51,"line":795},34,[49,797,716],{"class":121},[49,799,386],{"class":121},[49,801,802],{"class":59},"Design UI/UX",[49,804,386],{"class":121},[49,806,351],{"class":121},[49,808,673],{"class":121},[49,810,811],{"class":59},"20 h",[49,813,386],{"class":121},[49,815,351],{"class":121},[49,817,673],{"class":121},[49,819,820],{"class":59},"R$ 600,00",[49,822,386],{"class":121},[49,824,351],{"class":121},[49,826,673],{"class":121},[49,828,829],{"class":59},"R$ 12.000,00",[49,831,386],{"class":121},[49,833,699],{"class":121},[49,835,837],{"class":51,"line":836},35,[49,838,839],{"class":121},"                },\n",[49,841,843,846,848,851,853,856,858,861,863,866,868,871],{"class":51,"line":842},36,[49,844,845],{"class":242},"                template",[49,847,252],{"class":121},[49,849,850],{"class":229},"ColumnWidths",[49,852,258],{"class":121},[49,854,855],{"class":347},"40",[49,857,351],{"class":121},[49,859,860],{"class":347}," 15",[49,862,351],{"class":121},[49,864,865],{"class":347}," 20",[49,867,351],{"class":121},[49,869,870],{"class":347}," 25",[49,872,873],{"class":121},"),\n",[49,875,877,879,881,884,886,888,890,892,894,896,898,901,903,906,908,911,913,916],{"class":51,"line":876},37,[49,878,845],{"class":242},[49,880,252],{"class":121},[49,882,883],{"class":229},"TableHeaderStyle",[49,885,258],{"class":121},[49,887,261],{"class":242},[49,889,252],{"class":121},[49,891,416],{"class":229},[49,893,505],{"class":121},[49,895,396],{"class":242},[49,897,252],{"class":121},[49,899,900],{"class":229},"BgColor",[49,902,258],{"class":121},[49,904,905],{"class":242},"pdf",[49,907,252],{"class":121},[49,909,910],{"class":229},"RGBHex",[49,912,258],{"class":121},[49,914,915],{"class":347},"0xF0F0F0",[49,917,918],{"class":121},"))),\n",[49,920,922,924,926,929,931,933,935,937,939,942],{"class":51,"line":921},38,[49,923,845],{"class":242},[49,925,252],{"class":121},[49,927,928],{"class":229},"TableStripe",[49,930,258],{"class":121},[49,932,905],{"class":242},[49,934,252],{"class":121},[49,936,910],{"class":229},[49,938,258],{"class":121},[49,940,941],{"class":347},"0xFAFAFA",[49,943,944],{"class":121},")),\n",[49,946,948],{"class":51,"line":947},39,[49,949,950],{"class":121},"            )\n",[49,952,954,956,958,960,962,964,967,969,971,973,975,977,979,981,983,985,987,989,991,993,995,998],{"class":51,"line":953},40,[49,955,376],{"class":242},[49,957,252],{"class":121},[49,959,381],{"class":229},[49,961,258],{"class":121},[49,963,386],{"class":121},[49,965,966],{"class":59},"Total: R$ 87.000,00",[49,968,386],{"class":121},[49,970,351],{"class":121},[49,972,396],{"class":242},[49,974,252],{"class":121},[49,976,512],{"class":229},[49,978,505],{"class":121},[49,980,396],{"class":242},[49,982,252],{"class":121},[49,984,416],{"class":229},[49,986,505],{"class":121},[49,988,396],{"class":242},[49,990,252],{"class":121},[49,992,401],{"class":229},[49,994,258],{"class":121},[49,996,997],{"class":347},"14",[49,999,279],{"class":121},[49,1001,1003],{"class":51,"line":1002},41,[49,1004,445],{"class":121},[49,1006,1008],{"class":51,"line":1007},42,[49,1009,553],{"class":121},[49,1011,1013,1016,1018,1021,1023,1025,1027,1030],{"class":51,"line":1012},43,[49,1014,1015],{"class":242},"    b",[49,1017,351],{"class":121},[49,1019,1020],{"class":242}," err ",[49,1022,246],{"class":121},[49,1024,290],{"class":242},[49,1026,252],{"class":121},[49,1028,1029],{"class":229},"Generate",[49,1031,298],{"class":121},[49,1033,1035,1038,1040,1043,1046],{"class":51,"line":1034},44,[49,1036,1037],{"class":138},"    if",[49,1039,1020],{"class":242},[49,1041,1042],{"class":121},"!=",[49,1044,1045],{"class":121}," nil",[49,1047,236],{"class":121},[49,1049,1051,1054,1056,1059,1061,1064],{"class":51,"line":1050},45,[49,1052,1053],{"class":242},"        log",[49,1055,252],{"class":121},[49,1057,1058],{"class":229},"Fatal",[49,1060,258],{"class":121},[49,1062,1063],{"class":242},"err",[49,1065,215],{"class":121},[49,1067,1069],{"class":51,"line":1068},46,[49,1070,1071],{"class":121},"    }\n",[49,1073,1075,1077,1079,1081,1084,1086,1089,1091,1093,1096,1098,1100,1103,1105,1108,1111,1113,1115,1117],{"class":51,"line":1074},47,[49,1076,1037],{"class":138},[49,1078,1020],{"class":242},[49,1080,246],{"class":121},[49,1082,1083],{"class":242}," os",[49,1085,252],{"class":121},[49,1087,1088],{"class":229},"WriteFile",[49,1090,258],{"class":121},[49,1092,386],{"class":121},[49,1094,1095],{"class":59},"invoice.pdf",[49,1097,386],{"class":121},[49,1099,351],{"class":121},[49,1101,1102],{"class":242}," b",[49,1104,351],{"class":121},[49,1106,1107],{"class":347}," 0644",[49,1109,1110],{"class":121},");",[49,1112,1020],{"class":242},[49,1114,1042],{"class":121},[49,1116,1045],{"class":121},[49,1118,236],{"class":121},[49,1120,1122,1124,1126,1128,1130,1132],{"class":51,"line":1121},48,[49,1123,1053],{"class":242},[49,1125,252],{"class":121},[49,1127,1058],{"class":229},[49,1129,258],{"class":121},[49,1131,1063],{"class":242},[49,1133,215],{"class":121},[49,1135,1137],{"class":51,"line":1136},49,[49,1138,1071],{"class":121},[49,1140,1142],{"class":51,"line":1141},50,[49,1143,1144],{"class":121},"}\n",[19,1146,1147,1150,1151,1153],{},[28,1148,1149],{},"go run ."," produz ",[28,1152,1095],{}," no diretório atual. Em um M1 o programa inteiro termina em alguns milissegundos — a geração do PDF em si está abaixo de 150 µs; o resto é inicialização de processo.",[14,1155,1157],{"id":1156},"o-que-cada-bloco-faz","O que cada bloco faz",[1159,1160,1162],"h3",{"id":1161},"imports","Imports",[19,1164,1165],{},"Quatro pacotes do gpdf:",[81,1167,1168,1180,1213,1228],{},[84,1169,1170,1172,1173,1176,1177,252],{},[28,1171,177],{}," — a fachada. Usamos apenas ",[28,1174,1175],{},"gpdf.NewDocument",", que é um wrapper fino sobre ",[28,1178,1179],{},"template.New",[84,1181,1182,1184,1185,1187,1188,1187,1191,1187,1194,1187,1197,1187,1200,1203,1204,1187,1206,1187,1209,1212],{},[28,1183,187],{}," — unidades (",[28,1186,629],{},", ",[28,1189,1190],{},"Pt",[28,1192,1193],{},"Cm",[28,1195,1196],{},"In",[28,1198,1199],{},"Em",[28,1201,1202],{},"Pct","), tamanhos de página (",[28,1205,276],{},[28,1207,1208],{},"Letter",[28,1210,1211],{},"Legal","), margens.",[84,1214,1215,1217,1218,1187,1220,1223,1224,1227],{},[28,1216,197],{}," — primitivas de cor (",[28,1219,910],{},[28,1221,1222],{},"Gray",", constantes como ",[28,1225,1226],{},"pdf.White",").",[84,1229,1230,1232],{},[28,1231,207],{}," — o Builder API.",[19,1234,1235,1236,1239,1240,1243,1244,1247],{},"Zero dependências externas. Após ",[28,1237,1238],{},"go get github.com/gpdf-dev/gpdf",", o ",[28,1241,1242],{},"require"," do ",[28,1245,1246],{},"go.mod"," tem uma linha.",[1159,1249,1251],{"id":1250},"construção-do-documento","Construção do documento",[40,1253,1255],{"className":113,"code":1254,"language":56,"meta":45,"style":45},"doc := gpdf.NewDocument(template.WithPageSize(document.A4))\n",[28,1256,1257],{"__ignoreMap":45},[49,1258,1259,1262,1264,1266,1268,1270,1272,1274,1276,1278,1280,1282,1284,1286],{"class":51,"line":52},[49,1260,1261],{"class":242},"doc ",[49,1263,246],{"class":121},[49,1265,249],{"class":242},[49,1267,252],{"class":121},[49,1269,255],{"class":229},[49,1271,258],{"class":121},[49,1273,261],{"class":242},[49,1275,252],{"class":121},[49,1277,266],{"class":229},[49,1279,258],{"class":121},[49,1281,271],{"class":242},[49,1283,252],{"class":121},[49,1285,276],{"class":242},[49,1287,279],{"class":121},[19,1289,1290,1292,1293,1296,1297,1300],{},[28,1291,1175],{}," aceita ",[28,1294,1295],{},"...template.Option",". Tamanho de página, margens, fonte padrão, metadados, fontes custom: tudo é opção ",[28,1298,1299],{},"WithXxx",". Margem padrão 20 mm.",[1159,1302,1304],{"id":1303},"a-linha-do-cabeçalho","A linha do cabeçalho",[40,1306,1308],{"className":113,"code":1307,"language":56,"meta":45,"style":45},"page.AutoRow(func(r *template.RowBuilder) {\n    r.Col(6, func(c *template.ColBuilder) { ... })\n    r.Col(6, func(c *template.ColBuilder) { ... })\n})\n",[28,1309,1310,1335,1373,1407],{"__ignoreMap":45},[49,1311,1312,1315,1317,1319,1321,1323,1325,1327,1329,1331,1333],{"class":51,"line":52},[49,1313,1314],{"class":242},"page",[49,1316,252],{"class":121},[49,1318,309],{"class":229},[49,1320,312],{"class":121},[49,1322,316],{"class":315},[49,1324,319],{"class":121},[49,1326,261],{"class":55},[49,1328,252],{"class":121},[49,1330,326],{"class":55},[49,1332,329],{"class":121},[49,1334,236],{"class":121},[49,1336,1337,1340,1342,1344,1346,1348,1350,1352,1354,1356,1358,1360,1362,1364,1367,1370],{"class":51,"line":128},[49,1338,1339],{"class":242},"    r",[49,1341,252],{"class":121},[49,1343,342],{"class":229},[49,1345,258],{"class":121},[49,1347,348],{"class":347},[49,1349,351],{"class":121},[49,1351,354],{"class":121},[49,1353,357],{"class":315},[49,1355,319],{"class":121},[49,1357,261],{"class":55},[49,1359,252],{"class":121},[49,1361,366],{"class":55},[49,1363,329],{"class":121},[49,1365,1366],{"class":121}," {",[49,1368,1369],{"class":121}," ...",[49,1371,1372],{"class":121}," })\n",[49,1374,1375,1377,1379,1381,1383,1385,1387,1389,1391,1393,1395,1397,1399,1401,1403,1405],{"class":51,"line":135},[49,1376,1339],{"class":242},[49,1378,252],{"class":121},[49,1380,342],{"class":229},[49,1382,258],{"class":121},[49,1384,348],{"class":347},[49,1386,351],{"class":121},[49,1388,354],{"class":121},[49,1390,357],{"class":315},[49,1392,319],{"class":121},[49,1394,261],{"class":55},[49,1396,252],{"class":121},[49,1398,366],{"class":55},[49,1400,329],{"class":121},[49,1402,1366],{"class":121},[49,1404,1369],{"class":121},[49,1406,1372],{"class":121},[49,1408,1409],{"class":51,"line":145},[49,1410,1411],{"class":121},"})\n",[19,1413,1414,1415,1418,1419,1422,1423,1426],{},"O gpdf usa uma ",[23,1416,1417],{},"grade de 12 colunas",", mesmo modelo mental do Bootstrap. Uma linha tem 12 unidades horizontais; ",[28,1420,1421],{},"r.Col(6, ...)"," ocupa metade; dois ",[28,1424,1425],{},"Col(6)"," preenchem a linha.",[19,1428,1429,1431,1432,1435],{},[28,1430,309],{}," significa que a altura da linha é a do conteúdo mais alto. Dentro de cada coluna você empilha ",[28,1433,1434],{},"c.Text(...)"," de cima para baixo. Sem posicionamento explícito — o builder controla um cursor internamente.",[19,1437,1438,1439,1442,1443,1446],{},"A coluna direita usa ",[28,1440,1441],{},"template.AlignRight()",". Opções de texto são componíveis: ",[28,1444,1445],{},"c.Text(\"FATURA\", template.Bold(), template.AlignRight(), template.FontSize(20))"," empilha três modificadores em uma única chamada. A ordem não importa.",[1159,1448,1450],{"id":1449},"a-tabela-de-itens","A tabela de itens",[40,1452,1454],{"className":113,"code":1453,"language":56,"meta":45,"style":45},"c.Table(\n    []string{\"Descrição\", \"Qtd.\", \"Valor unit.\", \"Valor\"},\n    [][]string{ /* linhas */ },\n    template.ColumnWidths(40, 15, 20, 25),\n    template.TableHeaderStyle(template.Bold(), template.BgColor(pdf.RGBHex(0xF0F0F0))),\n    template.TableStripe(pdf.RGBHex(0xFAFAFA)),\n)\n",[28,1455,1456,1466,1507,1523,1550,1588,1610],{"__ignoreMap":45},[49,1457,1458,1460,1462,1464],{"class":51,"line":52},[49,1459,357],{"class":242},[49,1461,252],{"class":121},[49,1463,645],{"class":229},[49,1465,648],{"class":121},[49,1467,1468,1471,1473,1475,1477,1479,1481,1483,1485,1487,1489,1491,1493,1495,1497,1499,1501,1503,1505],{"class":51,"line":128},[49,1469,1470],{"class":121},"    []",[49,1472,658],{"class":657},[49,1474,661],{"class":121},[49,1476,386],{"class":121},[49,1478,666],{"class":59},[49,1480,386],{"class":121},[49,1482,351],{"class":121},[49,1484,673],{"class":121},[49,1486,676],{"class":59},[49,1488,386],{"class":121},[49,1490,351],{"class":121},[49,1492,673],{"class":121},[49,1494,685],{"class":59},[49,1496,386],{"class":121},[49,1498,351],{"class":121},[49,1500,673],{"class":121},[49,1502,694],{"class":59},[49,1504,386],{"class":121},[49,1506,699],{"class":121},[49,1508,1509,1512,1514,1516,1520],{"class":51,"line":135},[49,1510,1511],{"class":121},"    [][]",[49,1513,658],{"class":657},[49,1515,661],{"class":121},[49,1517,1519],{"class":1518},"sHwdD"," /* linhas */",[49,1521,1522],{"class":121}," },\n",[49,1524,1525,1528,1530,1532,1534,1536,1538,1540,1542,1544,1546,1548],{"class":51,"line":145},[49,1526,1527],{"class":242},"    template",[49,1529,252],{"class":121},[49,1531,850],{"class":229},[49,1533,258],{"class":121},[49,1535,855],{"class":347},[49,1537,351],{"class":121},[49,1539,860],{"class":347},[49,1541,351],{"class":121},[49,1543,865],{"class":347},[49,1545,351],{"class":121},[49,1547,870],{"class":347},[49,1549,873],{"class":121},[49,1551,1552,1554,1556,1558,1560,1562,1564,1566,1568,1570,1572,1574,1576,1578,1580,1582,1584,1586],{"class":51,"line":157},[49,1553,1527],{"class":242},[49,1555,252],{"class":121},[49,1557,883],{"class":229},[49,1559,258],{"class":121},[49,1561,261],{"class":242},[49,1563,252],{"class":121},[49,1565,416],{"class":229},[49,1567,505],{"class":121},[49,1569,396],{"class":242},[49,1571,252],{"class":121},[49,1573,900],{"class":229},[49,1575,258],{"class":121},[49,1577,905],{"class":242},[49,1579,252],{"class":121},[49,1581,910],{"class":229},[49,1583,258],{"class":121},[49,1585,915],{"class":347},[49,1587,918],{"class":121},[49,1589,1590,1592,1594,1596,1598,1600,1602,1604,1606,1608],{"class":51,"line":167},[49,1591,1527],{"class":242},[49,1593,252],{"class":121},[49,1595,928],{"class":229},[49,1597,258],{"class":121},[49,1599,905],{"class":242},[49,1601,252],{"class":121},[49,1603,910],{"class":229},[49,1605,258],{"class":121},[49,1607,941],{"class":347},[49,1609,944],{"class":121},[49,1611,1612],{"class":51,"line":172},[49,1613,215],{"class":121},[19,1615,1616,1618,1619,1622],{},[28,1617,850],{}," são ",[23,1620,1621],{},"porcentagens"," da coluna pai, não pontos absolutos. Os quatro valores devem somar 100. Se não somar, não há erro mas a última coluna transborda — a única pegadinha.",[19,1624,1625,1627,1628,1631],{},[28,1626,883],{}," aceita as mesmas opções de texto usadas em outros lugares. ",[28,1629,1630],{},"TableStripe(color)"," alterna o fundo das linhas. A tabela mede cada célula, escolhe a altura pela mais alta e, se passar da página, o gpdf quebra e redesenha o cabeçalho na continuação.",[1159,1633,1635],{"id":1634},"o-total","O total",[40,1637,1639],{"className":113,"code":1638,"language":56,"meta":45,"style":45},"c.Text(\"Total: R$ 87.000,00\", template.AlignRight(), template.Bold(), template.FontSize(14))\n",[28,1640,1641],{"__ignoreMap":45},[49,1642,1643,1645,1647,1649,1651,1653,1655,1657,1659,1661,1663,1665,1667,1669,1671,1673,1675,1677,1679,1681,1683,1685],{"class":51,"line":52},[49,1644,357],{"class":242},[49,1646,252],{"class":121},[49,1648,381],{"class":229},[49,1650,258],{"class":121},[49,1652,386],{"class":121},[49,1654,966],{"class":59},[49,1656,386],{"class":121},[49,1658,351],{"class":121},[49,1660,396],{"class":242},[49,1662,252],{"class":121},[49,1664,512],{"class":229},[49,1666,505],{"class":121},[49,1668,396],{"class":242},[49,1670,252],{"class":121},[49,1672,416],{"class":229},[49,1674,505],{"class":121},[49,1676,396],{"class":242},[49,1678,252],{"class":121},[49,1680,401],{"class":229},[49,1682,258],{"class":121},[49,1684,997],{"class":347},[49,1686,279],{"class":121},[19,1688,1689,1690,1692,1693,1696],{},"Outro ",[28,1691,381],{}," fora da tabela, alinhado à direita, um pouco maior. Se quiser mais respiro, adicione ",[28,1694,1695],{},"c.Spacer(document.Mm(3))"," antes.",[1159,1698,1700],{"id":1699},"gerar-e-escrever","Gerar e escrever",[40,1702,1704],{"className":113,"code":1703,"language":56,"meta":45,"style":45},"b, err := doc.Generate()\nif err != nil { log.Fatal(err) }\nif err := os.WriteFile(\"invoice.pdf\", b, 0644); err != nil { log.Fatal(err) }\n",[28,1705,1706,1725,1754],{"__ignoreMap":45},[49,1707,1708,1711,1713,1715,1717,1719,1721,1723],{"class":51,"line":52},[49,1709,1710],{"class":242},"b",[49,1712,351],{"class":121},[49,1714,1020],{"class":242},[49,1716,246],{"class":121},[49,1718,290],{"class":242},[49,1720,252],{"class":121},[49,1722,1029],{"class":229},[49,1724,298],{"class":121},[49,1726,1727,1730,1732,1734,1736,1738,1741,1743,1745,1747,1749,1751],{"class":51,"line":128},[49,1728,1729],{"class":138},"if",[49,1731,1020],{"class":242},[49,1733,1042],{"class":121},[49,1735,1045],{"class":121},[49,1737,1366],{"class":121},[49,1739,1740],{"class":242}," log",[49,1742,252],{"class":121},[49,1744,1058],{"class":229},[49,1746,258],{"class":121},[49,1748,1063],{"class":242},[49,1750,329],{"class":121},[49,1752,1753],{"class":121}," }\n",[49,1755,1756,1758,1760,1762,1764,1766,1768,1770,1772,1774,1776,1778,1780,1782,1784,1786,1788,1790,1792,1794,1796,1798,1800,1802,1804,1806],{"class":51,"line":135},[49,1757,1729],{"class":138},[49,1759,1020],{"class":242},[49,1761,246],{"class":121},[49,1763,1083],{"class":242},[49,1765,252],{"class":121},[49,1767,1088],{"class":229},[49,1769,258],{"class":121},[49,1771,386],{"class":121},[49,1773,1095],{"class":59},[49,1775,386],{"class":121},[49,1777,351],{"class":121},[49,1779,1102],{"class":242},[49,1781,351],{"class":121},[49,1783,1107],{"class":347},[49,1785,1110],{"class":121},[49,1787,1020],{"class":242},[49,1789,1042],{"class":121},[49,1791,1045],{"class":121},[49,1793,1366],{"class":121},[49,1795,1740],{"class":242},[49,1797,252],{"class":121},[49,1799,1058],{"class":229},[49,1801,258],{"class":121},[49,1803,1063],{"class":242},[49,1805,329],{"class":121},[49,1807,1753],{"class":121},[19,1809,1810,1813,1814,1817,1818,1821,1822,252],{},[28,1811,1812],{},"doc.Generate()"," devolve ",[28,1815,1816],{},"([]byte, error)",". Não toca o sistema de arquivos. O slice é um PDF completo — grave no disco, envie para S3, devolva como resposta HTTP com ",[28,1819,1820],{},"w.Write(b)",", anexe em e-mail. Se preferir streaming, use ",[28,1823,1824],{},"doc.Render(w io.Writer)",[14,1826,1828],{"id":1827},"deixando-mais-bonita-sem-passar-de-50-linhas","Deixando mais bonita sem passar de 50 linhas",[19,1830,1831,1834,1835,1838],{},[23,1832,1833],{},"Cor da marca."," Escolha um hex (por exemplo, azul-marinho ",[28,1836,1837],{},"0x1A237E",") e aplique no nome da empresa e no cabeçalho da tabela:",[40,1840,1842],{"className":113,"code":1841,"language":56,"meta":45,"style":45},"brand := pdf.RGBHex(0x1A237E)\nc.Text(\"ACME Ltda.\", template.FontSize(22), template.Bold(), template.TextColor(brand))\ntemplate.TableHeaderStyle(template.Bold(), template.TextColor(pdf.White), template.BgColor(brand)),\n",[28,1843,1844,1864,1916],{"__ignoreMap":45},[49,1845,1846,1849,1851,1854,1856,1858,1860,1862],{"class":51,"line":52},[49,1847,1848],{"class":242},"brand ",[49,1850,246],{"class":121},[49,1852,1853],{"class":242}," pdf",[49,1855,252],{"class":121},[49,1857,910],{"class":229},[49,1859,258],{"class":121},[49,1861,1837],{"class":347},[49,1863,215],{"class":121},[49,1865,1866,1868,1870,1872,1874,1876,1878,1880,1882,1884,1886,1888,1890,1892,1894,1896,1898,1900,1902,1904,1906,1909,1911,1914],{"class":51,"line":128},[49,1867,357],{"class":242},[49,1869,252],{"class":121},[49,1871,381],{"class":229},[49,1873,258],{"class":121},[49,1875,386],{"class":121},[49,1877,389],{"class":59},[49,1879,386],{"class":121},[49,1881,351],{"class":121},[49,1883,396],{"class":242},[49,1885,252],{"class":121},[49,1887,401],{"class":229},[49,1889,258],{"class":121},[49,1891,406],{"class":347},[49,1893,409],{"class":121},[49,1895,396],{"class":242},[49,1897,252],{"class":121},[49,1899,416],{"class":229},[49,1901,505],{"class":121},[49,1903,396],{"class":242},[49,1905,252],{"class":121},[49,1907,1908],{"class":229},"TextColor",[49,1910,258],{"class":121},[49,1912,1913],{"class":242},"brand",[49,1915,279],{"class":121},[49,1917,1918,1920,1922,1924,1926,1928,1930,1932,1934,1936,1938,1940,1942,1944,1946,1949,1951,1953,1955,1957,1959,1961],{"class":51,"line":135},[49,1919,261],{"class":242},[49,1921,252],{"class":121},[49,1923,883],{"class":229},[49,1925,258],{"class":121},[49,1927,261],{"class":242},[49,1929,252],{"class":121},[49,1931,416],{"class":229},[49,1933,505],{"class":121},[49,1935,396],{"class":242},[49,1937,252],{"class":121},[49,1939,1908],{"class":229},[49,1941,258],{"class":121},[49,1943,905],{"class":242},[49,1945,252],{"class":121},[49,1947,1948],{"class":242},"White",[49,1950,409],{"class":121},[49,1952,396],{"class":242},[49,1954,252],{"class":121},[49,1956,900],{"class":229},[49,1958,258],{"class":121},[49,1960,1913],{"class":242},[49,1962,944],{"class":121},[19,1964,1965,1968,1969,1972],{},[23,1966,1967],{},"Subtotal e impostos."," Acima do total, três ",[28,1970,1971],{},"c.Text"," empilhados:",[40,1974,1976],{"className":113,"code":1975,"language":56,"meta":45,"style":45},"c.Text(\"Subtotal: R$ 87.000,00\", template.AlignRight())\nc.Text(\"ISS (5%): R$ 4.350,00\", template.AlignRight())\nc.Text(\"Total: R$ 91.350,00\", template.AlignRight(), template.Bold(), template.FontSize(14))\n",[28,1977,1978,2005,2032],{"__ignoreMap":45},[49,1979,1980,1982,1984,1986,1988,1990,1993,1995,1997,1999,2001,2003],{"class":51,"line":52},[49,1981,357],{"class":242},[49,1983,252],{"class":121},[49,1985,381],{"class":229},[49,1987,258],{"class":121},[49,1989,386],{"class":121},[49,1991,1992],{"class":59},"Subtotal: R$ 87.000,00",[49,1994,386],{"class":121},[49,1996,351],{"class":121},[49,1998,396],{"class":242},[49,2000,252],{"class":121},[49,2002,512],{"class":229},[49,2004,419],{"class":121},[49,2006,2007,2009,2011,2013,2015,2017,2020,2022,2024,2026,2028,2030],{"class":51,"line":128},[49,2008,357],{"class":242},[49,2010,252],{"class":121},[49,2012,381],{"class":229},[49,2014,258],{"class":121},[49,2016,386],{"class":121},[49,2018,2019],{"class":59},"ISS (5%): R$ 4.350,00",[49,2021,386],{"class":121},[49,2023,351],{"class":121},[49,2025,396],{"class":242},[49,2027,252],{"class":121},[49,2029,512],{"class":229},[49,2031,419],{"class":121},[49,2033,2034,2036,2038,2040,2042,2044,2047,2049,2051,2053,2055,2057,2059,2061,2063,2065,2067,2069,2071,2073,2075,2077],{"class":51,"line":135},[49,2035,357],{"class":242},[49,2037,252],{"class":121},[49,2039,381],{"class":229},[49,2041,258],{"class":121},[49,2043,386],{"class":121},[49,2045,2046],{"class":59},"Total: R$ 91.350,00",[49,2048,386],{"class":121},[49,2050,351],{"class":121},[49,2052,396],{"class":242},[49,2054,252],{"class":121},[49,2056,512],{"class":229},[49,2058,505],{"class":121},[49,2060,396],{"class":242},[49,2062,252],{"class":121},[49,2064,416],{"class":229},[49,2066,505],{"class":121},[49,2068,396],{"class":242},[49,2070,252],{"class":121},[49,2072,401],{"class":229},[49,2074,258],{"class":121},[49,2076,997],{"class":347},[49,2078,279],{"class":121},[19,2080,2081,2084,2085,2087],{},[23,2082,2083],{},"Requisitos de NFe/DANFE (Brasil)."," Para uma Nota Fiscal eletrônica, os campos obrigatórios (CNPJ do emitente, natureza da operação, chave de acesso) são apenas ",[28,2086,1971],{}," adicionais. O layout não muda — a diferença está nos dados e na assinatura digital posterior, não na montagem do documento.",[19,2089,2090,2093],{},[23,2091,2092],{},"Uma linha sobre o total."," Entre o subtotal e o total:",[40,2095,2097],{"className":113,"code":2096,"language":56,"meta":45,"style":45},"c.Spacer(document.Mm(2))\nc.Line(template.LineThickness(document.Pt(0.5)))\nc.Spacer(document.Mm(2))\n",[28,2098,2099,2122,2156],{"__ignoreMap":45},[49,2100,2101,2103,2105,2107,2109,2111,2113,2115,2117,2120],{"class":51,"line":52},[49,2102,357],{"class":242},[49,2104,252],{"class":121},[49,2106,620],{"class":229},[49,2108,258],{"class":121},[49,2110,271],{"class":242},[49,2112,252],{"class":121},[49,2114,629],{"class":229},[49,2116,258],{"class":121},[49,2118,2119],{"class":347},"2",[49,2121,279],{"class":121},[49,2123,2124,2126,2128,2131,2133,2135,2137,2140,2142,2144,2146,2148,2150,2153],{"class":51,"line":128},[49,2125,357],{"class":242},[49,2127,252],{"class":121},[49,2129,2130],{"class":229},"Line",[49,2132,258],{"class":121},[49,2134,261],{"class":242},[49,2136,252],{"class":121},[49,2138,2139],{"class":229},"LineThickness",[49,2141,258],{"class":121},[49,2143,271],{"class":242},[49,2145,252],{"class":121},[49,2147,1190],{"class":229},[49,2149,258],{"class":121},[49,2151,2152],{"class":347},"0.5",[49,2154,2155],{"class":121},")))\n",[49,2157,2158,2160,2162,2164,2166,2168,2170,2172,2174,2176],{"class":51,"line":135},[49,2159,357],{"class":242},[49,2161,252],{"class":121},[49,2163,620],{"class":229},[49,2165,258],{"class":121},[49,2167,271],{"class":242},[49,2169,252],{"class":121},[49,2171,629],{"class":229},[49,2173,258],{"class":121},[49,2175,2119],{"class":347},[49,2177,279],{"class":121},[14,2179,2181],{"id":2180},"executando","Executando",[40,2183,2185],{"className":42,"code":2184,"language":44,"meta":45,"style":45},"mkdir invoice-demo\ncd invoice-demo\ngo mod init example.com/invoice-demo\ngo get github.com/gpdf-dev/gpdf\n# cole main.go\ngo run .\nopen invoice.pdf    # macOS; xdg-open no Linux, start no Windows\n",[28,2186,2187,2195,2202,2215,2223,2228,2238],{"__ignoreMap":45},[49,2188,2189,2192],{"class":51,"line":52},[49,2190,2191],{"class":55},"mkdir",[49,2193,2194],{"class":59}," invoice-demo\n",[49,2196,2197,2200],{"class":51,"line":128},[49,2198,2199],{"class":229},"cd",[49,2201,2194],{"class":59},[49,2203,2204,2206,2209,2212],{"class":51,"line":135},[49,2205,56],{"class":55},[49,2207,2208],{"class":59}," mod",[49,2210,2211],{"class":59}," init",[49,2213,2214],{"class":59}," example.com/invoice-demo\n",[49,2216,2217,2219,2221],{"class":51,"line":145},[49,2218,56],{"class":55},[49,2220,60],{"class":59},[49,2222,63],{"class":59},[49,2224,2225],{"class":51,"line":157},[49,2226,2227],{"class":1518},"# cole main.go\n",[49,2229,2230,2232,2235],{"class":51,"line":167},[49,2231,56],{"class":55},[49,2233,2234],{"class":59}," run",[49,2236,2237],{"class":59}," .\n",[49,2239,2240,2243,2246],{"class":51,"line":172},[49,2241,2242],{"class":55},"open",[49,2244,2245],{"class":59}," invoice.pdf",[49,2247,2248],{"class":1518},"    # macOS; xdg-open no Linux, start no Windows\n",[14,2250,2252],{"id":2251},"quando-esse-padrão-deixa-de-servir","Quando esse padrão deixa de servir",[81,2254,2255,2265,2274,2291],{},[84,2256,2257,2260,2261,2264],{},[23,2258,2259],{},"Os itens viram dados."," Quando vêm de uma query ou JSON, a tabela não muda — você só constrói ",[28,2262,2263],{},"[][]string"," a partir dos dados.",[84,2266,2267,2270,2271,252],{},[23,2268,2269],{},"Você quer reusar o layout."," Assim que começar a gerar faturas em loop, extraia o corpo para ",[28,2272,2273],{},"func renderInvoice(doc *template.Document, inv Invoice)",[84,2275,2276,2279,2280,2285,2286,2290],{},[23,2277,2278],{},"O layout ganha branches."," Com condicionais o Builder API fica verboso — o ",[2281,2282,2284],"a",{"href":2283},"/pt/docs/guide/json-templates","entrypoint JSON"," ou o ",[2281,2287,2289],{"href":2288},"/pt/docs/guide/go-templates","entrypoint Go templates"," se encaixa melhor.",[84,2292,2293,2296,2297,2300,2301,252],{},[23,2294,2295],{},"Você precisa de CJK."," Japonês, chinês, coreano aparecem como quadrados vazios com a fonte padrão. Registre um TTF com ",[28,2298,2299],{},"template.WithFont",". Veja ",[2281,2302,2304],{"href":2303},"/pt/blog/embed-japanese-font","Como embutir uma fonte japonesa no gpdf",[19,2306,2307],{},"Nenhum dos quatro é \"reescrever do zero\" — são extensões incrementais.",[14,2309,2311],{"id":2310},"faq","FAQ",[19,2313,2314,2317],{},[23,2315,2316],{},"Posso usar em faturas comerciais sem atribuição?","\nSim. O gpdf é MIT. Pode construir em cima o que quiser, inclusive produtos comerciais fechados. Atribuição não é obrigatória (uma star no GitHub é bem-vinda).",[19,2319,2320,2327,2328,2331,2332,2334,2335,252],{},[23,2321,2322,2323,2326],{},"Dá para escrever direto em ",[28,2324,2325],{},"io.Writer"," sem o slice?","\nSim — ",[28,2329,2330],{},"doc.Render(w io.Writer) error",". A versão com ",[28,2333,1812],{}," é uma comodidade para o caso comum de querer ",[28,2336,2337],{},"[]byte",[19,2339,2340,2343,2344,2347],{},[23,2341,2342],{},"Qual é a velocidade real?","\nAs 50 linhas acima geram o PDF em cerca de 100 µs num M1. Um hello world de uma página fica em ",[23,2345,2346],{},"13 µs",". Em cargas batch — geração de faturas noturna, relatórios em massa — o gpdf raramente é o gargalo.",[19,2349,2350,2353,2354,2357,2358,2361,2362,2365],{},[23,2351,2352],{},"Dá para gerar uma fatura PDF em Go sem o gpdf?","\nDá. ",[28,2355,2356],{},"jung-kurt/gofpdf"," funciona (arquivado mas estável), ",[28,2359,2360],{},"signintech/gopdf"," num nível mais baixo, e ",[28,2363,2364],{},"johnfercher/maroto"," com outra abstração de layout. Todos ficam mais verbosos que as 50 linhas acima para a mesma fatura.",[19,2367,2368,2375,2376,2379],{},[23,2369,2370,2371,2374],{},"Por que não existe um helper ",[28,2372,2373],{},"gpdf.Invoice","?","\nPorque \"fatura\" significa coisas diferentes em países diferentes e qualquer simplificação deixa alguém de fora. Preferimos te dar um ponto de partida de 50 linhas do que um ",[28,2377,2378],{},"NewInvoice(...)"," que quebra na primeira NFe brasileira ou 適格請求書 japonês.",[19,2381,2382,2385,2386,2389,2390,252],{},[23,2383,2384],{},"O PDF valida como PDF/A?","\nPor padrão sai PDF 1.7 normal. Para PDF/A-2b passe ",[28,2387,2388],{},"gpdf.WithPDFA(pdfa.Level2B)"," ao construir o documento. Ver ",[2281,2391,2393],{"href":2392},"/pt/docs/guide/pdf-a","Construindo PDF/A-2b em Go puro",[14,2395,2397],{"id":2396},"experimente-o-gpdf","Experimente o gpdf",[19,2399,2400],{},"O gpdf é uma biblioteca Go para gerar PDFs. MIT, zero dependências, CJK nativo, 10–30× mais rápida que alternativas nos workloads que medimos.",[40,2402,2403],{"className":42,"code":43,"language":44,"meta":45,"style":45},[28,2404,2405],{"__ignoreMap":45},[49,2406,2407,2409,2411],{"class":51,"line":52},[49,2408,56],{"class":55},[49,2410,60],{"class":59},[49,2412,63],{"class":59},[19,2414,2415,2421,2422],{},[2281,2416,2420],{"href":2417,"rel":2418},"https://github.com/gpdf-dev/gpdf",[2419],"nofollow","⭐ Star no GitHub"," · ",[2281,2423,2426],{"href":2424,"rel":2425},"https://gpdf.dev/pt/docs/quickstart",[2419],"Ler os docs",[14,2428,2430],{"id":2429},"próximas-leituras","Próximas leituras",[81,2432,2433,2440,2447],{},[84,2434,2435,2439],{},[2281,2436,2438],{"href":2437},"/pt/blog/why-gpdf-is-faster","Por que o gpdf é 10–30× mais rápido que outras libs Go de PDF"," — os números por trás do \"algumas centenas de microssegundos\".",[84,2441,2442,2446],{},[2281,2443,2445],{"href":2444},"/pt/blog/go-pdf-library-showdown-2026","Go PDF Library Showdown 2026"," — quantas linhas a mesma fatura ocupa em gofpdf, gopdf e Maroto.",[84,2448,2449,2453],{},[2281,2450,2452],{"href":2451},"/pt/blog/12-column-grid","Como a grade de 12 colunas do gpdf funciona"," — o modelo de layout usado no cabeçalho acima em mais detalhes.",[2455,2456,2457],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}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 .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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}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":45,"searchDepth":128,"depth":128,"links":2459},[2460,2461,2462,2463,2471,2472,2473,2474,2475,2476],{"id":16,"depth":128,"text":17},{"id":72,"depth":128,"text":73},{"id":109,"depth":128,"text":110},{"id":1156,"depth":128,"text":1157,"children":2464},[2465,2466,2467,2468,2469,2470],{"id":1161,"depth":135,"text":1162},{"id":1250,"depth":135,"text":1251},{"id":1303,"depth":135,"text":1304},{"id":1449,"depth":135,"text":1450},{"id":1634,"depth":135,"text":1635},{"id":1699,"depth":135,"text":1700},{"id":1827,"depth":128,"text":1828},{"id":2180,"depth":128,"text":2181},{"id":2251,"depth":128,"text":2252},{"id":2310,"depth":128,"text":2311},{"id":2396,"depth":128,"text":2397},{"id":2429,"depth":128,"text":2430},"2026-04-21","Código completo e executável para gerar uma fatura PDF em Go — 50 linhas com gpdf, zero dependências, sem Chromium, sem CGO. Inclui cabeçalho, tabela e total.",false,"md",{"name":2482,"totalTime":2483,"tools":2484,"steps":2486},"Gerar uma fatura PDF em Go com gpdf","PT10M",[2485],"Go 1.22+",[2487,2490,2493,2496,2499],{"name":2488,"text":2489},"Instale o gpdf","Rode go get github.com/gpdf-dev/gpdf no seu módulo. O gpdf não tem dependências transitivas; o go.sum fica com uma linha e o binário não recebe superfície CGO.",{"name":2491,"text":2492},"Construa o documento","Chame gpdf.NewDocument com template.WithPageSize(document.A4). Em seguida, doc.AddPage() devolve um PageBuilder no qual você empilha linhas.",{"name":2494,"text":2495},"Monte o cabeçalho com duas células de 6 colunas","Use page.AutoRow com r.Col(6, ...) duas vezes. Bloco da empresa à esquerda, rótulo INVOICE e número à direita com template.AlignRight().",{"name":2497,"text":2498},"Renderize a tabela de itens","Dentro de uma célula de 12 colunas, chame c.Table com um slice de cabeçalhos e um slice de linhas. Passe template.ColumnWidths e template.TableHeaderStyle para estilizar.",{"name":2500,"text":2501},"Gere e escreva os bytes","Chame doc.Generate() para obter []byte e depois os.WriteFile(\"invoice.pdf\", b, 0644). Um arquivo em disco, sem diretório temporário nem binário externo.",null,{},"/pt/blog/invoice-pdf-go-under-50-lines",{"title":5,"description":2478},"pt/blog/012.invoice-pdf-go-under-50-lines",[2508,2509],"tutorial","templates","Na_5oG8kJ8upsg6a_BA50tBp4P8bMYNGjXM1JpjYMBw",1779199037394]