[{"data":1,"prerenderedAt":1800},["ShallowReactive",2],{"blog-pt-gpdf-vs-wkhtmltopdf-vs-chromium":3},{"id":4,"title":5,"author":6,"body":10,"date":1786,"description":1787,"draft":1788,"extension":1789,"howTo":1790,"image":1790,"meta":1791,"navigation":330,"path":1792,"seo":1793,"stem":1794,"tags":1795,"updated":1790,"__hash__":1799},"blogPt/pt/blog/026.gpdf-vs-wkhtmltopdf-vs-chromium.md","gpdf vs wkhtmltopdf vs Chromium: geração de PDF em 2026",{"name":7,"url":8,"avatar":9},"Taiki Noda","https://nadai.dev/en/about","https://nadai.dev/og-default.png",{"type":11,"value":12,"toc":1772},"minimark",[13,18,31,34,37,41,163,172,175,178,181,184,188,191,194,214,217,223,229,232,236,239,245,251,269,290,293,296,300,303,960,978,985,989,992,1073,1085,1088,1091,1094,1097,1101,1104,1207,1218,1222,1225,1228,1239,1242,1246,1249,1254,1335,1346,1351,1401,1415,1420,1638,1644,1647,1651,1656,1664,1669,1672,1677,1680,1685,1696,1701,1707,1711,1714,1729,1742,1746,1768],[14,15,17],"h2",{"id":16},"tldr","TL;DR",[19,20,21,22,26,27,30],"p",{},"O wkhtmltopdf foi arquivado em janeiro de 2023. Chromium headless (Puppeteer, Playwright, chromedp, go-rod) funciona, mas leva junto um binário de navegador de ~170 MB, mantém 50–120 MB residentes por requisição concorrente e adiciona 300–800 ms de cold start. O ",[23,24,25],"strong",{},"gpdf"," renderiza uma página de PDF em ",[23,28,29],{},"13 µs",", sem dependências e sem navegador headless — ao preço de não renderizar HTML+CSS arbitrário.",[19,32,33],{},"Regra de decisão para o restante do post: se o requisito é \"a designer me entrega uma página Tailwind e quer pixel-perfect\", Chromium ainda é a ferramenta certa. Se é \"nota fiscal, extrato, relatório, certificado, etiqueta\", o caminho nativo pertence a outra categoria de custo.",[19,35,36],{},"Aviso de viés: nós publicamos o gpdf. O código de benchmark é público, a seção de trade-offs nomeia o que abrimos mão, e a matriz de casos não finge que gpdf vence tudo.",[14,38,40],{"id":39},"as-três-arquiteturas-lado-a-lado","As três arquiteturas, lado a lado",[42,43,44,72],"table",{},[45,46,47],"thead",{},[48,49,50,54,57,60,63,66,69],"tr",{},[51,52,53],"th",{},"Abordagem",[51,55,56],{},"Ferramentas exemplares",[51,58,59],{},"Engine de renderização",[51,61,62],{},"Tamanho do binário",[51,64,65],{},"RSS / requisição",[51,67,68],{},"Cold start",[51,70,71],{},"Licença",[73,74,75,101,132],"tbody",{},[48,76,77,83,86,89,92,95,98],{},[78,79,80],"td",{},[23,81,82],{},"wkhtmltopdf",[78,84,85],{},"wkhtmltopdf CLI",[78,87,88],{},"Fork do QtWebKit (~2014)",[78,90,91],{},"~40 MB",[78,93,94],{},"~30–80 MB",[78,96,97],{},"~150 ms",[78,99,100],{},"LGPLv3",[48,102,103,108,111,114,119,124,129],{},[78,104,105],{},[23,106,107],{},"Baseado em Chromium",[78,109,110],{},"Puppeteer, Playwright, chromedp, go-rod",[78,112,113],{},"Blink + V8 (Chromium real)",[78,115,116],{},[23,117,118],{},"~170 MB",[78,120,121],{},[23,122,123],{},"~50–120 MB",[78,125,126],{},[23,127,128],{},"~300–800 ms",[78,130,131],{},"BSD + restrições de redistribuição",[48,133,134,139,142,145,150,155,160],{},[78,135,136],{},[23,137,138],{},"Nativo (gpdf)",[78,140,141],{},"gpdf, signintech/gopdf, gofpdf†",[78,143,144],{},"PDF Writer puro em Go",[78,146,147],{},[23,148,149],{},"0 deps",[78,151,152],{},[23,153,154],{},"~2–10 MB",[78,156,157],{},[23,158,159],{},"0 ms",[78,161,162],{},"MIT",[19,164,165,166,171],{},"† gofpdf e go-pdf/fpdf estão ambos arquivados; o restante do panorama Go está em nosso ",[167,168,170],"a",{"href":169},"/pt/blog/go-pdf-library-showdown-2026","showdown de 2026",".",[19,173,174],{},"Três coisas a ler nessa tabela antes da explicação.",[19,176,177],{},"Um: o \"tamanho pequeno do binário\" do wkhtmltopdf é enganoso. A contagem de bytes é baixa porque o fork do WebKit parou de seguir o upstream há mais de uma década. O backlog de CVEs não é baixo.",[19,179,180],{},"Dois: Chromium não é uma biblioteca de PDF — é um navegador que por acaso imprime. Todo custo dessa coluna é custo de navegador.",[19,182,183],{},"Três: a diferença entre \"0 ms\" e \"300 ms\" de cold start não importa para um servidor longo que gera um PDF por hora. É existencial para serverless (Lambda, Cloud Run, Workers) e para lotes do tipo \"1.000 PDFs o mais rápido possível\".",[14,185,187],{"id":186},"wkhtmltopdf-em-2026","wkhtmltopdf em 2026",[19,189,190],{},"Talvez você não precise ler esta seção. Se seu time já saiu do wkhtmltopdf, pule para a próxima.",[19,192,193],{},"Para os demais: o desenvolvimento do wkhtmltopdf efetivamente parou em 2022, o repositório foi arquivado em janeiro de 2023, e a nota de despedida do mantenedor recomenda Chromium como substituto. A razão foi de infraestrutura. O renderizador do wkhtmltopdf é o QtWebKit, um fork do WebKit que parou de seguir o upstream por volta de 2014. O próprio Qt depreciou o QtWebKit em 2016 em favor do QtWebEngine (que embrulha Chromium). O fork que o wkhtmltopdf ainda usa é um motor de navegador de 12 anos atrás.",[19,195,196,197,201,202,205,206,209,210,213],{},"Concretamente, isso significa: CSS moderno — especificação completa de flex, grid, propriedades customizadas em escala, ",[198,199,200],"code",{},"aspect-ratio",", ",[198,203,204],{},":has()",", container queries, ",[198,207,208],{},"gap"," em flex, funções modernas de color — ou renderiza errado ou não renderiza. Web fonts via ",[198,211,212],{},"@font-face"," em sua maioria funcionam; web fonts com eixos variáveis, não. Suporte a SVG é parcial. Suporte a WOFF2 chegou tarde e tem bugs.",[19,215,216],{},"Portanto \"usar wkhtmltopdf\" em 2026 tem dois significados, ambos ruins.",[19,218,219,222],{},[23,220,221],{},"Você está em uma versão upstream que carrega código WebKit não corrigido."," Times de segurança vão acabar sinalizando, e \"o projeto foi arquivado\" não é um plano de mitigação. O último release foi em 2020. Desde então, trabalho de CVE tem sido feito por distros Linux portando patches, não pelo upstream.",[19,224,225,228],{},[23,226,227],{},"Você mantém um fork privado."," Alguém precisa ler fonte do Qt e do WebKit, retroportar patches e reconstruir para cada plataforma que você publica. Já vimos esse caso. O custo é um engenheiro full-time que preferia estar fazendo outra coisa.",[19,230,231],{},"A pergunta de migração é se você substitui o wkhtmltopdf por Chromium (alta fidelidade, alto custo) ou por um gerador de PDF nativo (baixo custo, sem HTML/CSS). É o assunto do restante do post.",[14,233,235],{"id":234},"geração-baseada-em-chromium-o-que-você-realmente-paga","Geração baseada em Chromium: o que você realmente paga",[19,237,238],{},"Chromium headless é a ferramenta certa quando você de fato precisa de um navegador. O custo aparece em quatro lugares.",[19,240,241,244],{},[23,242,243],{},"O binário."," Chromium em si tem ~170 MB. O Playwright já vem com um build conhecido bom; o Puppeteer baixa um na instalação (~280 MB somando os três navegadores que ele suporta). Em uma imagem de container, isso será sua maior camada por uma ordem de grandeza. No limite de 250 MB do zip do Lambda, esse item já preenche quase tudo.",[19,246,247,250],{},[23,248,249],{},"Memória por processo."," Um processo Chromium recém-iniciado abre com ~50 MB residentes. Carregar uma página não trivial (CSS real, web fonts, algumas imagens) leva a 80–120 MB. Os números variam com a página. O piso, não.",[19,252,253,256,257,260,261,264,265,268],{},[23,254,255],{},"Cold start."," Subir o Chromium e navegar para ",[198,258,259],{},"about:blank"," leva ~300 ms em uma máquina quente. Somando ",[198,262,263],{},"await page.goto(url)"," + carregamento real da página + obtenção de fontes + ",[198,266,267],{},"await page.pdf()"," é mais tipicamente 500 ms a 2 segundos na primeira requisição. Manter um pool de Chromium quente ajuda; não ajuda em serverless, onde você paga o cold start a cada evento de escala.",[19,270,271,274,275,278,279,278,282,285,286,289],{},[23,272,273],{},"Superfície operacional."," Um navegador é um continente de decisões que você não pretendia tomar: como tratar CSP, esperar ",[198,276,277],{},"networkidle"," ou ",[198,280,281],{},"load",[198,283,284],{},"domcontentloaded",", se desabilitar JS, como configurar ",[198,287,288],{},"--disable-dev-shm-usage"," no Docker, o que fazer quando o processo do navegador vaza. Nada é difícil. Tudo junto é debug que você preferiria não estar fazendo.",[19,291,292],{},"Há um contra-argumento honesto: quando você precisa da fidelidade, precisa mesmo. Um PDF de marketing desenhado por alguém que te entrega um export do Figma e uma página Tailwind, com fontes customizadas, gradientes e ícones SVG que precisam renderizar exatamente — esse é trabalho do Chromium. Tentar com uma API declarativa de documento queima uma semana e produz algo que a designer rejeita na primeira revisão.",[19,294,295],{},"Então a pergunta não é \"Chromium sim ou não\". É: \"o que estou renderizando é realmente uma página web?\".",[14,297,299],{"id":298},"gpdf-renderização-nativa-sem-navegador","gpdf: renderização nativa sem navegador",[19,301,302],{},"gpdf está na terceira categoria — um PDF Writer nativo em Go. Sem HTML, sem CSS, sem navegador headless. Você descreve o documento em Go (ou JSON, ou templates Go) e a biblioteca emite os bytes do PDF diretamente.",[304,305,310],"pre",{"className":306,"code":307,"language":308,"meta":309,"style":309},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","package main\n\nimport (\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.WithPaperSize(document.A4),\n        gpdf.WithMargin(document.Mm(20)),\n    )\n\n    doc.AddPage(func(p *template.PageBuilder) {\n        p.Row(document.Mm(12), func(r *template.RowBuilder) {\n            r.Col(12, func(c *template.ColBuilder) {\n                c.Text(\"Nota fiscal\", template.FontSize(24), template.Bold())\n            })\n        })\n        p.Row(document.Mm(8), func(r *template.RowBuilder) {\n            r.Col(6, func(c *template.ColBuilder) {\n                c.Text(\"Acme Ltda\", template.FontSize(11))\n            })\n            r.Col(6, func(c *template.ColBuilder) {\n                c.Text(\"INV-2026-0517\", template.FontSize(11), template.AlignRight())\n            })\n        })\n        // A seguir: linhas e totais\n    })\n\n    out, _ := os.Create(\"invoice.pdf\")\n    defer out.Close()\n    doc.Write(out)\n}\n","go","",[198,311,312,325,332,342,354,359,369,379,389,395,400,416,437,462,490,496,501,534,580,616,665,671,677,717,749,783,788,819,860,865,870,877,883,888,920,937,954],{"__ignoreMap":309},[313,314,317,321],"span",{"class":315,"line":316},"line",1,[313,318,320],{"class":319},"sMK4o","package",[313,322,324],{"class":323},"sBMFI"," main\n",[313,326,328],{"class":315,"line":327},2,[313,329,331],{"emptyLinePlaceholder":330},true,"\n",[313,333,335,339],{"class":315,"line":334},3,[313,336,338],{"class":337},"s7zQu","import",[313,340,341],{"class":319}," (\n",[313,343,345,348,351],{"class":315,"line":344},4,[313,346,347],{"class":319},"    \"",[313,349,350],{"class":323},"os",[313,352,353],{"class":319},"\"\n",[313,355,357],{"class":315,"line":356},5,[313,358,331],{"emptyLinePlaceholder":330},[313,360,362,364,367],{"class":315,"line":361},6,[313,363,347],{"class":319},[313,365,366],{"class":323},"github.com/gpdf-dev/gpdf",[313,368,353],{"class":319},[313,370,372,374,377],{"class":315,"line":371},7,[313,373,347],{"class":319},[313,375,376],{"class":323},"github.com/gpdf-dev/gpdf/document",[313,378,353],{"class":319},[313,380,382,384,387],{"class":315,"line":381},8,[313,383,347],{"class":319},[313,385,386],{"class":323},"github.com/gpdf-dev/gpdf/template",[313,388,353],{"class":319},[313,390,392],{"class":315,"line":391},9,[313,393,394],{"class":319},")\n",[313,396,398],{"class":315,"line":397},10,[313,399,331],{"emptyLinePlaceholder":330},[313,401,403,406,410,413],{"class":315,"line":402},11,[313,404,405],{"class":319},"func",[313,407,409],{"class":408},"s2Zo4"," main",[313,411,412],{"class":319},"()",[313,414,415],{"class":319}," {\n",[313,417,419,423,426,429,431,434],{"class":315,"line":418},12,[313,420,422],{"class":421},"sTEyZ","    doc ",[313,424,425],{"class":319},":=",[313,427,428],{"class":421}," gpdf",[313,430,171],{"class":319},[313,432,433],{"class":408},"NewDocument",[313,435,436],{"class":319},"(\n",[313,438,440,443,445,448,451,454,456,459],{"class":315,"line":439},13,[313,441,442],{"class":421},"        gpdf",[313,444,171],{"class":319},[313,446,447],{"class":408},"WithPaperSize",[313,449,450],{"class":319},"(",[313,452,453],{"class":421},"document",[313,455,171],{"class":319},[313,457,458],{"class":421},"A4",[313,460,461],{"class":319},"),\n",[313,463,465,467,469,472,474,476,478,481,483,487],{"class":315,"line":464},14,[313,466,442],{"class":421},[313,468,171],{"class":319},[313,470,471],{"class":408},"WithMargin",[313,473,450],{"class":319},[313,475,453],{"class":421},[313,477,171],{"class":319},[313,479,480],{"class":408},"Mm",[313,482,450],{"class":319},[313,484,486],{"class":485},"sbssI","20",[313,488,489],{"class":319},")),\n",[313,491,493],{"class":315,"line":492},15,[313,494,495],{"class":319},"    )\n",[313,497,499],{"class":315,"line":498},16,[313,500,331],{"emptyLinePlaceholder":330},[313,502,504,507,509,512,515,518,521,524,526,529,532],{"class":315,"line":503},17,[313,505,506],{"class":421},"    doc",[313,508,171],{"class":319},[313,510,511],{"class":408},"AddPage",[313,513,514],{"class":319},"(func(",[313,516,19],{"class":517},"sHdIc",[313,519,520],{"class":319}," *",[313,522,523],{"class":323},"template",[313,525,171],{"class":319},[313,527,528],{"class":323},"PageBuilder",[313,530,531],{"class":319},")",[313,533,415],{"class":319},[313,535,537,540,542,545,547,549,551,553,555,558,561,564,567,569,571,573,576,578],{"class":315,"line":536},18,[313,538,539],{"class":421},"        p",[313,541,171],{"class":319},[313,543,544],{"class":408},"Row",[313,546,450],{"class":319},[313,548,453],{"class":421},[313,550,171],{"class":319},[313,552,480],{"class":408},[313,554,450],{"class":319},[313,556,557],{"class":485},"12",[313,559,560],{"class":319},"),",[313,562,563],{"class":319}," func(",[313,565,566],{"class":517},"r",[313,568,520],{"class":319},[313,570,523],{"class":323},[313,572,171],{"class":319},[313,574,575],{"class":323},"RowBuilder",[313,577,531],{"class":319},[313,579,415],{"class":319},[313,581,583,586,588,591,593,595,598,600,603,605,607,609,612,614],{"class":315,"line":582},19,[313,584,585],{"class":421},"            r",[313,587,171],{"class":319},[313,589,590],{"class":408},"Col",[313,592,450],{"class":319},[313,594,557],{"class":485},[313,596,597],{"class":319},",",[313,599,563],{"class":319},[313,601,602],{"class":517},"c",[313,604,520],{"class":319},[313,606,523],{"class":323},[313,608,171],{"class":319},[313,610,611],{"class":323},"ColBuilder",[313,613,531],{"class":319},[313,615,415],{"class":319},[313,617,619,622,624,627,629,632,636,638,640,643,645,648,650,653,655,657,659,662],{"class":315,"line":618},20,[313,620,621],{"class":421},"                c",[313,623,171],{"class":319},[313,625,626],{"class":408},"Text",[313,628,450],{"class":319},[313,630,631],{"class":319},"\"",[313,633,635],{"class":634},"sfazB","Nota fiscal",[313,637,631],{"class":319},[313,639,597],{"class":319},[313,641,642],{"class":421}," template",[313,644,171],{"class":319},[313,646,647],{"class":408},"FontSize",[313,649,450],{"class":319},[313,651,652],{"class":485},"24",[313,654,560],{"class":319},[313,656,642],{"class":421},[313,658,171],{"class":319},[313,660,661],{"class":408},"Bold",[313,663,664],{"class":319},"())\n",[313,666,668],{"class":315,"line":667},21,[313,669,670],{"class":319},"            })\n",[313,672,674],{"class":315,"line":673},22,[313,675,676],{"class":319},"        })\n",[313,678,680,682,684,686,688,690,692,694,696,699,701,703,705,707,709,711,713,715],{"class":315,"line":679},23,[313,681,539],{"class":421},[313,683,171],{"class":319},[313,685,544],{"class":408},[313,687,450],{"class":319},[313,689,453],{"class":421},[313,691,171],{"class":319},[313,693,480],{"class":408},[313,695,450],{"class":319},[313,697,698],{"class":485},"8",[313,700,560],{"class":319},[313,702,563],{"class":319},[313,704,566],{"class":517},[313,706,520],{"class":319},[313,708,523],{"class":323},[313,710,171],{"class":319},[313,712,575],{"class":323},[313,714,531],{"class":319},[313,716,415],{"class":319},[313,718,720,722,724,726,728,731,733,735,737,739,741,743,745,747],{"class":315,"line":719},24,[313,721,585],{"class":421},[313,723,171],{"class":319},[313,725,590],{"class":408},[313,727,450],{"class":319},[313,729,730],{"class":485},"6",[313,732,597],{"class":319},[313,734,563],{"class":319},[313,736,602],{"class":517},[313,738,520],{"class":319},[313,740,523],{"class":323},[313,742,171],{"class":319},[313,744,611],{"class":323},[313,746,531],{"class":319},[313,748,415],{"class":319},[313,750,752,754,756,758,760,762,765,767,769,771,773,775,777,780],{"class":315,"line":751},25,[313,753,621],{"class":421},[313,755,171],{"class":319},[313,757,626],{"class":408},[313,759,450],{"class":319},[313,761,631],{"class":319},[313,763,764],{"class":634},"Acme Ltda",[313,766,631],{"class":319},[313,768,597],{"class":319},[313,770,642],{"class":421},[313,772,171],{"class":319},[313,774,647],{"class":408},[313,776,450],{"class":319},[313,778,779],{"class":485},"11",[313,781,782],{"class":319},"))\n",[313,784,786],{"class":315,"line":785},26,[313,787,670],{"class":319},[313,789,791,793,795,797,799,801,803,805,807,809,811,813,815,817],{"class":315,"line":790},27,[313,792,585],{"class":421},[313,794,171],{"class":319},[313,796,590],{"class":408},[313,798,450],{"class":319},[313,800,730],{"class":485},[313,802,597],{"class":319},[313,804,563],{"class":319},[313,806,602],{"class":517},[313,808,520],{"class":319},[313,810,523],{"class":323},[313,812,171],{"class":319},[313,814,611],{"class":323},[313,816,531],{"class":319},[313,818,415],{"class":319},[313,820,822,824,826,828,830,832,835,837,839,841,843,845,847,849,851,853,855,858],{"class":315,"line":821},28,[313,823,621],{"class":421},[313,825,171],{"class":319},[313,827,626],{"class":408},[313,829,450],{"class":319},[313,831,631],{"class":319},[313,833,834],{"class":634},"INV-2026-0517",[313,836,631],{"class":319},[313,838,597],{"class":319},[313,840,642],{"class":421},[313,842,171],{"class":319},[313,844,647],{"class":408},[313,846,450],{"class":319},[313,848,779],{"class":485},[313,850,560],{"class":319},[313,852,642],{"class":421},[313,854,171],{"class":319},[313,856,857],{"class":408},"AlignRight",[313,859,664],{"class":319},[313,861,863],{"class":315,"line":862},29,[313,864,670],{"class":319},[313,866,868],{"class":315,"line":867},30,[313,869,676],{"class":319},[313,871,873],{"class":315,"line":872},31,[313,874,876],{"class":875},"sHwdD","        // A seguir: linhas e totais\n",[313,878,880],{"class":315,"line":879},32,[313,881,882],{"class":319},"    })\n",[313,884,886],{"class":315,"line":885},33,[313,887,331],{"emptyLinePlaceholder":330},[313,889,891,894,896,899,901,904,906,909,911,913,916,918],{"class":315,"line":890},34,[313,892,893],{"class":421},"    out",[313,895,597],{"class":319},[313,897,898],{"class":421}," _ ",[313,900,425],{"class":319},[313,902,903],{"class":421}," os",[313,905,171],{"class":319},[313,907,908],{"class":408},"Create",[313,910,450],{"class":319},[313,912,631],{"class":319},[313,914,915],{"class":634},"invoice.pdf",[313,917,631],{"class":319},[313,919,394],{"class":319},[313,921,923,926,929,931,934],{"class":315,"line":922},35,[313,924,925],{"class":337},"    defer",[313,927,928],{"class":421}," out",[313,930,171],{"class":319},[313,932,933],{"class":408},"Close",[313,935,936],{"class":319},"()\n",[313,938,940,942,944,947,949,952],{"class":315,"line":939},36,[313,941,506],{"class":421},[313,943,171],{"class":319},[313,945,946],{"class":408},"Write",[313,948,450],{"class":319},[313,950,951],{"class":421},"out",[313,953,394],{"class":319},[313,955,957],{"class":315,"line":956},37,[313,958,959],{"class":319},"}\n",[19,961,962,963,966,967,970,971,973,974,171],{},"Essa é a pilha inteira. Sem binário do Chromium no container. Sem ",[198,964,965],{},"npm install puppeteer",". Sem ",[198,968,969],{},"page.goto",". A chamada ",[198,972,946],{}," emite o PDF direto no writer — para uma nota fiscal de uma página, ",[167,975,977],{"href":976},"/pt/blog/why-gpdf-is-faster","~13 µs de CPU",[19,979,980,981,984],{},"O que abrimos mão para chegar aqui: o renderizador não sabe o que ",[198,982,983],{},"display: flex"," significa. Sabe linhas, colunas (grid de 12 colunas), runs de texto, imagens, tabelas, códigos de barras. Para a maioria dos documentos gerados em escala — notas fiscais, extratos, recibos, relatórios, certificados, etiquetas, romaneios — esse vocabulário basta. Para o restante (PDFs de marketing, folhetos conduzidos por design, qualquer coisa que começou como página web), não basta.",[14,986,988],{"id":987},"a-comparação-de-desempenho","A comparação de desempenho",[19,990,991],{},"Fazer benchmark entre essas três categorias é metodologicamente espinhoso, porque elas resolvem problemas ligeiramente diferentes. Vamos fazer mesmo assim. A comparação justa é \"mesmo produto final, três implementações\": uma nota fiscal de uma página com cabeçalho, tabela 4×10 de itens e totais.",[42,993,994,1012],{},[45,995,996],{},[48,997,998,1001,1003,1006],{},[51,999,1000],{},"Carga",[51,1002,25],{},[51,1004,1005],{},"wkhtmltopdf (CLI)",[51,1007,1008,1009,531],{},"Chromium (Playwright ",[198,1010,1011],{},"page.pdf()",[73,1013,1014,1029,1045,1059],{},[48,1015,1016,1019,1023,1026],{},[78,1017,1018],{},"Nota fiscal de uma página",[78,1020,1021],{},[23,1022,29],{},[78,1024,1025],{},"~140 ms",[78,1027,1028],{},"~280 ms (quente) / ~1.2 s (frio)",[48,1030,1031,1034,1039,1042],{},[78,1032,1033],{},"Relatório paginado de 100 páginas",[78,1035,1036],{},[23,1037,1038],{},"683 µs",[78,1040,1041],{},"~3.4 s",[78,1043,1044],{},"~6.1 s (quente)",[48,1046,1047,1050,1053,1056],{},[78,1048,1049],{},"RSS de pico em uma única requisição",[78,1051,1052],{},"~5 MB",[78,1054,1055],{},"~70 MB",[78,1057,1058],{},"~120 MB",[48,1060,1061,1064,1067,1070],{},[78,1062,1063],{},"Impacto no tamanho da imagem",[78,1065,1066],{},"0",[78,1068,1069],{},"+40 MB",[78,1071,1072],{},"+170 MB",[19,1074,1075,1076,1084],{},"Apple M1, Go 1.25 para o gpdf; binário wkhtmltopdf 0.12.6; Playwright 1.42 com Chromium incluso. O código de benchmark do gpdf está em ",[167,1077,1081],{"href":1078,"rel":1079},"https://github.com/gpdf-dev/gpdf/tree/main/_benchmark",[1080],"nofollow",[198,1082,1083],{},"_benchmark/"," — clone e rode no seu hardware.",[19,1086,1087],{},"Dois números merecem um parágrafo.",[19,1089,1090],{},"A diferença na nota fiscal de uma página é de cerca de 22.000×. A maior parte não é a renderização em si — é o custo de subir e derrubar um processo de navegador por requisição. Se você mantém um pool do Playwright quente, reduz ~4×; ainda fica em quatro ordens de grandeza.",[19,1092,1093],{},"A diferença do relatório de 100 páginas é de cerca de 9.000×. Aqui o custo de renderização domina, e o overhead constante de \"iniciar um navegador\" amortiza. Mesmo amortizado, o Chromium paga custos de layout por elemento que um PDF writer nativo pula.",[19,1095,1096],{},"O número que morde na produção é o RSS de pico. Um processo Chromium segurando ~120 MB durante um trabalho de 6 segundos significa que um container de 4 GB lida com cerca de 30 relatórios concorrentes. O mesmo container rodando gpdf lida com milhares.",[14,1098,1100],{"id":1099},"quando-cada-abordagem-vence","Quando cada abordagem vence",[19,1102,1103],{},"Esta não é uma matriz \"gpdf vence em tudo\". Não deveria ser. Decisões reais de arquitetura têm essa cara.",[42,1105,1106,1119],{},[45,1107,1108],{},[48,1109,1110,1113,1116],{},[51,1111,1112],{},"Caso de uso",[51,1114,1115],{},"Ferramenta certa",[51,1117,1118],{},"Por quê",[73,1120,1121,1132,1142,1153,1163,1174,1185,1196],{},[48,1122,1123,1126,1129],{},[78,1124,1125],{},"PDF de marketing a partir de design Figma + Tailwind",[78,1127,1128],{},"Chromium (Playwright)",[78,1130,1131],{},"Fidelidade à intenção do design pesa mais que custo.",[48,1133,1134,1137,1139],{},[78,1135,1136],{},"50.000 extratos mensais no fechamento",[78,1138,25],{},[78,1140,1141],{},"Custo por documento × volume = dinheiro real. CSS não é necessário.",[48,1143,1144,1147,1150],{},[78,1145,1146],{},"Único \"designer pediu um folheto\"",[78,1148,1149],{},"Chromium (or InDesign)",[78,1151,1152],{},"Volume baixo, CSS alto. Use a ferramenta certa uma vez.",[48,1154,1155,1158,1160],{},[78,1156,1157],{},"Notas fiscais para um sistema de billing SaaS",[78,1159,25],{},[78,1161,1162],{},"Volume escala com receita. Cold start importa. Layout estruturado.",[48,1164,1165,1168,1171],{},[78,1166,1167],{},"Formulários fiscais / declarações regulatórias (PDF/A)",[78,1169,1170],{},"gpdf (or unidoc)",[78,1172,1173],{},"Conformidade PDF/A, assinatura, trilhas de auditoria. Navegadores não fazem isso.",[48,1175,1176,1179,1182],{},[78,1177,1178],{},"Relatório de BI dashboard com screenshots de gráficos",[78,1180,1181],{},"Chromium",[78,1183,1184],{},"O gráfico é o ponto. PDF é a exportação.",[48,1186,1187,1190,1193],{},[78,1188,1189],{},"\"Imprimir o Markdown\" / PDF de documentação",[78,1191,1192],{},"gpdf ou Chromium",[78,1194,1195],{},"Qualquer um serve. Troca-se custo por fidelidade.",[48,1197,1198,1201,1204],{},[78,1199,1200],{},"Migração de wkhtmltopdf legado",[78,1202,1203],{},"gpdf se o HTML era simples; Chromium se o CSS era sério",[78,1205,1206],{},"Auditar templates primeiro.",[19,1208,1209,1210,1213,1214,1217],{},"O padrão: ",[23,1211,1212],{},"volume × custo por requisição"," vs ",[23,1215,1216],{},"fidelidade de design",". Se o primeiro eixo domina, vence nativo. Se o segundo domina, vence Chromium. O wkhtmltopdf não tem lugar nessa matriz em 2026.",[14,1219,1221],{"id":1220},"o-trade-off-que-não-fingimos-que-não-existe","O trade-off que não fingimos que não existe",[19,1223,1224],{},"Viemos costurando isso o post inteiro. Merece seção própria.",[19,1226,1227],{},"O gpdf não renderiza HTML nem CSS. Se seu sistema atual é \"temos um template de email em HTML que também imprimimos como PDF\", migrar para gpdf significa reescrever esse template contra a API builder do gpdf. Para um template, uma tarde resolve. Para uma biblioteca de 30 templates de marketing mantidos por designers, é um projeto.",[19,1229,1230,1231,1233,1234,1238],{},"Também não renderizamos web fonts via ",[198,1232,212],{},". Você passa arquivos TTF/OTF ao gpdf na construção do documento. Fontes CJK em particular são first-class — escrevemos sobre ",[167,1235,1237],{"href":1236},"/pt/blog/japanese-pdf-in-go","por que renderizamos CJK sem CGO"," — mas o desenvolvedor precisa distribuir o arquivo de fonte.",[19,1240,1241],{},"Onde não cedemos: velocidade, memória, facilidade de deploy, footprint de dependências. O trade-off é pago em superfície de funcionalidades, não em custo de produção. Achamos que muitos times gerando documentos estruturados em alto volume vêm pagando por um navegador de que não precisavam, e a resposta certa para esses times é o caminho nativo. Não achamos que o gpdf seja a resposta certa para todos os times.",[14,1243,1245],{"id":1244},"código-a-mesma-nota-fiscal-três-jeitos","Código: a mesma nota fiscal, três jeitos",[19,1247,1248],{},"Se quiser sentir as diferenças de API na prática, eis as três implementações lado a lado.",[19,1250,1251],{},[23,1252,1253],{},"Chromium (Playwright, Node):",[304,1255,1259],{"className":1256,"code":1257,"language":1258,"meta":309,"style":309},"language-js shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const { chromium } = require('playwright');\nconst fs = require('fs');\n\n(async () => {\n  const browser = await chromium.launch();\n  const page = await browser.newPage();\n  const html = fs.readFileSync('invoice.html', 'utf8');\n  await page.setContent(html, { waitUntil: 'networkidle' });\n  await page.pdf({\n    path: 'invoice.pdf',\n    format: 'A4',\n    margin: { top: '20mm', bottom: '20mm', left: '20mm', right: '20mm' },\n  });\n  await browser.close();\n})();\n","js",[198,1260,1261,1266,1271,1275,1280,1285,1290,1295,1300,1305,1310,1315,1320,1325,1330],{"__ignoreMap":309},[313,1262,1263],{"class":315,"line":316},[313,1264,1265],{},"const { chromium } = require('playwright');\n",[313,1267,1268],{"class":315,"line":327},[313,1269,1270],{},"const fs = require('fs');\n",[313,1272,1273],{"class":315,"line":334},[313,1274,331],{"emptyLinePlaceholder":330},[313,1276,1277],{"class":315,"line":344},[313,1278,1279],{},"(async () => {\n",[313,1281,1282],{"class":315,"line":356},[313,1283,1284],{},"  const browser = await chromium.launch();\n",[313,1286,1287],{"class":315,"line":361},[313,1288,1289],{},"  const page = await browser.newPage();\n",[313,1291,1292],{"class":315,"line":371},[313,1293,1294],{},"  const html = fs.readFileSync('invoice.html', 'utf8');\n",[313,1296,1297],{"class":315,"line":381},[313,1298,1299],{},"  await page.setContent(html, { waitUntil: 'networkidle' });\n",[313,1301,1302],{"class":315,"line":391},[313,1303,1304],{},"  await page.pdf({\n",[313,1306,1307],{"class":315,"line":397},[313,1308,1309],{},"    path: 'invoice.pdf',\n",[313,1311,1312],{"class":315,"line":402},[313,1313,1314],{},"    format: 'A4',\n",[313,1316,1317],{"class":315,"line":418},[313,1318,1319],{},"    margin: { top: '20mm', bottom: '20mm', left: '20mm', right: '20mm' },\n",[313,1321,1322],{"class":315,"line":439},[313,1323,1324],{},"  });\n",[313,1326,1327],{"class":315,"line":464},[313,1328,1329],{},"  await browser.close();\n",[313,1331,1332],{"class":315,"line":492},[313,1333,1334],{},"})();\n",[19,1336,1337,1338,1341,1342,1345],{},"Mais um ",[198,1339,1340],{},"invoice.html"," que você mantém, mais o binário Chromium incluso (~170 MB), mais um jeito de tratar carregamento de fontes (web fonts? base64 inline? ",[198,1343,1344],{},"--font-render-hinting","?). Funciona lindo num template Tailwind; a superfície de manutenção é o HTML.",[19,1347,1348],{},[23,1349,1350],{},"wkhtmltopdf (shell):",[304,1352,1356],{"className":1353,"code":1354,"language":1355,"meta":309,"style":309},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","wkhtmltopdf --enable-local-file-access \\\n  --margin-top 20mm --margin-bottom 20mm --margin-left 20mm --margin-right 20mm \\\n  invoice.html invoice.pdf\n","bash",[198,1357,1358,1368,1393],{"__ignoreMap":309},[313,1359,1360,1362,1365],{"class":315,"line":316},[313,1361,82],{"class":323},[313,1363,1364],{"class":634}," --enable-local-file-access",[313,1366,1367],{"class":421}," \\\n",[313,1369,1370,1373,1376,1379,1381,1384,1386,1389,1391],{"class":315,"line":327},[313,1371,1372],{"class":634},"  --margin-top",[313,1374,1375],{"class":634}," 20mm",[313,1377,1378],{"class":634}," --margin-bottom",[313,1380,1375],{"class":634},[313,1382,1383],{"class":634}," --margin-left",[313,1385,1375],{"class":634},[313,1387,1388],{"class":634}," --margin-right",[313,1390,1375],{"class":634},[313,1392,1367],{"class":421},[313,1394,1395,1398],{"class":315,"line":334},[313,1396,1397],{"class":634},"  invoice.html",[313,1399,1400],{"class":634}," invoice.pdf\n",[19,1402,1403,1404,1407,1408,1411,1412,1414],{},"Mais o binário do wkhtmltopdf, mais um template HTML que evite CSS que o QtWebKit-2014 não entende (na prática: sem ",[198,1405,1406],{},"grid",", cuidado com ",[198,1409,1410],{},"flex",", sem ",[198,1413,204],{},", custom properties só parcialmente). Mais a conversa de segurança quando o binário for sinalizado em uma auditoria.",[19,1416,1417],{},[23,1418,1419],{},"gpdf (Go):",[304,1421,1423],{"className":306,"code":1422,"language":308,"meta":309,"style":309},"doc := gpdf.NewDocument(\n    gpdf.WithPaperSize(document.A4),\n    gpdf.WithMargin(document.Mm(20)),\n)\ndoc.AddPage(func(p *template.PageBuilder) {\n    invoiceHeader(p, \"INV-2026-0517\", \"Acme Ltda\")\n    invoiceTable(p, lineItems)\n    invoiceTotals(p, subtotal, tax, total)\n})\nout, _ := os.Create(\"invoice.pdf\")\ndefer out.Close()\ndoc.Write(out)\n",[198,1424,1425,1440,1459,1481,1485,1510,1538,1554,1580,1585,1611,1624],{"__ignoreMap":309},[313,1426,1427,1430,1432,1434,1436,1438],{"class":315,"line":316},[313,1428,1429],{"class":421},"doc ",[313,1431,425],{"class":319},[313,1433,428],{"class":421},[313,1435,171],{"class":319},[313,1437,433],{"class":408},[313,1439,436],{"class":319},[313,1441,1442,1445,1447,1449,1451,1453,1455,1457],{"class":315,"line":327},[313,1443,1444],{"class":421},"    gpdf",[313,1446,171],{"class":319},[313,1448,447],{"class":408},[313,1450,450],{"class":319},[313,1452,453],{"class":421},[313,1454,171],{"class":319},[313,1456,458],{"class":421},[313,1458,461],{"class":319},[313,1460,1461,1463,1465,1467,1469,1471,1473,1475,1477,1479],{"class":315,"line":334},[313,1462,1444],{"class":421},[313,1464,171],{"class":319},[313,1466,471],{"class":408},[313,1468,450],{"class":319},[313,1470,453],{"class":421},[313,1472,171],{"class":319},[313,1474,480],{"class":408},[313,1476,450],{"class":319},[313,1478,486],{"class":485},[313,1480,489],{"class":319},[313,1482,1483],{"class":315,"line":344},[313,1484,394],{"class":319},[313,1486,1487,1490,1492,1494,1496,1498,1500,1502,1504,1506,1508],{"class":315,"line":356},[313,1488,1489],{"class":421},"doc",[313,1491,171],{"class":319},[313,1493,511],{"class":408},[313,1495,514],{"class":319},[313,1497,19],{"class":517},[313,1499,520],{"class":319},[313,1501,523],{"class":323},[313,1503,171],{"class":319},[313,1505,528],{"class":323},[313,1507,531],{"class":319},[313,1509,415],{"class":319},[313,1511,1512,1515,1517,1519,1521,1524,1526,1528,1530,1532,1534,1536],{"class":315,"line":361},[313,1513,1514],{"class":408},"    invoiceHeader",[313,1516,450],{"class":319},[313,1518,19],{"class":421},[313,1520,597],{"class":319},[313,1522,1523],{"class":319}," \"",[313,1525,834],{"class":634},[313,1527,631],{"class":319},[313,1529,597],{"class":319},[313,1531,1523],{"class":319},[313,1533,764],{"class":634},[313,1535,631],{"class":319},[313,1537,394],{"class":319},[313,1539,1540,1543,1545,1547,1549,1552],{"class":315,"line":371},[313,1541,1542],{"class":408},"    invoiceTable",[313,1544,450],{"class":319},[313,1546,19],{"class":421},[313,1548,597],{"class":319},[313,1550,1551],{"class":421}," lineItems",[313,1553,394],{"class":319},[313,1555,1556,1559,1561,1563,1565,1568,1570,1573,1575,1578],{"class":315,"line":381},[313,1557,1558],{"class":408},"    invoiceTotals",[313,1560,450],{"class":319},[313,1562,19],{"class":421},[313,1564,597],{"class":319},[313,1566,1567],{"class":421}," subtotal",[313,1569,597],{"class":319},[313,1571,1572],{"class":421}," tax",[313,1574,597],{"class":319},[313,1576,1577],{"class":421}," total",[313,1579,394],{"class":319},[313,1581,1582],{"class":315,"line":391},[313,1583,1584],{"class":319},"})\n",[313,1586,1587,1589,1591,1593,1595,1597,1599,1601,1603,1605,1607,1609],{"class":315,"line":397},[313,1588,951],{"class":421},[313,1590,597],{"class":319},[313,1592,898],{"class":421},[313,1594,425],{"class":319},[313,1596,903],{"class":421},[313,1598,171],{"class":319},[313,1600,908],{"class":408},[313,1602,450],{"class":319},[313,1604,631],{"class":319},[313,1606,915],{"class":634},[313,1608,631],{"class":319},[313,1610,394],{"class":319},[313,1612,1613,1616,1618,1620,1622],{"class":315,"line":402},[313,1614,1615],{"class":337},"defer",[313,1617,928],{"class":421},[313,1619,171],{"class":319},[313,1621,933],{"class":408},[313,1623,936],{"class":319},[313,1625,1626,1628,1630,1632,1634,1636],{"class":315,"line":418},[313,1627,1489],{"class":421},[313,1629,171],{"class":319},[313,1631,946],{"class":408},[313,1633,450],{"class":319},[313,1635,951],{"class":421},[313,1637,394],{"class":319},[19,1639,1640,1641,171],{},"Mais três funções Go que você escreveu contra a API builder. Sem arquivos de template, sem dependência binária, sem etapa de renderização separada. Implantável como um único binário Go em um container ",[198,1642,1643],{},"FROM scratch",[19,1645,1646],{},"A leitura certa não é \"qual é o mais curto\". É: \"qual superfície quero manter\". A do Chromium é HTML + CSS + um navegador; a do wkhtmltopdf é HTML + CSS + um navegador de dez anos atrás; a do gpdf é Go.",[14,1648,1650],{"id":1649},"faq","FAQ",[19,1652,1653],{},[23,1654,1655],{},"O wkhtmltopdf é mesmo inviável em 2026?",[19,1657,1658,1659,1663],{},"Inviável é forte. ",[1660,1661,1662],"em",{},"Não recomendável"," é a palavra certa. Ainda roda, ainda produz PDFs, e para templates simples produz PDFs corretos. As razões para não começar um projeto novo nele: o projeto foi arquivado, o fork do WebKit é base de 2014, auditorias de segurança vão sinalizar, e a orientação oficial de substituição é \"use Chromium\". Se você tem wkhtmltopdf em produção hoje, tem tempo de migrar; não tem tempo de adicionar novas dependências sobre ele.",[19,1665,1666],{},[23,1667,1668],{},"Não dá só pra rodar Chromium e aceitar o custo?",[19,1670,1671],{},"Para a maioria das cargas, dá. A matriz acima coloca PDFs de marketing e documentos conduzidos por design firmemente na coluna do Chromium. A razão deste post existir é que Chromium também está sendo usado para notas fiscais, extratos e relatórios — cargas onde o navegador está pagando por fidelidade que o documento não precisa. É aí que o custo aparece na fatura da AWS.",[19,1673,1674],{},[23,1675,1676],{},"E os HTML-para-PDF sem Chromium, tipo html2pdf ou jsPDF?",[19,1678,1679],{},"Essas são bibliotecas JS do lado do navegador que renderizam HTML em canvas e daí em PDF. A fidelidade é significativamente pior que a do Chromium (a maioria do CSS moderno não funciona) e o desempenho é pior que o nativo (você renderiza duas vezes: HTML → canvas → PDF). Têm nicho próprio — geração de PDF do lado cliente sem servidor — mas não entram nessa comparação.",[19,1681,1682],{},[23,1683,1684],{},"O gpdf suporta PDF/A ou assinaturas digitais?",[19,1686,1687,1688,1691,1692,1695],{},"Sim. ",[198,1689,1690],{},"gpdf.WithPDFA(...)"," para conformidade PDF/A-1b e PDF/A-2b, ",[198,1693,1694],{},"gpdf.SignDocument(...)"," para assinaturas PKCS#7 com timestamp RFC 3161. Ambos na biblioteca core MIT — sem add-on, sem licença comercial.",[19,1697,1698],{},[23,1699,1700],{},"Como o gpdf se compara a outras bibliotecas de PDF em Go (não navegadores)?",[19,1702,1703,1704,171],{},"Pergunta diferente. Versão curta: gofpdf e go-pdf/fpdf estão arquivadas; signintech/gopdf é mantida mas de baixo nível (sem grid de layout); Maroto v2 é mantida mas construída sobre o gofpdf arquivado; unidoc é comercial. A comparação completa está em ",[167,1705,1706],{"href":169},"Showdown de bibliotecas PDF em Go 2026",[14,1708,1710],{"id":1709},"experimente-o-gpdf","Experimente o gpdf",[19,1712,1713],{},"gpdf é uma biblioteca de PDF para Go. MIT, zero dependências, CJK nativo.",[304,1715,1717],{"className":1353,"code":1716,"language":1355,"meta":309,"style":309},"go get github.com/gpdf-dev/gpdf\n",[198,1718,1719],{"__ignoreMap":309},[313,1720,1721,1723,1726],{"class":315,"line":316},[313,1722,308],{"class":323},[313,1724,1725],{"class":634}," get",[313,1727,1728],{"class":634}," github.com/gpdf-dev/gpdf\n",[19,1730,1731,1736,1737],{},[167,1732,1735],{"href":1733,"rel":1734},"https://github.com/gpdf-dev/gpdf",[1080],"⭐ Star no GitHub"," · ",[167,1738,1741],{"href":1739,"rel":1740},"https://gpdf.dev/pt/docs/quickstart",[1080],"Ler a documentação",[14,1743,1745],{"id":1744},"próximas-leituras","Próximas leituras",[1747,1748,1749,1756,1761],"ul",{},[1750,1751,1752,1755],"li",{},[167,1753,1754],{"href":976},"Por que o gpdf é 10–30× mais rápido que outras bibliotecas de PDF em Go"," — a arquitetura por trás dos números deste post",[1750,1757,1758,1760],{},[167,1759,1706],{"href":169}," — comparação entre bibliotecas Go nativas",[1750,1762,1763,1767],{},[167,1764,1766],{"href":1765},"/pt/blog/gofpdf-migration","Migrando de gofpdf para gpdf"," — se você está deixando uma biblioteca arquivada",[1769,1770,1771],"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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}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 .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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}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);}",{"title":309,"searchDepth":327,"depth":327,"links":1773},[1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,1784,1785],{"id":16,"depth":327,"text":17},{"id":39,"depth":327,"text":40},{"id":186,"depth":327,"text":187},{"id":234,"depth":327,"text":235},{"id":298,"depth":327,"text":299},{"id":987,"depth":327,"text":988},{"id":1099,"depth":327,"text":1100},{"id":1220,"depth":327,"text":1221},{"id":1244,"depth":327,"text":1245},{"id":1649,"depth":327,"text":1650},{"id":1709,"depth":327,"text":1710},{"id":1744,"depth":327,"text":1745},"2026-05-18","wkhtmltopdf foi arquivado. Chromium consome 170 MB por requisição. gpdf renderiza uma página em 13 µs sem navegador. Comparação honesta para 2026.",false,"md",null,{},"/pt/blog/gpdf-vs-wkhtmltopdf-vs-chromium",{"title":5,"description":1787},"pt/blog/026.gpdf-vs-wkhtmltopdf-vs-chromium",[1796,1797,1798],"comparison","benchmark","migration","-JIw6pxyqZg9rDP42ZySZ5zRCP3d3IvwgZ4GjdkBxto",1779199037298]