[{"data":1,"prerenderedAt":5707},["ShallowReactive",2],{"blog-es-unidoc-migration":3},{"id":4,"title":5,"author":6,"body":10,"date":5667,"description":5668,"draft":5669,"extension":5670,"howTo":5671,"image":5697,"meta":5698,"navigation":304,"path":5699,"seo":5700,"stem":5701,"tags":5702,"updated":5697,"__hash__":5706},"blogEs/es/blog/016.unidoc-migration.md","unipdf es AGPL o de pago. Cómo migrar a gpdf.",{"name":7,"url":8,"avatar":9},"Taiki Noda","https://nadai.dev/en/about","https://nadai.dev/og-default.png",{"type":11,"value":12,"toc":5650},"minimark",[13,18,43,59,74,77,81,84,87,109,112,116,119,249,256,260,263,410,531,549,556,560,571,878,909,913,916,921,1295,1300,1730,1739,1743,1760,1764,2380,2383,2387,2781,2794,2805,2812,2816,2819,2823,3086,3092,3096,3550,3565,3568,3572,3588,3592,3882,3885,3889,4551,4558,4562,4568,4572,5037,5041,5329,5340,5344,5351,5447,5450,5453,5457,5460,5501,5507,5511,5517,5529,5549,5555,5574,5580,5584,5587,5604,5617,5621,5647],[14,15,17],"h2",{"id":16},"tldr","TL;DR",[19,20,21,25,26,29,30,33,34,38,39,42],"p",{},[22,23,24],"strong",{},"gpdf"," es una biblioteca PDF en Go puro bajo ",[22,27,28],{},"licencia MIT",", con ",[22,31,32],{},"cero dependencias externas"," y sin paso de registro de clave. Si estás en ",[35,36,37],"code",{},"unidoc/unipdf"," porque nada más manejaba CJK ni el aplanado de AcroForm, pero la cláusula AGPL tiene a tu equipo legal bloqueando la distribución y el plan comercial cuesta justificarlo, esta guía mapea la API ",[35,40,41],{},"creator"," de unipdf a gpdf, pieza por pieza.",[19,44,45,46,49,50,53,54,58],{},"El trimestre pasado, un amigo en una fintech pasó ",[35,47,48],{},"github.com/unidoc/unipdf/v3"," por el flujo de aprobación OSS. El ticket de compliance volvió al día siguiente con una X roja junto a ",[22,51,52],{},"AGPL-3.0"," y una nota de legal: ",[55,56,57],"em",{},"\"No se puede enlazar en productos cerrados distribuibles. Adquirir licencia comercial o eliminar.\""," La cotización comercial llegó con una tarifa anual por desarrollador que, para un equipo de doce, hizo que todos reabrieran los resultados de búsqueda.",[19,60,61,62,65,66,69,70,73],{},"Esta es la parte de unipdf que no aparece en el README. unipdf es técnicamente excelente — maduro, completo, bien mantenido. También es de ",[22,63,64],{},"doble licencia",": ",[22,67,68],{},"AGPL v3"," para uso abierto, ",[22,71,72],{},"comercial de pago"," para todo lo demás. AGPL v3 es uno de los copylefts más fuertes en uso común. Si enlazas unipdf en un servicio al que los usuarios acceden por red, el §13 te obliga a publicar el código fuente correspondiente completo. La mayoría de los abogados de empresa dice no.",[19,75,76],{},"Si tienes una base de código en unipdf y la licencia te mordió en una auditoría o está por renovarse, esta es la guía de migración. Si recién empiezas y agarraste unipdf de reflejo porque su documentación era la más pulida, esta es la alternativa que no incluye una relación de facturación.",[14,78,80],{"id":79},"qué-significa-agpl-o-de-pago-en-la-práctica","Qué significa \"AGPL o de pago\" en la práctica",[19,82,83],{},"Muchas bibliotecas Go llevan la etiqueta \"AGPL\" sin que el equipo piense de verdad lo que implica. unipdf no es de esos. El archivo de licencia del repositorio es AGPL v3 puro, el README es explícito en que el uso comercial requiere una clave, y el binario mismo lo refuerza — llama a cualquier API de unipdf sin registrar una licencia al inicio y obtienes un error o una marca de agua en cada página.",[19,85,86],{},"Hay aproximadamente tres modos en los que puedes estar:",[88,89,90,97,103],"ol",{},[91,92,93,96],"li",{},[22,94,95],{},"Modo AGPL."," Publicas tu código bajo AGPL v3. Cada byte de tu servicio que toque unipdf, más todo lo que lo enlace, debe estar disponible para cualquiera que interactúe con el servicio por la red. Para la mayor parte de las herramientas internas y productos SaaS, no es viable.",[91,98,99,102],{},[22,100,101],{},"Modo comercial."," Pagas a UniDoc por desarrollador por año. Los precios varían — las cotizaciones públicas recientes rondan los cuatro dígitos por asiento al año — e incluyen una llamada de registro (medida o por clave) que cada binario debe hacer al arrancar. La clave se trata como secreto, así que vive en tu gestor de secretos y se inyecta en cada contenedor.",[91,104,105,108],{},[22,106,107],{},"Modo trial / evaluación."," Gratis por tiempo limitado. La salida lleva marca de agua. Inviable en producción.",[19,110,111],{},"Ninguno de estos modos es intrínsecamente malo. UniDoc es una empresa real con ingenieros reales, y el precio refleja lo que cuesta construir y mantener una biblioteca PDF completa. El punto es que la decisión de licencia se mete en cada capa: revisión legal, rotación de secretos, renovación financiera y la superficie de despliegue (cada contenedor necesita la clave). gpdf elimina esa columna entera de tu hoja de cálculo al ser MIT.",[14,113,115],{"id":114},"qué-pierdes-y-qué-conservas","Qué pierdes y qué conservas",[19,117,118],{},"Vale ser honesto antes de entrar a la API. unipdf hace cosas que gpdf no:",[120,121,122,137],"table",{},[123,124,125],"thead",{},[126,127,128,132,135],"tr",{},[129,130,131],"th",{},"Capacidad",[129,133,134],{},"unipdf",[129,136,24],{},[138,139,140,151,161,171,181,190,200,210,220,229,238],"tbody",{},[126,141,142,146,149],{},[143,144,145],"td",{},"Generación de PDF",[143,147,148],{},"✅",[143,150,148],{},[126,152,153,156,158],{},[143,154,155],{},"TrueType / fuentes CJK",[143,157,148],{},[143,159,160],{},"✅ (sin CGO, subset automático)",[126,162,163,166,168],{},[143,164,165],{},"Cifrado AES-128/256",[143,167,148],{},[143,169,170],{},"✅ (ISO 32000-2 Rev 6, Go puro)",[126,172,173,176,178],{},[143,174,175],{},"Firma PKCS#7 / PAdES",[143,177,148],{},[143,179,180],{},"✅ (soporte RFC 3161 TSA)",[126,182,183,186,188],{},[143,184,185],{},"PDF/A-1b/2b",[143,187,148],{},[143,189,148],{},[126,191,192,195,197],{},[143,193,194],{},"AcroForm — rellenar existentes",[143,196,148],{},[143,198,199],{},"✅ (solo aplanado, no creación nueva)",[126,201,202,205,207],{},[143,203,204],{},"AcroForm — crear nuevos campos",[143,206,148],{},[143,208,209],{},"❌",[126,211,212,215,217],{},[143,213,214],{},"Parsing / extracción de texto",[143,216,148],{},[143,218,219],{},"❌ (gpdf se enfoca en generación)",[126,221,222,225,227],{},[143,223,224],{},"OCR",[143,226,148],{},[143,228,209],{},[126,230,231,234,236],{},[143,232,233],{},"Redacción (tachado)",[143,235,148],{},[143,237,209],{},[126,239,240,243,246],{},[143,241,242],{},"Render HTML",[143,244,245],{},"parcial",[143,247,248],{},"❌ (usa un renderer aparte y luego merge)",[19,250,251,252,255],{},"Si necesitas parsing de PDF, OCR o redacción, esta migración no te lleva hasta el final. O dejas unipdf solo en esos caminos de código (seguirás debiendo licencia comercial para esos binarios) o eliges una biblioteca centrada en parsing para el lado de lectura. Para el camino de ",[22,253,254],{},"generación, cifrado, firma, fuentes y CJK"," — que es para lo que en realidad se pagan la mayoría de las facturas de unipdf — gpdf es un reemplazo completo.",[14,257,259],{"id":258},"eliminar-el-código-de-registro-de-licencia","Eliminar el código de registro de licencia",[19,261,262],{},"Es el diff más pequeño de toda la migración y el que hace sentir real al resto. Los binarios unipdf deben registrar una clave al arranque. Hay un par de variantes:",[264,265,270],"pre",{"className":266,"code":267,"language":268,"meta":269,"style":269},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","// API key (medida)\nimport \"github.com/unidoc/unipdf/v3/common/license\"\n\nfunc init() {\n    if err := license.SetMeteredKey(os.Getenv(\"UNIDOC_API_KEY\")); err != nil {\n        log.Fatal(err)\n    }\n}\n","go","",[35,271,272,281,299,306,322,379,398,404],{"__ignoreMap":269},[273,274,277],"span",{"class":275,"line":276},"line",1,[273,278,280],{"class":279},"sHwdD","// API key (medida)\n",[273,282,284,288,292,296],{"class":275,"line":283},2,[273,285,287],{"class":286},"s7zQu","import",[273,289,291],{"class":290},"sMK4o"," \"",[273,293,295],{"class":294},"sBMFI","github.com/unidoc/unipdf/v3/common/license",[273,297,298],{"class":290},"\"\n",[273,300,302],{"class":275,"line":301},3,[273,303,305],{"emptyLinePlaceholder":304},true,"\n",[273,307,309,312,316,319],{"class":275,"line":308},4,[273,310,311],{"class":290},"func",[273,313,315],{"class":314},"s2Zo4"," init",[273,317,318],{"class":290},"()",[273,320,321],{"class":290}," {\n",[273,323,325,328,332,335,338,341,344,347,350,352,355,357,360,364,366,369,371,374,377],{"class":275,"line":324},5,[273,326,327],{"class":286},"    if",[273,329,331],{"class":330},"sTEyZ"," err ",[273,333,334],{"class":290},":=",[273,336,337],{"class":330}," license",[273,339,340],{"class":290},".",[273,342,343],{"class":314},"SetMeteredKey",[273,345,346],{"class":290},"(",[273,348,349],{"class":330},"os",[273,351,340],{"class":290},[273,353,354],{"class":314},"Getenv",[273,356,346],{"class":290},[273,358,359],{"class":290},"\"",[273,361,363],{"class":362},"sfazB","UNIDOC_API_KEY",[273,365,359],{"class":290},[273,367,368],{"class":290},"));",[273,370,331],{"class":330},[273,372,373],{"class":290},"!=",[273,375,376],{"class":290}," nil",[273,378,321],{"class":290},[273,380,382,385,387,390,392,395],{"class":275,"line":381},6,[273,383,384],{"class":330},"        log",[273,386,340],{"class":290},[273,388,389],{"class":314},"Fatal",[273,391,346],{"class":290},[273,393,394],{"class":330},"err",[273,396,397],{"class":290},")\n",[273,399,401],{"class":275,"line":400},7,[273,402,403],{"class":290},"    }\n",[273,405,407],{"class":275,"line":406},8,[273,408,409],{"class":290},"}\n",[264,411,413],{"className":266,"code":412,"language":268,"meta":269,"style":269},"// Archivo de licencia offline\nfunc init() {\n    licenseKey, _ := os.ReadFile(\"/etc/unidoc/license.txt\")\n    if err := license.SetLicenseKey(string(licenseKey), \"Acme Corp\"); err != nil {\n        log.Fatal(err)\n    }\n}\n",[35,414,415,420,430,462,509,523,527],{"__ignoreMap":269},[273,416,417],{"class":275,"line":276},[273,418,419],{"class":279},"// Archivo de licencia offline\n",[273,421,422,424,426,428],{"class":275,"line":283},[273,423,311],{"class":290},[273,425,315],{"class":314},[273,427,318],{"class":290},[273,429,321],{"class":290},[273,431,432,435,438,441,443,446,448,451,453,455,458,460],{"class":275,"line":301},[273,433,434],{"class":330},"    licenseKey",[273,436,437],{"class":290},",",[273,439,440],{"class":330}," _ ",[273,442,334],{"class":290},[273,444,445],{"class":330}," os",[273,447,340],{"class":290},[273,449,450],{"class":314},"ReadFile",[273,452,346],{"class":290},[273,454,359],{"class":290},[273,456,457],{"class":362},"/etc/unidoc/license.txt",[273,459,359],{"class":290},[273,461,397],{"class":290},[273,463,464,466,468,470,472,474,477,479,483,485,488,491,493,496,498,501,503,505,507],{"class":275,"line":308},[273,465,327],{"class":286},[273,467,331],{"class":330},[273,469,334],{"class":290},[273,471,337],{"class":330},[273,473,340],{"class":290},[273,475,476],{"class":314},"SetLicenseKey",[273,478,346],{"class":290},[273,480,482],{"class":481},"spNyl","string",[273,484,346],{"class":290},[273,486,487],{"class":330},"licenseKey",[273,489,490],{"class":290},"),",[273,492,291],{"class":290},[273,494,495],{"class":362},"Acme Corp",[273,497,359],{"class":290},[273,499,500],{"class":290},");",[273,502,331],{"class":330},[273,504,373],{"class":290},[273,506,376],{"class":290},[273,508,321],{"class":290},[273,510,511,513,515,517,519,521],{"class":275,"line":324},[273,512,384],{"class":330},[273,514,340],{"class":290},[273,516,389],{"class":314},[273,518,346],{"class":290},[273,520,394],{"class":330},[273,522,397],{"class":290},[273,524,525],{"class":275,"line":381},[273,526,403],{"class":290},[273,528,529],{"class":275,"line":400},[273,530,409],{"class":290},[19,532,533,534,537,538,540,541,544,545,548],{},"En gpdf no hay equivalente. Borra el bloque ",[35,535,536],{},"init()"," entero. Saca ",[35,539,363],{}," de tu gestor de secretos, de tus variables de CI y de los manifiestos de contenedor. Quita el archivo de licencia de tu imagen. Lo único que importas es ",[35,542,543],{},"github.com/gpdf-dev/gpdf",", y lo único que requiere es que llames a ",[35,546,547],{},"gpdf.NewDocument"," en algún lugar.",[19,550,551,552,555],{},"Eso es todo. Es también el test de si tu migración aterrizó: ",[35,553,554],{},"grep -r unidoc ."," debe devolver cero coincidencias cuando termines.",[14,557,559],{"id":558},"tabla-de-mapeo-de-la-api","Tabla de mapeo de la API",[19,561,562,563,566,567,570],{},"La tabla es la chuleta. Las secciones siguientes recorren cinco pares concretos. unipdf llama ",[35,564,565],{},"Creator"," al builder de alto nivel; gpdf lo llama ",[35,568,569],{},"Document",". Las formas son lo bastante similares como para que la mayoría del código se traduzca por inspección.",[120,572,573,588],{},[123,574,575],{},[126,576,577,580,586],{},[129,578,579],{},"Lo que quieres hacer",[129,581,582,583,585],{},"unipdf (",[35,584,41],{},")",[129,587,24],{},[138,589,590,605,620,635,654,672,690,706,721,736,751,773,795,815,830,848,863],{},[126,591,592,595,600],{},[143,593,594],{},"Crear un builder",[143,596,597],{},[35,598,599],{},"c := creator.New(); c.SetPageSize(creator.PageSizeA4)",[143,601,602],{},[35,603,604],{},"doc := gpdf.NewDocument(gpdf.WithPageSize(document.A4))",[126,606,607,610,615],{},[143,608,609],{},"Configurar márgenes",[143,611,612],{},[35,613,614],{},"c.SetPageMargins(L, R, T, B)",[143,616,617],{},[35,618,619],{},"gpdf.WithMargins(document.UniformEdges(document.Mm(20)))",[126,621,622,625,630],{},[143,623,624],{},"Nueva página",[143,626,627],{},[35,628,629],{},"c.NewPage()",[143,631,632],{},[35,633,634],{},"page := doc.AddPage()",[126,636,637,640,645],{},[143,638,639],{},"Una línea de texto",[143,641,642],{},[35,643,644],{},"p := c.NewParagraph(\"hi\"); c.Draw(p)",[143,646,647,650,651],{},[35,648,649],{},"c.Text(\"hi\")"," ",[55,652,653],{},"(dentro de una columna)",[126,655,656,659,664],{},[143,657,658],{},"Texto con salto de línea",[143,660,661],{},[35,662,663],{},"p := c.NewStyledParagraph(); p.SetText(...); c.Draw(p)",[143,665,666,650,669],{},[35,667,668],{},"c.Text(body)",[55,670,671],{},"(salto automático)",[126,673,674,677,682],{},[143,675,676],{},"Registro de fuente",[143,678,679],{},[35,680,681],{},"model.NewCompositePdfFontFromTTFFile(path)",[143,683,684,650,687],{},[35,685,686],{},"gpdf.WithFont(\"Name\", ttfBytes)",[55,688,689],{},"(en construcción)",[126,691,692,695,700],{},[143,693,694],{},"Asignar fuente al texto",[143,696,697],{},[35,698,699],{},"style.Font = font; style.FontSize = 12",[143,701,702,705],{},[35,703,704],{},"template.FontFamily(\"Name\"), template.FontSize(12)"," por-texto",[126,707,708,711,716],{},[143,709,710],{},"Color",[143,712,713],{},[35,714,715],{},"style.Color = creator.ColorRGBFromHex(\"#1A237E\")",[143,717,718],{},[35,719,720],{},"template.TextColor(pdf.RGBHex(0x1A237E))",[126,722,723,726,731],{},[143,724,725],{},"Tabla",[143,727,728],{},[35,729,730],{},"t := c.NewTable(4); t.SetColumnWidths(...); c.Draw(t)",[143,732,733],{},[35,734,735],{},"c.Table(headers, rows, template.ColumnWidths(...))",[126,737,738,741,746],{},[143,739,740],{},"Imagen",[143,742,743],{},[35,744,745],{},"img, _ := c.NewImageFromFile(path); img.ScaleToWidth(w); c.Draw(img)",[143,747,748],{},[35,749,750],{},"c.Image(imgBytes, template.FitWidth(document.Mm(50)))",[126,752,753,756,765],{},[143,754,755],{},"Encabezado / pie",[143,757,758,761,762],{},[35,759,760],{},"c.DrawHeader(fn)"," / ",[35,763,764],{},"c.DrawFooter(fn)",[143,766,767,761,770],{},[35,768,769],{},"doc.Header(fn)",[35,771,772],{},"doc.Footer(fn)",[126,774,775,778,784],{},[143,776,777],{},"Número de página",[143,779,780,781],{},"manual desde los args de ",[35,782,783],{},"DrawFooter",[143,785,786,761,789,650,792],{},[35,787,788],{},"c.PageNumber()",[35,790,791],{},"c.TotalPages()",[55,793,794],{},"(placeholders)",[126,796,797,800,810],{},[143,798,799],{},"Cifrado",[143,801,802,805,806,809],{},[35,803,804],{},"model.PdfWriter"," + ",[35,807,808],{},"Encrypt"," re-encoding",[143,811,812],{},[35,813,814],{},"gpdf.WithEncryption(gpdf.AES256, \"user\", \"owner\", perms)",[126,816,817,820,825],{},[143,818,819],{},"Firma",[143,821,822],{},[35,823,824],{},"model.NewPdfAppender(...).Sign(...)",[143,826,827],{},[35,828,829],{},"gpdf.SignDocument(pdfBytes, signer, opts)",[126,831,832,835,843],{},[143,833,834],{},"Registro de licencia",[143,836,837,840,841],{},[35,838,839],{},"license.SetMeteredKey(...)"," en ",[35,842,536],{},[143,844,845],{},[55,846,847],{},"(ninguno — bórralo)",[126,849,850,853,858],{},[143,851,852],{},"Salida a archivo",[143,854,855],{},[35,856,857],{},"c.WriteToFile(\"out.pdf\")",[143,859,860],{},[35,861,862],{},"data, _ := doc.Generate(); os.WriteFile(\"out.pdf\", data, 0o644)",[126,864,865,868,873],{},[143,866,867],{},"Salida a writer",[143,869,870],{},[35,871,872],{},"c.Write(w)",[143,874,875],{},[35,876,877],{},"doc.Render(w)",[19,879,880,881,884,885,888,889,892,893,896,897,900,901,904,905,908],{},"Dos cambios estructurales para tener en mente. El creator de unipdf es ",[22,882,883],{},"con estado",": construyes un ",[35,886,887],{},"Paragraph"," o una ",[35,890,891],{},"Table"," y luego llamas a ",[35,894,895],{},"c.Draw(thing)"," para confirmarlo. gpdf es ",[22,898,899],{},"declarativo",": describes un árbol de filas y columnas y dejas al motor de layout colocarlas. El segundo cambio es que gpdf tiene una ",[22,902,903],{},"rejilla de 12 columnas"," como Bootstrap. Cada fila tiene implícitamente 12 unidades de ancho; las gastas con ",[35,906,907],{},"r.Col(n, fn)",". La mayoría de los layouts colapsan a dos o tres líneas en cuanto dejas de medir anchos en milímetros.",[14,910,912],{"id":911},"antes-después-1-el-pdf-más-pequeño-posible","Antes / Después 1: el PDF más pequeño posible",[19,914,915],{},"El par \"hola mundo\". La versión de unipdf no es larga; solo tiene más ceremonia por la llamada de licencia.",[19,917,918],{},[22,919,920],{},"Antes — unipdf:",[264,922,924],{"className":266,"code":923,"language":268,"meta":269,"style":269},"package main\n\nimport (\n    \"log\"\n    \"os\"\n\n    \"github.com/unidoc/unipdf/v3/common/license\"\n    \"github.com/unidoc/unipdf/v3/creator\"\n)\n\nfunc init() {\n    if err := license.SetMeteredKey(os.Getenv(\"UNIDOC_API_KEY\")); err != nil {\n        log.Fatal(err)\n    }\n}\n\nfunc main() {\n    c := creator.New()\n    c.SetPageSize(creator.PageSizeA4)\n\n    p := c.NewParagraph(\"Hello, World!\")\n    p.SetFontSize(24)\n    if err := c.Draw(p); err != nil {\n        log.Fatal(err)\n    }\n\n    if err := c.WriteToFile(\"hello.pdf\"); err != nil {\n        log.Fatal(err)\n    }\n}\n",[35,925,926,934,938,945,955,963,967,975,984,989,994,1005,1046,1061,1066,1071,1076,1088,1107,1129,1134,1161,1180,1210,1225,1230,1235,1270,1285,1290],{"__ignoreMap":269},[273,927,928,931],{"class":275,"line":276},[273,929,930],{"class":290},"package",[273,932,933],{"class":294}," main\n",[273,935,936],{"class":275,"line":283},[273,937,305],{"emptyLinePlaceholder":304},[273,939,940,942],{"class":275,"line":301},[273,941,287],{"class":286},[273,943,944],{"class":290}," (\n",[273,946,947,950,953],{"class":275,"line":308},[273,948,949],{"class":290},"    \"",[273,951,952],{"class":294},"log",[273,954,298],{"class":290},[273,956,957,959,961],{"class":275,"line":324},[273,958,949],{"class":290},[273,960,349],{"class":294},[273,962,298],{"class":290},[273,964,965],{"class":275,"line":381},[273,966,305],{"emptyLinePlaceholder":304},[273,968,969,971,973],{"class":275,"line":400},[273,970,949],{"class":290},[273,972,295],{"class":294},[273,974,298],{"class":290},[273,976,977,979,982],{"class":275,"line":406},[273,978,949],{"class":290},[273,980,981],{"class":294},"github.com/unidoc/unipdf/v3/creator",[273,983,298],{"class":290},[273,985,987],{"class":275,"line":986},9,[273,988,397],{"class":290},[273,990,992],{"class":275,"line":991},10,[273,993,305],{"emptyLinePlaceholder":304},[273,995,997,999,1001,1003],{"class":275,"line":996},11,[273,998,311],{"class":290},[273,1000,315],{"class":314},[273,1002,318],{"class":290},[273,1004,321],{"class":290},[273,1006,1008,1010,1012,1014,1016,1018,1020,1022,1024,1026,1028,1030,1032,1034,1036,1038,1040,1042,1044],{"class":275,"line":1007},12,[273,1009,327],{"class":286},[273,1011,331],{"class":330},[273,1013,334],{"class":290},[273,1015,337],{"class":330},[273,1017,340],{"class":290},[273,1019,343],{"class":314},[273,1021,346],{"class":290},[273,1023,349],{"class":330},[273,1025,340],{"class":290},[273,1027,354],{"class":314},[273,1029,346],{"class":290},[273,1031,359],{"class":290},[273,1033,363],{"class":362},[273,1035,359],{"class":290},[273,1037,368],{"class":290},[273,1039,331],{"class":330},[273,1041,373],{"class":290},[273,1043,376],{"class":290},[273,1045,321],{"class":290},[273,1047,1049,1051,1053,1055,1057,1059],{"class":275,"line":1048},13,[273,1050,384],{"class":330},[273,1052,340],{"class":290},[273,1054,389],{"class":314},[273,1056,346],{"class":290},[273,1058,394],{"class":330},[273,1060,397],{"class":290},[273,1062,1064],{"class":275,"line":1063},14,[273,1065,403],{"class":290},[273,1067,1069],{"class":275,"line":1068},15,[273,1070,409],{"class":290},[273,1072,1074],{"class":275,"line":1073},16,[273,1075,305],{"emptyLinePlaceholder":304},[273,1077,1079,1081,1084,1086],{"class":275,"line":1078},17,[273,1080,311],{"class":290},[273,1082,1083],{"class":314}," main",[273,1085,318],{"class":290},[273,1087,321],{"class":290},[273,1089,1091,1094,1096,1099,1101,1104],{"class":275,"line":1090},18,[273,1092,1093],{"class":330},"    c ",[273,1095,334],{"class":290},[273,1097,1098],{"class":330}," creator",[273,1100,340],{"class":290},[273,1102,1103],{"class":314},"New",[273,1105,1106],{"class":290},"()\n",[273,1108,1110,1113,1115,1118,1120,1122,1124,1127],{"class":275,"line":1109},19,[273,1111,1112],{"class":330},"    c",[273,1114,340],{"class":290},[273,1116,1117],{"class":314},"SetPageSize",[273,1119,346],{"class":290},[273,1121,41],{"class":330},[273,1123,340],{"class":290},[273,1125,1126],{"class":330},"PageSizeA4",[273,1128,397],{"class":290},[273,1130,1132],{"class":275,"line":1131},20,[273,1133,305],{"emptyLinePlaceholder":304},[273,1135,1137,1140,1142,1145,1147,1150,1152,1154,1157,1159],{"class":275,"line":1136},21,[273,1138,1139],{"class":330},"    p ",[273,1141,334],{"class":290},[273,1143,1144],{"class":330}," c",[273,1146,340],{"class":290},[273,1148,1149],{"class":314},"NewParagraph",[273,1151,346],{"class":290},[273,1153,359],{"class":290},[273,1155,1156],{"class":362},"Hello, World!",[273,1158,359],{"class":290},[273,1160,397],{"class":290},[273,1162,1164,1167,1169,1172,1174,1178],{"class":275,"line":1163},22,[273,1165,1166],{"class":330},"    p",[273,1168,340],{"class":290},[273,1170,1171],{"class":314},"SetFontSize",[273,1173,346],{"class":290},[273,1175,1177],{"class":1176},"sbssI","24",[273,1179,397],{"class":290},[273,1181,1183,1185,1187,1189,1191,1193,1196,1198,1200,1202,1204,1206,1208],{"class":275,"line":1182},23,[273,1184,327],{"class":286},[273,1186,331],{"class":330},[273,1188,334],{"class":290},[273,1190,1144],{"class":330},[273,1192,340],{"class":290},[273,1194,1195],{"class":314},"Draw",[273,1197,346],{"class":290},[273,1199,19],{"class":330},[273,1201,500],{"class":290},[273,1203,331],{"class":330},[273,1205,373],{"class":290},[273,1207,376],{"class":290},[273,1209,321],{"class":290},[273,1211,1213,1215,1217,1219,1221,1223],{"class":275,"line":1212},24,[273,1214,384],{"class":330},[273,1216,340],{"class":290},[273,1218,389],{"class":314},[273,1220,346],{"class":290},[273,1222,394],{"class":330},[273,1224,397],{"class":290},[273,1226,1228],{"class":275,"line":1227},25,[273,1229,403],{"class":290},[273,1231,1233],{"class":275,"line":1232},26,[273,1234,305],{"emptyLinePlaceholder":304},[273,1236,1238,1240,1242,1244,1246,1248,1251,1253,1255,1258,1260,1262,1264,1266,1268],{"class":275,"line":1237},27,[273,1239,327],{"class":286},[273,1241,331],{"class":330},[273,1243,334],{"class":290},[273,1245,1144],{"class":330},[273,1247,340],{"class":290},[273,1249,1250],{"class":314},"WriteToFile",[273,1252,346],{"class":290},[273,1254,359],{"class":290},[273,1256,1257],{"class":362},"hello.pdf",[273,1259,359],{"class":290},[273,1261,500],{"class":290},[273,1263,331],{"class":330},[273,1265,373],{"class":290},[273,1267,376],{"class":290},[273,1269,321],{"class":290},[273,1271,1273,1275,1277,1279,1281,1283],{"class":275,"line":1272},28,[273,1274,384],{"class":330},[273,1276,340],{"class":290},[273,1278,389],{"class":314},[273,1280,346],{"class":290},[273,1282,394],{"class":330},[273,1284,397],{"class":290},[273,1286,1288],{"class":275,"line":1287},29,[273,1289,403],{"class":290},[273,1291,1293],{"class":275,"line":1292},30,[273,1294,409],{"class":290},[19,1296,1297],{},[22,1298,1299],{},"Después — gpdf:",[264,1301,1303],{"className":266,"code":1302,"language":268,"meta":269,"style":269},"package main\n\nimport (\n    \"log\"\n    \"os\"\n\n    \"github.com/gpdf-dev/gpdf\"\n    \"github.com/gpdf-dev/gpdf/document\"\n    \"github.com/gpdf-dev/gpdf/template\"\n)\n\nfunc main() {\n    doc := gpdf.NewDocument(\n        gpdf.WithPageSize(document.A4),\n        gpdf.WithMargins(document.UniformEdges(document.Mm(20))),\n    )\n\n    page := doc.AddPage()\n    page.AutoRow(func(r *template.RowBuilder) {\n        r.Col(12, func(c *template.ColBuilder) {\n            c.Text(\"Hello, World!\", template.FontSize(24), template.Bold())\n        })\n    })\n\n    data, err := doc.Generate()\n    if err != nil {\n        log.Fatal(err)\n    }\n    if err := os.WriteFile(\"hello.pdf\", data, 0o644); err != nil {\n        log.Fatal(err)\n    }\n}\n",[35,1304,1305,1311,1315,1321,1329,1337,1341,1349,1358,1367,1371,1375,1385,1403,1426,1461,1466,1470,1487,1519,1555,1599,1604,1609,1613,1633,1645,1659,1663,1706,1720,1725],{"__ignoreMap":269},[273,1306,1307,1309],{"class":275,"line":276},[273,1308,930],{"class":290},[273,1310,933],{"class":294},[273,1312,1313],{"class":275,"line":283},[273,1314,305],{"emptyLinePlaceholder":304},[273,1316,1317,1319],{"class":275,"line":301},[273,1318,287],{"class":286},[273,1320,944],{"class":290},[273,1322,1323,1325,1327],{"class":275,"line":308},[273,1324,949],{"class":290},[273,1326,952],{"class":294},[273,1328,298],{"class":290},[273,1330,1331,1333,1335],{"class":275,"line":324},[273,1332,949],{"class":290},[273,1334,349],{"class":294},[273,1336,298],{"class":290},[273,1338,1339],{"class":275,"line":381},[273,1340,305],{"emptyLinePlaceholder":304},[273,1342,1343,1345,1347],{"class":275,"line":400},[273,1344,949],{"class":290},[273,1346,543],{"class":294},[273,1348,298],{"class":290},[273,1350,1351,1353,1356],{"class":275,"line":406},[273,1352,949],{"class":290},[273,1354,1355],{"class":294},"github.com/gpdf-dev/gpdf/document",[273,1357,298],{"class":290},[273,1359,1360,1362,1365],{"class":275,"line":986},[273,1361,949],{"class":290},[273,1363,1364],{"class":294},"github.com/gpdf-dev/gpdf/template",[273,1366,298],{"class":290},[273,1368,1369],{"class":275,"line":991},[273,1370,397],{"class":290},[273,1372,1373],{"class":275,"line":996},[273,1374,305],{"emptyLinePlaceholder":304},[273,1376,1377,1379,1381,1383],{"class":275,"line":1007},[273,1378,311],{"class":290},[273,1380,1083],{"class":314},[273,1382,318],{"class":290},[273,1384,321],{"class":290},[273,1386,1387,1390,1392,1395,1397,1400],{"class":275,"line":1048},[273,1388,1389],{"class":330},"    doc ",[273,1391,334],{"class":290},[273,1393,1394],{"class":330}," gpdf",[273,1396,340],{"class":290},[273,1398,1399],{"class":314},"NewDocument",[273,1401,1402],{"class":290},"(\n",[273,1404,1405,1408,1410,1413,1415,1418,1420,1423],{"class":275,"line":1063},[273,1406,1407],{"class":330},"        gpdf",[273,1409,340],{"class":290},[273,1411,1412],{"class":314},"WithPageSize",[273,1414,346],{"class":290},[273,1416,1417],{"class":330},"document",[273,1419,340],{"class":290},[273,1421,1422],{"class":330},"A4",[273,1424,1425],{"class":290},"),\n",[273,1427,1428,1430,1432,1435,1437,1439,1441,1444,1446,1448,1450,1453,1455,1458],{"class":275,"line":1068},[273,1429,1407],{"class":330},[273,1431,340],{"class":290},[273,1433,1434],{"class":314},"WithMargins",[273,1436,346],{"class":290},[273,1438,1417],{"class":330},[273,1440,340],{"class":290},[273,1442,1443],{"class":314},"UniformEdges",[273,1445,346],{"class":290},[273,1447,1417],{"class":330},[273,1449,340],{"class":290},[273,1451,1452],{"class":314},"Mm",[273,1454,346],{"class":290},[273,1456,1457],{"class":1176},"20",[273,1459,1460],{"class":290},"))),\n",[273,1462,1463],{"class":275,"line":1073},[273,1464,1465],{"class":290},"    )\n",[273,1467,1468],{"class":275,"line":1078},[273,1469,305],{"emptyLinePlaceholder":304},[273,1471,1472,1475,1477,1480,1482,1485],{"class":275,"line":1090},[273,1473,1474],{"class":330},"    page ",[273,1476,334],{"class":290},[273,1478,1479],{"class":330}," doc",[273,1481,340],{"class":290},[273,1483,1484],{"class":314},"AddPage",[273,1486,1106],{"class":290},[273,1488,1489,1492,1494,1497,1500,1504,1507,1510,1512,1515,1517],{"class":275,"line":1109},[273,1490,1491],{"class":330},"    page",[273,1493,340],{"class":290},[273,1495,1496],{"class":314},"AutoRow",[273,1498,1499],{"class":290},"(func(",[273,1501,1503],{"class":1502},"sHdIc","r",[273,1505,1506],{"class":290}," *",[273,1508,1509],{"class":294},"template",[273,1511,340],{"class":290},[273,1513,1514],{"class":294},"RowBuilder",[273,1516,585],{"class":290},[273,1518,321],{"class":290},[273,1520,1521,1524,1526,1529,1531,1534,1536,1539,1542,1544,1546,1548,1551,1553],{"class":275,"line":1131},[273,1522,1523],{"class":330},"        r",[273,1525,340],{"class":290},[273,1527,1528],{"class":314},"Col",[273,1530,346],{"class":290},[273,1532,1533],{"class":1176},"12",[273,1535,437],{"class":290},[273,1537,1538],{"class":290}," func(",[273,1540,1541],{"class":1502},"c",[273,1543,1506],{"class":290},[273,1545,1509],{"class":294},[273,1547,340],{"class":290},[273,1549,1550],{"class":294},"ColBuilder",[273,1552,585],{"class":290},[273,1554,321],{"class":290},[273,1556,1557,1560,1562,1565,1567,1569,1571,1573,1575,1578,1580,1583,1585,1587,1589,1591,1593,1596],{"class":275,"line":1136},[273,1558,1559],{"class":330},"            c",[273,1561,340],{"class":290},[273,1563,1564],{"class":314},"Text",[273,1566,346],{"class":290},[273,1568,359],{"class":290},[273,1570,1156],{"class":362},[273,1572,359],{"class":290},[273,1574,437],{"class":290},[273,1576,1577],{"class":330}," template",[273,1579,340],{"class":290},[273,1581,1582],{"class":314},"FontSize",[273,1584,346],{"class":290},[273,1586,1177],{"class":1176},[273,1588,490],{"class":290},[273,1590,1577],{"class":330},[273,1592,340],{"class":290},[273,1594,1595],{"class":314},"Bold",[273,1597,1598],{"class":290},"())\n",[273,1600,1601],{"class":275,"line":1163},[273,1602,1603],{"class":290},"        })\n",[273,1605,1606],{"class":275,"line":1182},[273,1607,1608],{"class":290},"    })\n",[273,1610,1611],{"class":275,"line":1212},[273,1612,305],{"emptyLinePlaceholder":304},[273,1614,1615,1618,1620,1622,1624,1626,1628,1631],{"class":275,"line":1227},[273,1616,1617],{"class":330},"    data",[273,1619,437],{"class":290},[273,1621,331],{"class":330},[273,1623,334],{"class":290},[273,1625,1479],{"class":330},[273,1627,340],{"class":290},[273,1629,1630],{"class":314},"Generate",[273,1632,1106],{"class":290},[273,1634,1635,1637,1639,1641,1643],{"class":275,"line":1232},[273,1636,327],{"class":286},[273,1638,331],{"class":330},[273,1640,373],{"class":290},[273,1642,376],{"class":290},[273,1644,321],{"class":290},[273,1646,1647,1649,1651,1653,1655,1657],{"class":275,"line":1237},[273,1648,384],{"class":330},[273,1650,340],{"class":290},[273,1652,389],{"class":314},[273,1654,346],{"class":290},[273,1656,394],{"class":330},[273,1658,397],{"class":290},[273,1660,1661],{"class":275,"line":1272},[273,1662,403],{"class":290},[273,1664,1665,1667,1669,1671,1673,1675,1678,1680,1682,1684,1686,1688,1691,1693,1696,1698,1700,1702,1704],{"class":275,"line":1287},[273,1666,327],{"class":286},[273,1668,331],{"class":330},[273,1670,334],{"class":290},[273,1672,445],{"class":330},[273,1674,340],{"class":290},[273,1676,1677],{"class":314},"WriteFile",[273,1679,346],{"class":290},[273,1681,359],{"class":290},[273,1683,1257],{"class":362},[273,1685,359],{"class":290},[273,1687,437],{"class":290},[273,1689,1690],{"class":330}," data",[273,1692,437],{"class":290},[273,1694,1695],{"class":1176}," 0o644",[273,1697,500],{"class":290},[273,1699,331],{"class":330},[273,1701,373],{"class":290},[273,1703,376],{"class":290},[273,1705,321],{"class":290},[273,1707,1708,1710,1712,1714,1716,1718],{"class":275,"line":1292},[273,1709,384],{"class":330},[273,1711,340],{"class":290},[273,1713,389],{"class":314},[273,1715,346],{"class":290},[273,1717,394],{"class":330},[273,1719,397],{"class":290},[273,1721,1723],{"class":275,"line":1722},31,[273,1724,403],{"class":290},[273,1726,1728],{"class":275,"line":1727},32,[273,1729,409],{"class":290},[19,1731,1732,1733,1735,1736,1738],{},"Tres cosas para notar. El bloque ",[35,1734,536],{}," ya no está — sin clave, sin variable de entorno. La construcción usa opciones en vez de mutar el builder. El texto vive dentro de una fila y columna en lugar de ser un ",[35,1737,887],{}," libre que dibujas después. La rejilla hace la colocación; tú no eliges coordenadas.",[14,1740,1742],{"id":1741},"antes-después-2-tabla-de-partidas-de-una-factura","Antes / Después 2: tabla de partidas de una factura",[19,1744,1745,1746,1748,1749,1752,1753,761,1756,1759],{},"Las tablas son donde la API creator de unipdf se alarga. Construyes una ",[35,1747,891],{},", llamas a ",[35,1750,1751],{},"SetColumnWidths"," con fracciones absolutas, armas celdas una por una con ",[35,1754,1755],{},"NewCell",[35,1757,1758],{},"SetContent",", y configuras los bordes y la alineación de cada celda a mano.",[19,1761,1762],{},[22,1763,920],{},[264,1765,1767],{"className":266,"code":1766,"language":268,"meta":269,"style":269},"table := c.NewTable(4)\ntable.SetColumnWidths(0.5, 0.15, 0.15, 0.2)\n\nheaderStyle := c.NewTextStyle()\nheaderStyle.Font, _ = model.NewStandard14Font(\"Helvetica-Bold\")\nheaderStyle.FontSize = 11\nheaderStyle.Color = creator.ColorWhite\n\ndrawHeaderCell := func(text string) {\n    cell := table.NewCell()\n    cell.SetBackgroundColor(creator.ColorRGBFromHex(\"#1A237E\"))\n    cell.SetBorder(creator.CellBorderSideAll, creator.CellBorderStyleSingle, 0.5)\n\n    p := c.NewStyledParagraph()\n    chunk := p.Append(text)\n    chunk.Style = headerStyle\n    cell.SetContent(p)\n}\n\nfor _, h := range []string{\"Concepto\", \"Cant.\", \"Precio\", \"Importe\"} {\n    drawHeaderCell(h)\n}\n\nfor _, row := range items {\n    for _, cellText := range row {\n        cell := table.NewCell()\n        cell.SetBorder(creator.CellBorderSideAll, creator.CellBorderStyleSingle, 0.3)\n\n        p := c.NewParagraph(cellText)\n        p.SetFontSize(11)\n        cell.SetContent(p)\n    }\n}\n\nif err := c.Draw(table); err != nil {\n    log.Fatal(err)\n}\n",[35,1768,1769,1790,1819,1823,1839,1875,1889,1907,1911,1930,1946,1977,2011,2015,2030,2051,2066,2080,2084,2088,2153,2165,2169,2173,2194,2214,2229,2261,2265,2285,2301,2315,2319,2324,2329,2359,2375],{"__ignoreMap":269},[273,1770,1771,1774,1776,1778,1780,1783,1785,1788],{"class":275,"line":276},[273,1772,1773],{"class":330},"table ",[273,1775,334],{"class":290},[273,1777,1144],{"class":330},[273,1779,340],{"class":290},[273,1781,1782],{"class":314},"NewTable",[273,1784,346],{"class":290},[273,1786,1787],{"class":1176},"4",[273,1789,397],{"class":290},[273,1791,1792,1794,1796,1798,1800,1803,1805,1808,1810,1812,1814,1817],{"class":275,"line":283},[273,1793,120],{"class":330},[273,1795,340],{"class":290},[273,1797,1751],{"class":314},[273,1799,346],{"class":290},[273,1801,1802],{"class":1176},"0.5",[273,1804,437],{"class":290},[273,1806,1807],{"class":1176}," 0.15",[273,1809,437],{"class":290},[273,1811,1807],{"class":1176},[273,1813,437],{"class":290},[273,1815,1816],{"class":1176}," 0.2",[273,1818,397],{"class":290},[273,1820,1821],{"class":275,"line":301},[273,1822,305],{"emptyLinePlaceholder":304},[273,1824,1825,1828,1830,1832,1834,1837],{"class":275,"line":308},[273,1826,1827],{"class":330},"headerStyle ",[273,1829,334],{"class":290},[273,1831,1144],{"class":330},[273,1833,340],{"class":290},[273,1835,1836],{"class":314},"NewTextStyle",[273,1838,1106],{"class":290},[273,1840,1841,1844,1846,1849,1851,1853,1856,1859,1861,1864,1866,1868,1871,1873],{"class":275,"line":324},[273,1842,1843],{"class":330},"headerStyle",[273,1845,340],{"class":290},[273,1847,1848],{"class":330},"Font",[273,1850,437],{"class":290},[273,1852,440],{"class":330},[273,1854,1855],{"class":290},"=",[273,1857,1858],{"class":330}," model",[273,1860,340],{"class":290},[273,1862,1863],{"class":314},"NewStandard14Font",[273,1865,346],{"class":290},[273,1867,359],{"class":290},[273,1869,1870],{"class":362},"Helvetica-Bold",[273,1872,359],{"class":290},[273,1874,397],{"class":290},[273,1876,1877,1879,1881,1884,1886],{"class":275,"line":381},[273,1878,1843],{"class":330},[273,1880,340],{"class":290},[273,1882,1883],{"class":330},"FontSize ",[273,1885,1855],{"class":290},[273,1887,1888],{"class":1176}," 11\n",[273,1890,1891,1893,1895,1898,1900,1902,1904],{"class":275,"line":400},[273,1892,1843],{"class":330},[273,1894,340],{"class":290},[273,1896,1897],{"class":330},"Color ",[273,1899,1855],{"class":290},[273,1901,1098],{"class":330},[273,1903,340],{"class":290},[273,1905,1906],{"class":330},"ColorWhite\n",[273,1908,1909],{"class":275,"line":406},[273,1910,305],{"emptyLinePlaceholder":304},[273,1912,1913,1916,1918,1920,1923,1926,1928],{"class":275,"line":986},[273,1914,1915],{"class":330},"drawHeaderCell ",[273,1917,334],{"class":290},[273,1919,1538],{"class":290},[273,1921,1922],{"class":1502},"text",[273,1924,1925],{"class":481}," string",[273,1927,585],{"class":290},[273,1929,321],{"class":290},[273,1931,1932,1935,1937,1940,1942,1944],{"class":275,"line":991},[273,1933,1934],{"class":330},"    cell ",[273,1936,334],{"class":290},[273,1938,1939],{"class":330}," table",[273,1941,340],{"class":290},[273,1943,1755],{"class":314},[273,1945,1106],{"class":290},[273,1947,1948,1951,1953,1956,1958,1960,1962,1965,1967,1969,1972,1974],{"class":275,"line":996},[273,1949,1950],{"class":330},"    cell",[273,1952,340],{"class":290},[273,1954,1955],{"class":314},"SetBackgroundColor",[273,1957,346],{"class":290},[273,1959,41],{"class":330},[273,1961,340],{"class":290},[273,1963,1964],{"class":314},"ColorRGBFromHex",[273,1966,346],{"class":290},[273,1968,359],{"class":290},[273,1970,1971],{"class":362},"#1A237E",[273,1973,359],{"class":290},[273,1975,1976],{"class":290},"))\n",[273,1978,1979,1981,1983,1986,1988,1990,1992,1995,1997,1999,2001,2004,2006,2009],{"class":275,"line":1007},[273,1980,1950],{"class":330},[273,1982,340],{"class":290},[273,1984,1985],{"class":314},"SetBorder",[273,1987,346],{"class":290},[273,1989,41],{"class":330},[273,1991,340],{"class":290},[273,1993,1994],{"class":330},"CellBorderSideAll",[273,1996,437],{"class":290},[273,1998,1098],{"class":330},[273,2000,340],{"class":290},[273,2002,2003],{"class":330},"CellBorderStyleSingle",[273,2005,437],{"class":290},[273,2007,2008],{"class":1176}," 0.5",[273,2010,397],{"class":290},[273,2012,2013],{"class":275,"line":1048},[273,2014,305],{"emptyLinePlaceholder":304},[273,2016,2017,2019,2021,2023,2025,2028],{"class":275,"line":1063},[273,2018,1139],{"class":330},[273,2020,334],{"class":290},[273,2022,1144],{"class":330},[273,2024,340],{"class":290},[273,2026,2027],{"class":314},"NewStyledParagraph",[273,2029,1106],{"class":290},[273,2031,2032,2035,2037,2040,2042,2045,2047,2049],{"class":275,"line":1068},[273,2033,2034],{"class":330},"    chunk ",[273,2036,334],{"class":290},[273,2038,2039],{"class":330}," p",[273,2041,340],{"class":290},[273,2043,2044],{"class":314},"Append",[273,2046,346],{"class":290},[273,2048,1922],{"class":330},[273,2050,397],{"class":290},[273,2052,2053,2056,2058,2061,2063],{"class":275,"line":1073},[273,2054,2055],{"class":330},"    chunk",[273,2057,340],{"class":290},[273,2059,2060],{"class":330},"Style ",[273,2062,1855],{"class":290},[273,2064,2065],{"class":330}," headerStyle\n",[273,2067,2068,2070,2072,2074,2076,2078],{"class":275,"line":1078},[273,2069,1950],{"class":330},[273,2071,340],{"class":290},[273,2073,1758],{"class":314},[273,2075,346],{"class":290},[273,2077,19],{"class":330},[273,2079,397],{"class":290},[273,2081,2082],{"class":275,"line":1090},[273,2083,409],{"class":290},[273,2085,2086],{"class":275,"line":1109},[273,2087,305],{"emptyLinePlaceholder":304},[273,2089,2090,2093,2096,2098,2101,2103,2106,2109,2111,2114,2116,2119,2121,2123,2125,2128,2130,2132,2134,2137,2139,2141,2143,2146,2148,2151],{"class":275,"line":1131},[273,2091,2092],{"class":286},"for",[273,2094,2095],{"class":330}," _",[273,2097,437],{"class":290},[273,2099,2100],{"class":330}," h ",[273,2102,334],{"class":290},[273,2104,2105],{"class":286}," range",[273,2107,2108],{"class":290}," []",[273,2110,482],{"class":481},[273,2112,2113],{"class":290},"{",[273,2115,359],{"class":290},[273,2117,2118],{"class":362},"Concepto",[273,2120,359],{"class":290},[273,2122,437],{"class":290},[273,2124,291],{"class":290},[273,2126,2127],{"class":362},"Cant.",[273,2129,359],{"class":290},[273,2131,437],{"class":290},[273,2133,291],{"class":290},[273,2135,2136],{"class":362},"Precio",[273,2138,359],{"class":290},[273,2140,437],{"class":290},[273,2142,291],{"class":290},[273,2144,2145],{"class":362},"Importe",[273,2147,359],{"class":290},[273,2149,2150],{"class":290},"}",[273,2152,321],{"class":290},[273,2154,2155,2158,2160,2163],{"class":275,"line":1136},[273,2156,2157],{"class":314},"    drawHeaderCell",[273,2159,346],{"class":290},[273,2161,2162],{"class":330},"h",[273,2164,397],{"class":290},[273,2166,2167],{"class":275,"line":1163},[273,2168,409],{"class":290},[273,2170,2171],{"class":275,"line":1182},[273,2172,305],{"emptyLinePlaceholder":304},[273,2174,2175,2177,2179,2181,2184,2186,2188,2191],{"class":275,"line":1212},[273,2176,2092],{"class":286},[273,2178,2095],{"class":330},[273,2180,437],{"class":290},[273,2182,2183],{"class":330}," row ",[273,2185,334],{"class":290},[273,2187,2105],{"class":286},[273,2189,2190],{"class":330}," items ",[273,2192,2193],{"class":290},"{\n",[273,2195,2196,2199,2201,2203,2206,2208,2210,2212],{"class":275,"line":1227},[273,2197,2198],{"class":286},"    for",[273,2200,2095],{"class":330},[273,2202,437],{"class":290},[273,2204,2205],{"class":330}," cellText ",[273,2207,334],{"class":290},[273,2209,2105],{"class":286},[273,2211,2183],{"class":330},[273,2213,2193],{"class":290},[273,2215,2216,2219,2221,2223,2225,2227],{"class":275,"line":1232},[273,2217,2218],{"class":330},"        cell ",[273,2220,334],{"class":290},[273,2222,1939],{"class":330},[273,2224,340],{"class":290},[273,2226,1755],{"class":314},[273,2228,1106],{"class":290},[273,2230,2231,2234,2236,2238,2240,2242,2244,2246,2248,2250,2252,2254,2256,2259],{"class":275,"line":1237},[273,2232,2233],{"class":330},"        cell",[273,2235,340],{"class":290},[273,2237,1985],{"class":314},[273,2239,346],{"class":290},[273,2241,41],{"class":330},[273,2243,340],{"class":290},[273,2245,1994],{"class":330},[273,2247,437],{"class":290},[273,2249,1098],{"class":330},[273,2251,340],{"class":290},[273,2253,2003],{"class":330},[273,2255,437],{"class":290},[273,2257,2258],{"class":1176}," 0.3",[273,2260,397],{"class":290},[273,2262,2263],{"class":275,"line":1272},[273,2264,305],{"emptyLinePlaceholder":304},[273,2266,2267,2270,2272,2274,2276,2278,2280,2283],{"class":275,"line":1287},[273,2268,2269],{"class":330},"        p ",[273,2271,334],{"class":290},[273,2273,1144],{"class":330},[273,2275,340],{"class":290},[273,2277,1149],{"class":314},[273,2279,346],{"class":290},[273,2281,2282],{"class":330},"cellText",[273,2284,397],{"class":290},[273,2286,2287,2290,2292,2294,2296,2299],{"class":275,"line":1292},[273,2288,2289],{"class":330},"        p",[273,2291,340],{"class":290},[273,2293,1171],{"class":314},[273,2295,346],{"class":290},[273,2297,2298],{"class":1176},"11",[273,2300,397],{"class":290},[273,2302,2303,2305,2307,2309,2311,2313],{"class":275,"line":1722},[273,2304,2233],{"class":330},[273,2306,340],{"class":290},[273,2308,1758],{"class":314},[273,2310,346],{"class":290},[273,2312,19],{"class":330},[273,2314,397],{"class":290},[273,2316,2317],{"class":275,"line":1727},[273,2318,403],{"class":290},[273,2320,2322],{"class":275,"line":2321},33,[273,2323,409],{"class":290},[273,2325,2327],{"class":275,"line":2326},34,[273,2328,305],{"emptyLinePlaceholder":304},[273,2330,2332,2335,2337,2339,2341,2343,2345,2347,2349,2351,2353,2355,2357],{"class":275,"line":2331},35,[273,2333,2334],{"class":286},"if",[273,2336,331],{"class":330},[273,2338,334],{"class":290},[273,2340,1144],{"class":330},[273,2342,340],{"class":290},[273,2344,1195],{"class":314},[273,2346,346],{"class":290},[273,2348,120],{"class":330},[273,2350,500],{"class":290},[273,2352,331],{"class":330},[273,2354,373],{"class":290},[273,2356,376],{"class":290},[273,2358,321],{"class":290},[273,2360,2362,2365,2367,2369,2371,2373],{"class":275,"line":2361},36,[273,2363,2364],{"class":330},"    log",[273,2366,340],{"class":290},[273,2368,389],{"class":314},[273,2370,346],{"class":290},[273,2372,394],{"class":330},[273,2374,397],{"class":290},[273,2376,2378],{"class":275,"line":2377},37,[273,2379,409],{"class":290},[19,2381,2382],{},"Bordes, contenido por celda, el bucle que dibuja el encabezado — todo es mecánico.",[19,2384,2385],{},[22,2386,1299],{},[264,2388,2390],{"className":266,"code":2389,"language":268,"meta":269,"style":269},"page.AutoRow(func(r *template.RowBuilder) {\n    r.Col(12, func(c *template.ColBuilder) {\n        c.Table(\n            []string{\"Concepto\", \"Cant.\", \"Precio\", \"Importe\"},\n            [][]string{\n                {\"Desarrollo frontend\", \"40 h\", \"150,00 €\", \"6.000,00 €\"},\n                {\"Desarrollo backend\",  \"60 h\", \"150,00 €\", \"9.000,00 €\"},\n                {\"Diseño UI\",           \"20 h\", \"120,00 €\", \"2.400,00 €\"},\n            },\n            template.ColumnWidths(50, 15, 15, 20),\n            template.TableHeaderStyle(\n                template.Bold(),\n                template.TextColor(pdf.White),\n                template.BgColor(pdf.RGBHex(0x1A237E)),\n            ),\n            template.TableStripe(pdf.RGBHex(0xF5F5F5)),\n        )\n    })\n})\n",[35,2391,2392,2417,2448,2459,2501,2510,2551,2591,2632,2637,2668,2679,2691,2712,2738,2743,2767,2772,2776],{"__ignoreMap":269},[273,2393,2394,2397,2399,2401,2403,2405,2407,2409,2411,2413,2415],{"class":275,"line":276},[273,2395,2396],{"class":330},"page",[273,2398,340],{"class":290},[273,2400,1496],{"class":314},[273,2402,1499],{"class":290},[273,2404,1503],{"class":1502},[273,2406,1506],{"class":290},[273,2408,1509],{"class":294},[273,2410,340],{"class":290},[273,2412,1514],{"class":294},[273,2414,585],{"class":290},[273,2416,321],{"class":290},[273,2418,2419,2422,2424,2426,2428,2430,2432,2434,2436,2438,2440,2442,2444,2446],{"class":275,"line":283},[273,2420,2421],{"class":330},"    r",[273,2423,340],{"class":290},[273,2425,1528],{"class":314},[273,2427,346],{"class":290},[273,2429,1533],{"class":1176},[273,2431,437],{"class":290},[273,2433,1538],{"class":290},[273,2435,1541],{"class":1502},[273,2437,1506],{"class":290},[273,2439,1509],{"class":294},[273,2441,340],{"class":290},[273,2443,1550],{"class":294},[273,2445,585],{"class":290},[273,2447,321],{"class":290},[273,2449,2450,2453,2455,2457],{"class":275,"line":301},[273,2451,2452],{"class":330},"        c",[273,2454,340],{"class":290},[273,2456,891],{"class":314},[273,2458,1402],{"class":290},[273,2460,2461,2464,2466,2468,2470,2472,2474,2476,2478,2480,2482,2484,2486,2488,2490,2492,2494,2496,2498],{"class":275,"line":308},[273,2462,2463],{"class":290},"            []",[273,2465,482],{"class":481},[273,2467,2113],{"class":290},[273,2469,359],{"class":290},[273,2471,2118],{"class":362},[273,2473,359],{"class":290},[273,2475,437],{"class":290},[273,2477,291],{"class":290},[273,2479,2127],{"class":362},[273,2481,359],{"class":290},[273,2483,437],{"class":290},[273,2485,291],{"class":290},[273,2487,2136],{"class":362},[273,2489,359],{"class":290},[273,2491,437],{"class":290},[273,2493,291],{"class":290},[273,2495,2145],{"class":362},[273,2497,359],{"class":290},[273,2499,2500],{"class":290},"},\n",[273,2502,2503,2506,2508],{"class":275,"line":324},[273,2504,2505],{"class":290},"            [][]",[273,2507,482],{"class":481},[273,2509,2193],{"class":290},[273,2511,2512,2515,2517,2520,2522,2524,2526,2529,2531,2533,2535,2538,2540,2542,2544,2547,2549],{"class":275,"line":381},[273,2513,2514],{"class":290},"                {",[273,2516,359],{"class":290},[273,2518,2519],{"class":362},"Desarrollo frontend",[273,2521,359],{"class":290},[273,2523,437],{"class":290},[273,2525,291],{"class":290},[273,2527,2528],{"class":362},"40 h",[273,2530,359],{"class":290},[273,2532,437],{"class":290},[273,2534,291],{"class":290},[273,2536,2537],{"class":362},"150,00 €",[273,2539,359],{"class":290},[273,2541,437],{"class":290},[273,2543,291],{"class":290},[273,2545,2546],{"class":362},"6.000,00 €",[273,2548,359],{"class":290},[273,2550,2500],{"class":290},[273,2552,2553,2555,2557,2560,2562,2564,2567,2570,2572,2574,2576,2578,2580,2582,2584,2587,2589],{"class":275,"line":400},[273,2554,2514],{"class":290},[273,2556,359],{"class":290},[273,2558,2559],{"class":362},"Desarrollo backend",[273,2561,359],{"class":290},[273,2563,437],{"class":290},[273,2565,2566],{"class":290},"  \"",[273,2568,2569],{"class":362},"60 h",[273,2571,359],{"class":290},[273,2573,437],{"class":290},[273,2575,291],{"class":290},[273,2577,2537],{"class":362},[273,2579,359],{"class":290},[273,2581,437],{"class":290},[273,2583,291],{"class":290},[273,2585,2586],{"class":362},"9.000,00 €",[273,2588,359],{"class":290},[273,2590,2500],{"class":290},[273,2592,2593,2595,2597,2600,2602,2604,2607,2610,2612,2614,2616,2619,2621,2623,2625,2628,2630],{"class":275,"line":406},[273,2594,2514],{"class":290},[273,2596,359],{"class":290},[273,2598,2599],{"class":362},"Diseño UI",[273,2601,359],{"class":290},[273,2603,437],{"class":290},[273,2605,2606],{"class":290},"           \"",[273,2608,2609],{"class":362},"20 h",[273,2611,359],{"class":290},[273,2613,437],{"class":290},[273,2615,291],{"class":290},[273,2617,2618],{"class":362},"120,00 €",[273,2620,359],{"class":290},[273,2622,437],{"class":290},[273,2624,291],{"class":290},[273,2626,2627],{"class":362},"2.400,00 €",[273,2629,359],{"class":290},[273,2631,2500],{"class":290},[273,2633,2634],{"class":275,"line":986},[273,2635,2636],{"class":290},"            },\n",[273,2638,2639,2642,2644,2647,2649,2652,2654,2657,2659,2661,2663,2666],{"class":275,"line":991},[273,2640,2641],{"class":330},"            template",[273,2643,340],{"class":290},[273,2645,2646],{"class":314},"ColumnWidths",[273,2648,346],{"class":290},[273,2650,2651],{"class":1176},"50",[273,2653,437],{"class":290},[273,2655,2656],{"class":1176}," 15",[273,2658,437],{"class":290},[273,2660,2656],{"class":1176},[273,2662,437],{"class":290},[273,2664,2665],{"class":1176}," 20",[273,2667,1425],{"class":290},[273,2669,2670,2672,2674,2677],{"class":275,"line":996},[273,2671,2641],{"class":330},[273,2673,340],{"class":290},[273,2675,2676],{"class":314},"TableHeaderStyle",[273,2678,1402],{"class":290},[273,2680,2681,2684,2686,2688],{"class":275,"line":1007},[273,2682,2683],{"class":330},"                template",[273,2685,340],{"class":290},[273,2687,1595],{"class":314},[273,2689,2690],{"class":290},"(),\n",[273,2692,2693,2695,2697,2700,2702,2705,2707,2710],{"class":275,"line":1048},[273,2694,2683],{"class":330},[273,2696,340],{"class":290},[273,2698,2699],{"class":314},"TextColor",[273,2701,346],{"class":290},[273,2703,2704],{"class":330},"pdf",[273,2706,340],{"class":290},[273,2708,2709],{"class":330},"White",[273,2711,1425],{"class":290},[273,2713,2714,2716,2718,2721,2723,2725,2727,2730,2732,2735],{"class":275,"line":1063},[273,2715,2683],{"class":330},[273,2717,340],{"class":290},[273,2719,2720],{"class":314},"BgColor",[273,2722,346],{"class":290},[273,2724,2704],{"class":330},[273,2726,340],{"class":290},[273,2728,2729],{"class":314},"RGBHex",[273,2731,346],{"class":290},[273,2733,2734],{"class":1176},"0x1A237E",[273,2736,2737],{"class":290},")),\n",[273,2739,2740],{"class":275,"line":1068},[273,2741,2742],{"class":290},"            ),\n",[273,2744,2745,2747,2749,2752,2754,2756,2758,2760,2762,2765],{"class":275,"line":1073},[273,2746,2641],{"class":330},[273,2748,340],{"class":290},[273,2750,2751],{"class":314},"TableStripe",[273,2753,346],{"class":290},[273,2755,2704],{"class":330},[273,2757,340],{"class":290},[273,2759,2729],{"class":314},[273,2761,346],{"class":290},[273,2763,2764],{"class":1176},"0xF5F5F5",[273,2766,2737],{"class":290},[273,2768,2769],{"class":275,"line":1078},[273,2770,2771],{"class":290},"        )\n",[273,2773,2774],{"class":275,"line":1090},[273,2775,1608],{"class":290},[273,2777,2778],{"class":275,"line":1109},[273,2779,2780],{"class":290},"})\n",[19,2782,2783,2785,2786,2789,2790,2793],{},[35,2784,2646],{}," son ",[22,2787,2788],{},"porcentajes de la columna donde vive la tabla",", no fracciones absolutas de la página. Mete la misma tabla en un ",[35,2791,2792],{},"r.Col(6, ...)"," y los porcentajes siguen valiendo: la tabla ocupa la mitad de la fila y las columnas se redistribuyen en proporción. El salto de página se maneja solo; si el cuerpo pasa el margen inferior, el encabezado se repite en la siguiente página sin que cablees nada.",[19,2795,2796,2797,2800,2801,2804],{},"Un detalle concreto. La Table de unipdf en una corrida de 100 filas de factura mide alrededor de ",[22,2798,2799],{},"8,6 ms"," por render en nuestra suite. La de gpdf hace el mismo trabajo en ",[22,2802,2803],{},"108 µs"," — unas 80× más rápida — porque el motor de layout mide cada fila una vez y escribe páginas en una sola pasada, en vez de materializar un DOM celda por celda. Para una factura suelta es invisible. Para un job en cron, cambia si necesitas o no una cola.",[19,2806,2807,2808,2811],{},"Para facturación electrónica española / latinoamericana (tipos de IVA, conceptos retenidos, fechas) gpdf cubre el lado de layout sin problema. Si necesitas timestamping para Verifactu o equivalente, va por el lado de ",[35,2809,2810],{},"gpdf.SignDocument"," con la opción RFC 3161 TSA.",[14,2813,2815],{"id":2814},"antes-después-3-texto-en-otros-idiomas-sin-la-danza-de-composite-font","Antes / Después 3: texto en otros idiomas sin la danza de composite font",[19,2817,2818],{},"unipdf soporta CJK y caracteres extendidos, pero el camino es verboso. Construyes una composite font desde un TTF en disco, la pones como fuente del style y la pasas por cada paragraph. Si quieres fallbacks, los cableas tú.",[19,2820,2821],{},[22,2822,920],{},[264,2824,2826],{"className":266,"code":2825,"language":268,"meta":269,"style":269},"font, err := model.NewCompositePdfFontFromTTFFile(\"NotoSans-Regular.ttf\")\nif err != nil {\n    log.Fatal(err)\n}\n\nc := creator.New()\nc.SetPageSize(creator.PageSizeA4)\n\nstyle := c.NewTextStyle()\nstyle.Font = font\nstyle.FontSize = 14\n\np := c.NewStyledParagraph()\np.Append(\"Hola, mundo. Recibí ñ, á, é, í, ó, ú.\").Style = style\nif err := c.Draw(p); err != nil {\n    log.Fatal(err)\n}\n\nc.WriteToFile(\"es.pdf\")\n",[35,2827,2828,2857,2869,2883,2887,2891,2906,2924,2928,2943,2958,2971,2975,2990,3017,3045,3059,3063,3067],{"__ignoreMap":269},[273,2829,2830,2833,2835,2837,2839,2841,2843,2846,2848,2850,2853,2855],{"class":275,"line":276},[273,2831,2832],{"class":330},"font",[273,2834,437],{"class":290},[273,2836,331],{"class":330},[273,2838,334],{"class":290},[273,2840,1858],{"class":330},[273,2842,340],{"class":290},[273,2844,2845],{"class":314},"NewCompositePdfFontFromTTFFile",[273,2847,346],{"class":290},[273,2849,359],{"class":290},[273,2851,2852],{"class":362},"NotoSans-Regular.ttf",[273,2854,359],{"class":290},[273,2856,397],{"class":290},[273,2858,2859,2861,2863,2865,2867],{"class":275,"line":283},[273,2860,2334],{"class":286},[273,2862,331],{"class":330},[273,2864,373],{"class":290},[273,2866,376],{"class":290},[273,2868,321],{"class":290},[273,2870,2871,2873,2875,2877,2879,2881],{"class":275,"line":301},[273,2872,2364],{"class":330},[273,2874,340],{"class":290},[273,2876,389],{"class":314},[273,2878,346],{"class":290},[273,2880,394],{"class":330},[273,2882,397],{"class":290},[273,2884,2885],{"class":275,"line":308},[273,2886,409],{"class":290},[273,2888,2889],{"class":275,"line":324},[273,2890,305],{"emptyLinePlaceholder":304},[273,2892,2893,2896,2898,2900,2902,2904],{"class":275,"line":381},[273,2894,2895],{"class":330},"c ",[273,2897,334],{"class":290},[273,2899,1098],{"class":330},[273,2901,340],{"class":290},[273,2903,1103],{"class":314},[273,2905,1106],{"class":290},[273,2907,2908,2910,2912,2914,2916,2918,2920,2922],{"class":275,"line":400},[273,2909,1541],{"class":330},[273,2911,340],{"class":290},[273,2913,1117],{"class":314},[273,2915,346],{"class":290},[273,2917,41],{"class":330},[273,2919,340],{"class":290},[273,2921,1126],{"class":330},[273,2923,397],{"class":290},[273,2925,2926],{"class":275,"line":406},[273,2927,305],{"emptyLinePlaceholder":304},[273,2929,2930,2933,2935,2937,2939,2941],{"class":275,"line":986},[273,2931,2932],{"class":330},"style ",[273,2934,334],{"class":290},[273,2936,1144],{"class":330},[273,2938,340],{"class":290},[273,2940,1836],{"class":314},[273,2942,1106],{"class":290},[273,2944,2945,2948,2950,2953,2955],{"class":275,"line":991},[273,2946,2947],{"class":330},"style",[273,2949,340],{"class":290},[273,2951,2952],{"class":330},"Font ",[273,2954,1855],{"class":290},[273,2956,2957],{"class":330}," font\n",[273,2959,2960,2962,2964,2966,2968],{"class":275,"line":996},[273,2961,2947],{"class":330},[273,2963,340],{"class":290},[273,2965,1883],{"class":330},[273,2967,1855],{"class":290},[273,2969,2970],{"class":1176}," 14\n",[273,2972,2973],{"class":275,"line":1007},[273,2974,305],{"emptyLinePlaceholder":304},[273,2976,2977,2980,2982,2984,2986,2988],{"class":275,"line":1048},[273,2978,2979],{"class":330},"p ",[273,2981,334],{"class":290},[273,2983,1144],{"class":330},[273,2985,340],{"class":290},[273,2987,2027],{"class":314},[273,2989,1106],{"class":290},[273,2991,2992,2994,2996,2998,3000,3002,3005,3007,3010,3012,3014],{"class":275,"line":1063},[273,2993,19],{"class":330},[273,2995,340],{"class":290},[273,2997,2044],{"class":314},[273,2999,346],{"class":290},[273,3001,359],{"class":290},[273,3003,3004],{"class":362},"Hola, mundo. Recibí ñ, á, é, í, ó, ú.",[273,3006,359],{"class":290},[273,3008,3009],{"class":290},").",[273,3011,2060],{"class":330},[273,3013,1855],{"class":290},[273,3015,3016],{"class":330}," style\n",[273,3018,3019,3021,3023,3025,3027,3029,3031,3033,3035,3037,3039,3041,3043],{"class":275,"line":1068},[273,3020,2334],{"class":286},[273,3022,331],{"class":330},[273,3024,334],{"class":290},[273,3026,1144],{"class":330},[273,3028,340],{"class":290},[273,3030,1195],{"class":314},[273,3032,346],{"class":290},[273,3034,19],{"class":330},[273,3036,500],{"class":290},[273,3038,331],{"class":330},[273,3040,373],{"class":290},[273,3042,376],{"class":290},[273,3044,321],{"class":290},[273,3046,3047,3049,3051,3053,3055,3057],{"class":275,"line":1073},[273,3048,2364],{"class":330},[273,3050,340],{"class":290},[273,3052,389],{"class":314},[273,3054,346],{"class":290},[273,3056,394],{"class":330},[273,3058,397],{"class":290},[273,3060,3061],{"class":275,"line":1078},[273,3062,409],{"class":290},[273,3064,3065],{"class":275,"line":1090},[273,3066,305],{"emptyLinePlaceholder":304},[273,3068,3069,3071,3073,3075,3077,3079,3082,3084],{"class":275,"line":1109},[273,3070,1541],{"class":330},[273,3072,340],{"class":290},[273,3074,1250],{"class":314},[273,3076,346],{"class":290},[273,3078,359],{"class":290},[273,3080,3081],{"class":362},"es.pdf",[273,3083,359],{"class":290},[273,3085,397],{"class":290},[19,3087,3088,3089,3091],{},"El TTF debe existir en la ruta indicada, en runtime, en el host que ejecuta el binario. Las imágenes de contenedor tienen que llevar la fuente. ",[35,3090,2845],{}," debe ocurrir antes de cualquier llamada de dibujo que la use, así que vive en algún lugar global o se pasa como dependencia.",[19,3093,3094],{},[22,3095,1299],{},[264,3097,3099],{"className":266,"code":3098,"language":268,"meta":269,"style":269},"package main\n\nimport (\n    _ \"embed\"\n    \"log\"\n    \"os\"\n\n    \"github.com/gpdf-dev/gpdf\"\n    \"github.com/gpdf-dev/gpdf/document\"\n    \"github.com/gpdf-dev/gpdf/template\"\n)\n\n//go:embed NotoSans-Regular.ttf\nvar noto []byte\n\nfunc main() {\n    doc := gpdf.NewDocument(\n        gpdf.WithPageSize(document.A4),\n        gpdf.WithMargins(document.UniformEdges(document.Mm(20))),\n        gpdf.WithFont(\"Noto\", noto),\n        gpdf.WithDefaultFont(\"Noto\", 14),\n    )\n\n    page := doc.AddPage()\n    page.AutoRow(func(r *template.RowBuilder) {\n        r.Col(12, func(c *template.ColBuilder) {\n            c.Text(\"Hola, mundo.\")\n            c.Text(\"Recibí ñ, á, é, í, ó, ú sin escapes.\")\n            c.Text(\"Calle de Alcalá 12, 28014 Madrid\")\n        })\n    })\n\n    data, _ := doc.Generate()\n    if err := os.WriteFile(\"es.pdf\", data, 0o644); err != nil {\n        log.Fatal(err)\n    }\n}\n",[35,3100,3101,3107,3111,3117,3129,3137,3145,3149,3157,3165,3173,3177,3181,3186,3200,3204,3214,3228,3246,3276,3301,3325,3329,3333,3347,3371,3401,3420,3439,3458,3462,3466,3470,3488,3528,3542,3546],{"__ignoreMap":269},[273,3102,3103,3105],{"class":275,"line":276},[273,3104,930],{"class":290},[273,3106,933],{"class":294},[273,3108,3109],{"class":275,"line":283},[273,3110,305],{"emptyLinePlaceholder":304},[273,3112,3113,3115],{"class":275,"line":301},[273,3114,287],{"class":286},[273,3116,944],{"class":290},[273,3118,3119,3122,3124,3127],{"class":275,"line":308},[273,3120,3121],{"class":330},"    _ ",[273,3123,359],{"class":290},[273,3125,3126],{"class":294},"embed",[273,3128,298],{"class":290},[273,3130,3131,3133,3135],{"class":275,"line":324},[273,3132,949],{"class":290},[273,3134,952],{"class":294},[273,3136,298],{"class":290},[273,3138,3139,3141,3143],{"class":275,"line":381},[273,3140,949],{"class":290},[273,3142,349],{"class":294},[273,3144,298],{"class":290},[273,3146,3147],{"class":275,"line":400},[273,3148,305],{"emptyLinePlaceholder":304},[273,3150,3151,3153,3155],{"class":275,"line":406},[273,3152,949],{"class":290},[273,3154,543],{"class":294},[273,3156,298],{"class":290},[273,3158,3159,3161,3163],{"class":275,"line":986},[273,3160,949],{"class":290},[273,3162,1355],{"class":294},[273,3164,298],{"class":290},[273,3166,3167,3169,3171],{"class":275,"line":991},[273,3168,949],{"class":290},[273,3170,1364],{"class":294},[273,3172,298],{"class":290},[273,3174,3175],{"class":275,"line":996},[273,3176,397],{"class":290},[273,3178,3179],{"class":275,"line":1007},[273,3180,305],{"emptyLinePlaceholder":304},[273,3182,3183],{"class":275,"line":1048},[273,3184,3185],{"class":279},"//go:embed NotoSans-Regular.ttf\n",[273,3187,3188,3191,3194,3197],{"class":275,"line":1063},[273,3189,3190],{"class":290},"var",[273,3192,3193],{"class":330}," noto ",[273,3195,3196],{"class":290},"[]",[273,3198,3199],{"class":481},"byte\n",[273,3201,3202],{"class":275,"line":1068},[273,3203,305],{"emptyLinePlaceholder":304},[273,3205,3206,3208,3210,3212],{"class":275,"line":1073},[273,3207,311],{"class":290},[273,3209,1083],{"class":314},[273,3211,318],{"class":290},[273,3213,321],{"class":290},[273,3215,3216,3218,3220,3222,3224,3226],{"class":275,"line":1078},[273,3217,1389],{"class":330},[273,3219,334],{"class":290},[273,3221,1394],{"class":330},[273,3223,340],{"class":290},[273,3225,1399],{"class":314},[273,3227,1402],{"class":290},[273,3229,3230,3232,3234,3236,3238,3240,3242,3244],{"class":275,"line":1090},[273,3231,1407],{"class":330},[273,3233,340],{"class":290},[273,3235,1412],{"class":314},[273,3237,346],{"class":290},[273,3239,1417],{"class":330},[273,3241,340],{"class":290},[273,3243,1422],{"class":330},[273,3245,1425],{"class":290},[273,3247,3248,3250,3252,3254,3256,3258,3260,3262,3264,3266,3268,3270,3272,3274],{"class":275,"line":1109},[273,3249,1407],{"class":330},[273,3251,340],{"class":290},[273,3253,1434],{"class":314},[273,3255,346],{"class":290},[273,3257,1417],{"class":330},[273,3259,340],{"class":290},[273,3261,1443],{"class":314},[273,3263,346],{"class":290},[273,3265,1417],{"class":330},[273,3267,340],{"class":290},[273,3269,1452],{"class":314},[273,3271,346],{"class":290},[273,3273,1457],{"class":1176},[273,3275,1460],{"class":290},[273,3277,3278,3280,3282,3285,3287,3289,3292,3294,3296,3299],{"class":275,"line":1131},[273,3279,1407],{"class":330},[273,3281,340],{"class":290},[273,3283,3284],{"class":314},"WithFont",[273,3286,346],{"class":290},[273,3288,359],{"class":290},[273,3290,3291],{"class":362},"Noto",[273,3293,359],{"class":290},[273,3295,437],{"class":290},[273,3297,3298],{"class":330}," noto",[273,3300,1425],{"class":290},[273,3302,3303,3305,3307,3310,3312,3314,3316,3318,3320,3323],{"class":275,"line":1136},[273,3304,1407],{"class":330},[273,3306,340],{"class":290},[273,3308,3309],{"class":314},"WithDefaultFont",[273,3311,346],{"class":290},[273,3313,359],{"class":290},[273,3315,3291],{"class":362},[273,3317,359],{"class":290},[273,3319,437],{"class":290},[273,3321,3322],{"class":1176}," 14",[273,3324,1425],{"class":290},[273,3326,3327],{"class":275,"line":1163},[273,3328,1465],{"class":290},[273,3330,3331],{"class":275,"line":1182},[273,3332,305],{"emptyLinePlaceholder":304},[273,3334,3335,3337,3339,3341,3343,3345],{"class":275,"line":1212},[273,3336,1474],{"class":330},[273,3338,334],{"class":290},[273,3340,1479],{"class":330},[273,3342,340],{"class":290},[273,3344,1484],{"class":314},[273,3346,1106],{"class":290},[273,3348,3349,3351,3353,3355,3357,3359,3361,3363,3365,3367,3369],{"class":275,"line":1227},[273,3350,1491],{"class":330},[273,3352,340],{"class":290},[273,3354,1496],{"class":314},[273,3356,1499],{"class":290},[273,3358,1503],{"class":1502},[273,3360,1506],{"class":290},[273,3362,1509],{"class":294},[273,3364,340],{"class":290},[273,3366,1514],{"class":294},[273,3368,585],{"class":290},[273,3370,321],{"class":290},[273,3372,3373,3375,3377,3379,3381,3383,3385,3387,3389,3391,3393,3395,3397,3399],{"class":275,"line":1232},[273,3374,1523],{"class":330},[273,3376,340],{"class":290},[273,3378,1528],{"class":314},[273,3380,346],{"class":290},[273,3382,1533],{"class":1176},[273,3384,437],{"class":290},[273,3386,1538],{"class":290},[273,3388,1541],{"class":1502},[273,3390,1506],{"class":290},[273,3392,1509],{"class":294},[273,3394,340],{"class":290},[273,3396,1550],{"class":294},[273,3398,585],{"class":290},[273,3400,321],{"class":290},[273,3402,3403,3405,3407,3409,3411,3413,3416,3418],{"class":275,"line":1237},[273,3404,1559],{"class":330},[273,3406,340],{"class":290},[273,3408,1564],{"class":314},[273,3410,346],{"class":290},[273,3412,359],{"class":290},[273,3414,3415],{"class":362},"Hola, mundo.",[273,3417,359],{"class":290},[273,3419,397],{"class":290},[273,3421,3422,3424,3426,3428,3430,3432,3435,3437],{"class":275,"line":1272},[273,3423,1559],{"class":330},[273,3425,340],{"class":290},[273,3427,1564],{"class":314},[273,3429,346],{"class":290},[273,3431,359],{"class":290},[273,3433,3434],{"class":362},"Recibí ñ, á, é, í, ó, ú sin escapes.",[273,3436,359],{"class":290},[273,3438,397],{"class":290},[273,3440,3441,3443,3445,3447,3449,3451,3454,3456],{"class":275,"line":1287},[273,3442,1559],{"class":330},[273,3444,340],{"class":290},[273,3446,1564],{"class":314},[273,3448,346],{"class":290},[273,3450,359],{"class":290},[273,3452,3453],{"class":362},"Calle de Alcalá 12, 28014 Madrid",[273,3455,359],{"class":290},[273,3457,397],{"class":290},[273,3459,3460],{"class":275,"line":1292},[273,3461,1603],{"class":290},[273,3463,3464],{"class":275,"line":1722},[273,3465,1608],{"class":290},[273,3467,3468],{"class":275,"line":1727},[273,3469,305],{"emptyLinePlaceholder":304},[273,3471,3472,3474,3476,3478,3480,3482,3484,3486],{"class":275,"line":2321},[273,3473,1617],{"class":330},[273,3475,437],{"class":290},[273,3477,440],{"class":330},[273,3479,334],{"class":290},[273,3481,1479],{"class":330},[273,3483,340],{"class":290},[273,3485,1630],{"class":314},[273,3487,1106],{"class":290},[273,3489,3490,3492,3494,3496,3498,3500,3502,3504,3506,3508,3510,3512,3514,3516,3518,3520,3522,3524,3526],{"class":275,"line":2326},[273,3491,327],{"class":286},[273,3493,331],{"class":330},[273,3495,334],{"class":290},[273,3497,445],{"class":330},[273,3499,340],{"class":290},[273,3501,1677],{"class":314},[273,3503,346],{"class":290},[273,3505,359],{"class":290},[273,3507,3081],{"class":362},[273,3509,359],{"class":290},[273,3511,437],{"class":290},[273,3513,1690],{"class":330},[273,3515,437],{"class":290},[273,3517,1695],{"class":1176},[273,3519,500],{"class":290},[273,3521,331],{"class":330},[273,3523,373],{"class":290},[273,3525,376],{"class":290},[273,3527,321],{"class":290},[273,3529,3530,3532,3534,3536,3538,3540],{"class":275,"line":2331},[273,3531,384],{"class":330},[273,3533,340],{"class":290},[273,3535,389],{"class":314},[273,3537,346],{"class":290},[273,3539,394],{"class":330},[273,3541,397],{"class":290},[273,3543,3544],{"class":275,"line":2361},[273,3545,403],{"class":290},[273,3547,3548],{"class":275,"line":2377},[273,3549,409],{"class":290},[19,3551,3552,3553,3556,3557,3560,3561,3564],{},"Tres diferencias dignas de ver. La fuente son ",[22,3554,3555],{},"bytes",", no una ruta — ",[35,3558,3559],{},"//go:embed"," la compila al binario para que la imagen de runtime deje de necesitar un directorio de fuentes. La fuente se registra ",[22,3562,3563],{},"una vez en construcción","; sin pasar styles por cada paragraph. Y el subseteador TrueType de gpdf entiende formatos cmap CJK (4, 6, 12) y codificación Identity-H, así que el PDF de salida solo lleva los glifos que de verdad usaste. Una factura de 200 caracteres produce un subset de fuente de ~30 KB en lugar de un embed completo de 4 MB.",[19,3566,3567],{},"Para CJK específicamente (Source Han Sans, IPAex Gothic, cadenas de fallback), hay un artículo aparte sobre fuentes japonesas.",[14,3569,3571],{"id":3570},"antes-después-4-encabezado-en-cada-página-y-números-de-página-en-el-pie","Antes / Después 4: encabezado en cada página y números de página en el pie",[19,3573,3574,3575,3577,3578,3580,3581,3577,3584,3587],{},"El patrón de unipdf es ",[35,3576,760],{}," y ",[35,3579,764],{},", ambos reciben un contexto con el block actual y el número de página. Los números de página vienen de los campos ",[35,3582,3583],{},"PageNum",[35,3585,3586],{},"TotalPages"," del contexto.",[19,3589,3590],{},[22,3591,920],{},[264,3593,3595],{"className":266,"code":3594,"language":268,"meta":269,"style":269},"c.DrawHeader(func(block *creator.Block, args creator.HeaderFunctionArgs) {\n    p := c.NewParagraph(\"ACME, S.A.\")\n    p.SetFontSize(12)\n    p.SetPos(40, 30)\n    block.Draw(p)\n})\n\nc.DrawFooter(func(block *creator.Block, args creator.FooterFunctionArgs) {\n    p := c.NewParagraph(fmt.Sprintf(\"Página %d de %d\", args.PageNum, args.TotalPages))\n    p.SetFontSize(8)\n    p.SetPos(0, 20)\n    p.SetTextAlignment(creator.TextAlignmentCenter)\n    block.Draw(p)\n})\n",[35,3596,3597,3636,3659,3673,3694,3709,3713,3717,3752,3810,3825,3844,3864,3878],{"__ignoreMap":269},[273,3598,3599,3601,3603,3606,3608,3611,3613,3615,3617,3620,3622,3625,3627,3629,3632,3634],{"class":275,"line":276},[273,3600,1541],{"class":330},[273,3602,340],{"class":290},[273,3604,3605],{"class":314},"DrawHeader",[273,3607,1499],{"class":290},[273,3609,3610],{"class":1502},"block",[273,3612,1506],{"class":290},[273,3614,41],{"class":294},[273,3616,340],{"class":290},[273,3618,3619],{"class":294},"Block",[273,3621,437],{"class":290},[273,3623,3624],{"class":1502}," args",[273,3626,1098],{"class":294},[273,3628,340],{"class":290},[273,3630,3631],{"class":294},"HeaderFunctionArgs",[273,3633,585],{"class":290},[273,3635,321],{"class":290},[273,3637,3638,3640,3642,3644,3646,3648,3650,3652,3655,3657],{"class":275,"line":283},[273,3639,1139],{"class":330},[273,3641,334],{"class":290},[273,3643,1144],{"class":330},[273,3645,340],{"class":290},[273,3647,1149],{"class":314},[273,3649,346],{"class":290},[273,3651,359],{"class":290},[273,3653,3654],{"class":362},"ACME, S.A.",[273,3656,359],{"class":290},[273,3658,397],{"class":290},[273,3660,3661,3663,3665,3667,3669,3671],{"class":275,"line":301},[273,3662,1166],{"class":330},[273,3664,340],{"class":290},[273,3666,1171],{"class":314},[273,3668,346],{"class":290},[273,3670,1533],{"class":1176},[273,3672,397],{"class":290},[273,3674,3675,3677,3679,3682,3684,3687,3689,3692],{"class":275,"line":308},[273,3676,1166],{"class":330},[273,3678,340],{"class":290},[273,3680,3681],{"class":314},"SetPos",[273,3683,346],{"class":290},[273,3685,3686],{"class":1176},"40",[273,3688,437],{"class":290},[273,3690,3691],{"class":1176}," 30",[273,3693,397],{"class":290},[273,3695,3696,3699,3701,3703,3705,3707],{"class":275,"line":324},[273,3697,3698],{"class":330},"    block",[273,3700,340],{"class":290},[273,3702,1195],{"class":314},[273,3704,346],{"class":290},[273,3706,19],{"class":330},[273,3708,397],{"class":290},[273,3710,3711],{"class":275,"line":381},[273,3712,2780],{"class":290},[273,3714,3715],{"class":275,"line":400},[273,3716,305],{"emptyLinePlaceholder":304},[273,3718,3719,3721,3723,3725,3727,3729,3731,3733,3735,3737,3739,3741,3743,3745,3748,3750],{"class":275,"line":406},[273,3720,1541],{"class":330},[273,3722,340],{"class":290},[273,3724,783],{"class":314},[273,3726,1499],{"class":290},[273,3728,3610],{"class":1502},[273,3730,1506],{"class":290},[273,3732,41],{"class":294},[273,3734,340],{"class":290},[273,3736,3619],{"class":294},[273,3738,437],{"class":290},[273,3740,3624],{"class":1502},[273,3742,1098],{"class":294},[273,3744,340],{"class":290},[273,3746,3747],{"class":294},"FooterFunctionArgs",[273,3749,585],{"class":290},[273,3751,321],{"class":290},[273,3753,3754,3756,3758,3760,3762,3764,3766,3769,3771,3774,3776,3778,3781,3785,3788,3790,3792,3794,3796,3798,3800,3802,3804,3806,3808],{"class":275,"line":986},[273,3755,1139],{"class":330},[273,3757,334],{"class":290},[273,3759,1144],{"class":330},[273,3761,340],{"class":290},[273,3763,1149],{"class":314},[273,3765,346],{"class":290},[273,3767,3768],{"class":330},"fmt",[273,3770,340],{"class":290},[273,3772,3773],{"class":314},"Sprintf",[273,3775,346],{"class":290},[273,3777,359],{"class":290},[273,3779,3780],{"class":362},"Página ",[273,3782,3784],{"class":3783},"swJcz","%d",[273,3786,3787],{"class":362}," de ",[273,3789,3784],{"class":3783},[273,3791,359],{"class":290},[273,3793,437],{"class":290},[273,3795,3624],{"class":330},[273,3797,340],{"class":290},[273,3799,3583],{"class":330},[273,3801,437],{"class":290},[273,3803,3624],{"class":330},[273,3805,340],{"class":290},[273,3807,3586],{"class":330},[273,3809,1976],{"class":290},[273,3811,3812,3814,3816,3818,3820,3823],{"class":275,"line":991},[273,3813,1166],{"class":330},[273,3815,340],{"class":290},[273,3817,1171],{"class":314},[273,3819,346],{"class":290},[273,3821,3822],{"class":1176},"8",[273,3824,397],{"class":290},[273,3826,3827,3829,3831,3833,3835,3838,3840,3842],{"class":275,"line":996},[273,3828,1166],{"class":330},[273,3830,340],{"class":290},[273,3832,3681],{"class":314},[273,3834,346],{"class":290},[273,3836,3837],{"class":1176},"0",[273,3839,437],{"class":290},[273,3841,2665],{"class":1176},[273,3843,397],{"class":290},[273,3845,3846,3848,3850,3853,3855,3857,3859,3862],{"class":275,"line":1007},[273,3847,1166],{"class":330},[273,3849,340],{"class":290},[273,3851,3852],{"class":314},"SetTextAlignment",[273,3854,346],{"class":290},[273,3856,41],{"class":330},[273,3858,340],{"class":290},[273,3860,3861],{"class":330},"TextAlignmentCenter",[273,3863,397],{"class":290},[273,3865,3866,3868,3870,3872,3874,3876],{"class":275,"line":1048},[273,3867,3698],{"class":330},[273,3869,340],{"class":290},[273,3871,1195],{"class":314},[273,3873,346],{"class":290},[273,3875,19],{"class":330},[273,3877,397],{"class":290},[273,3879,3880],{"class":275,"line":1063},[273,3881,2780],{"class":290},[19,3883,3884],{},"Encabezado / pie son blocks que pintas con posiciones absolutas. Coordenada Y mal puesta, margen mal puesto — trabajo de píxeles cada vez que cambias el tamaño de página.",[19,3886,3887],{},[22,3888,1299],{},[264,3890,3892],{"className":266,"code":3891,"language":268,"meta":269,"style":269},"doc := gpdf.NewDocument(\n    gpdf.WithPageSize(document.A4),\n    gpdf.WithMargins(document.UniformEdges(document.Mm(20))),\n)\n\ndoc.Header(func(p *template.PageBuilder) {\n    p.AutoRow(func(r *template.RowBuilder) {\n        r.Col(12, func(c *template.ColBuilder) {\n            c.Text(\"ACME, S.A.\", template.Bold(), template.FontSize(12))\n            c.Line(template.LineColor(pdf.Gray(0.7)))\n            c.Spacer(document.Mm(4))\n        })\n    })\n})\n\ndoc.Footer(func(p *template.PageBuilder) {\n    p.AutoRow(func(r *template.RowBuilder) {\n        r.Col(6, func(c *template.ColBuilder) {\n            c.Text(\"ACME, S.A.\",\n                template.FontSize(8), template.TextColor(pdf.Gray(0.5)))\n        })\n        r.Col(6, func(c *template.ColBuilder) {\n            c.PageNumber(template.AlignRight(),\n                template.FontSize(8), template.TextColor(pdf.Gray(0.5)))\n        })\n    })\n})\n\nfor i := 0; i \u003C 10; i++ {\n    page := doc.AddPage()\n    page.AutoRow(func(r *template.RowBuilder) {\n        r.Col(12, func(c *template.ColBuilder) {\n            c.Text(fmt.Sprintf(\"Cuerpo de la página %d.\", i+1))\n        })\n    })\n}\n",[35,3893,3894,3909,3928,3958,3962,3966,3993,4017,4047,4086,4121,4144,4148,4152,4156,4160,4185,4209,4240,4259,4293,4297,4327,4347,4381,4385,4389,4393,4397,4430,4444,4468,4498,4539,4543,4547],{"__ignoreMap":269},[273,3895,3896,3899,3901,3903,3905,3907],{"class":275,"line":276},[273,3897,3898],{"class":330},"doc ",[273,3900,334],{"class":290},[273,3902,1394],{"class":330},[273,3904,340],{"class":290},[273,3906,1399],{"class":314},[273,3908,1402],{"class":290},[273,3910,3911,3914,3916,3918,3920,3922,3924,3926],{"class":275,"line":283},[273,3912,3913],{"class":330},"    gpdf",[273,3915,340],{"class":290},[273,3917,1412],{"class":314},[273,3919,346],{"class":290},[273,3921,1417],{"class":330},[273,3923,340],{"class":290},[273,3925,1422],{"class":330},[273,3927,1425],{"class":290},[273,3929,3930,3932,3934,3936,3938,3940,3942,3944,3946,3948,3950,3952,3954,3956],{"class":275,"line":301},[273,3931,3913],{"class":330},[273,3933,340],{"class":290},[273,3935,1434],{"class":314},[273,3937,346],{"class":290},[273,3939,1417],{"class":330},[273,3941,340],{"class":290},[273,3943,1443],{"class":314},[273,3945,346],{"class":290},[273,3947,1417],{"class":330},[273,3949,340],{"class":290},[273,3951,1452],{"class":314},[273,3953,346],{"class":290},[273,3955,1457],{"class":1176},[273,3957,1460],{"class":290},[273,3959,3960],{"class":275,"line":308},[273,3961,397],{"class":290},[273,3963,3964],{"class":275,"line":324},[273,3965,305],{"emptyLinePlaceholder":304},[273,3967,3968,3971,3973,3976,3978,3980,3982,3984,3986,3989,3991],{"class":275,"line":381},[273,3969,3970],{"class":330},"doc",[273,3972,340],{"class":290},[273,3974,3975],{"class":314},"Header",[273,3977,1499],{"class":290},[273,3979,19],{"class":1502},[273,3981,1506],{"class":290},[273,3983,1509],{"class":294},[273,3985,340],{"class":290},[273,3987,3988],{"class":294},"PageBuilder",[273,3990,585],{"class":290},[273,3992,321],{"class":290},[273,3994,3995,3997,3999,4001,4003,4005,4007,4009,4011,4013,4015],{"class":275,"line":400},[273,3996,1166],{"class":330},[273,3998,340],{"class":290},[273,4000,1496],{"class":314},[273,4002,1499],{"class":290},[273,4004,1503],{"class":1502},[273,4006,1506],{"class":290},[273,4008,1509],{"class":294},[273,4010,340],{"class":290},[273,4012,1514],{"class":294},[273,4014,585],{"class":290},[273,4016,321],{"class":290},[273,4018,4019,4021,4023,4025,4027,4029,4031,4033,4035,4037,4039,4041,4043,4045],{"class":275,"line":406},[273,4020,1523],{"class":330},[273,4022,340],{"class":290},[273,4024,1528],{"class":314},[273,4026,346],{"class":290},[273,4028,1533],{"class":1176},[273,4030,437],{"class":290},[273,4032,1538],{"class":290},[273,4034,1541],{"class":1502},[273,4036,1506],{"class":290},[273,4038,1509],{"class":294},[273,4040,340],{"class":290},[273,4042,1550],{"class":294},[273,4044,585],{"class":290},[273,4046,321],{"class":290},[273,4048,4049,4051,4053,4055,4057,4059,4061,4063,4065,4067,4069,4071,4074,4076,4078,4080,4082,4084],{"class":275,"line":986},[273,4050,1559],{"class":330},[273,4052,340],{"class":290},[273,4054,1564],{"class":314},[273,4056,346],{"class":290},[273,4058,359],{"class":290},[273,4060,3654],{"class":362},[273,4062,359],{"class":290},[273,4064,437],{"class":290},[273,4066,1577],{"class":330},[273,4068,340],{"class":290},[273,4070,1595],{"class":314},[273,4072,4073],{"class":290},"(),",[273,4075,1577],{"class":330},[273,4077,340],{"class":290},[273,4079,1582],{"class":314},[273,4081,346],{"class":290},[273,4083,1533],{"class":1176},[273,4085,1976],{"class":290},[273,4087,4088,4090,4092,4095,4097,4099,4101,4104,4106,4108,4110,4113,4115,4118],{"class":275,"line":991},[273,4089,1559],{"class":330},[273,4091,340],{"class":290},[273,4093,4094],{"class":314},"Line",[273,4096,346],{"class":290},[273,4098,1509],{"class":330},[273,4100,340],{"class":290},[273,4102,4103],{"class":314},"LineColor",[273,4105,346],{"class":290},[273,4107,2704],{"class":330},[273,4109,340],{"class":290},[273,4111,4112],{"class":314},"Gray",[273,4114,346],{"class":290},[273,4116,4117],{"class":1176},"0.7",[273,4119,4120],{"class":290},")))\n",[273,4122,4123,4125,4127,4130,4132,4134,4136,4138,4140,4142],{"class":275,"line":996},[273,4124,1559],{"class":330},[273,4126,340],{"class":290},[273,4128,4129],{"class":314},"Spacer",[273,4131,346],{"class":290},[273,4133,1417],{"class":330},[273,4135,340],{"class":290},[273,4137,1452],{"class":314},[273,4139,346],{"class":290},[273,4141,1787],{"class":1176},[273,4143,1976],{"class":290},[273,4145,4146],{"class":275,"line":1007},[273,4147,1603],{"class":290},[273,4149,4150],{"class":275,"line":1048},[273,4151,1608],{"class":290},[273,4153,4154],{"class":275,"line":1063},[273,4155,2780],{"class":290},[273,4157,4158],{"class":275,"line":1068},[273,4159,305],{"emptyLinePlaceholder":304},[273,4161,4162,4164,4166,4169,4171,4173,4175,4177,4179,4181,4183],{"class":275,"line":1073},[273,4163,3970],{"class":330},[273,4165,340],{"class":290},[273,4167,4168],{"class":314},"Footer",[273,4170,1499],{"class":290},[273,4172,19],{"class":1502},[273,4174,1506],{"class":290},[273,4176,1509],{"class":294},[273,4178,340],{"class":290},[273,4180,3988],{"class":294},[273,4182,585],{"class":290},[273,4184,321],{"class":290},[273,4186,4187,4189,4191,4193,4195,4197,4199,4201,4203,4205,4207],{"class":275,"line":1078},[273,4188,1166],{"class":330},[273,4190,340],{"class":290},[273,4192,1496],{"class":314},[273,4194,1499],{"class":290},[273,4196,1503],{"class":1502},[273,4198,1506],{"class":290},[273,4200,1509],{"class":294},[273,4202,340],{"class":290},[273,4204,1514],{"class":294},[273,4206,585],{"class":290},[273,4208,321],{"class":290},[273,4210,4211,4213,4215,4217,4219,4222,4224,4226,4228,4230,4232,4234,4236,4238],{"class":275,"line":1090},[273,4212,1523],{"class":330},[273,4214,340],{"class":290},[273,4216,1528],{"class":314},[273,4218,346],{"class":290},[273,4220,4221],{"class":1176},"6",[273,4223,437],{"class":290},[273,4225,1538],{"class":290},[273,4227,1541],{"class":1502},[273,4229,1506],{"class":290},[273,4231,1509],{"class":294},[273,4233,340],{"class":290},[273,4235,1550],{"class":294},[273,4237,585],{"class":290},[273,4239,321],{"class":290},[273,4241,4242,4244,4246,4248,4250,4252,4254,4256],{"class":275,"line":1109},[273,4243,1559],{"class":330},[273,4245,340],{"class":290},[273,4247,1564],{"class":314},[273,4249,346],{"class":290},[273,4251,359],{"class":290},[273,4253,3654],{"class":362},[273,4255,359],{"class":290},[273,4257,4258],{"class":290},",\n",[273,4260,4261,4263,4265,4267,4269,4271,4273,4275,4277,4279,4281,4283,4285,4287,4289,4291],{"class":275,"line":1131},[273,4262,2683],{"class":330},[273,4264,340],{"class":290},[273,4266,1582],{"class":314},[273,4268,346],{"class":290},[273,4270,3822],{"class":1176},[273,4272,490],{"class":290},[273,4274,1577],{"class":330},[273,4276,340],{"class":290},[273,4278,2699],{"class":314},[273,4280,346],{"class":290},[273,4282,2704],{"class":330},[273,4284,340],{"class":290},[273,4286,4112],{"class":314},[273,4288,346],{"class":290},[273,4290,1802],{"class":1176},[273,4292,4120],{"class":290},[273,4294,4295],{"class":275,"line":1136},[273,4296,1603],{"class":290},[273,4298,4299,4301,4303,4305,4307,4309,4311,4313,4315,4317,4319,4321,4323,4325],{"class":275,"line":1163},[273,4300,1523],{"class":330},[273,4302,340],{"class":290},[273,4304,1528],{"class":314},[273,4306,346],{"class":290},[273,4308,4221],{"class":1176},[273,4310,437],{"class":290},[273,4312,1538],{"class":290},[273,4314,1541],{"class":1502},[273,4316,1506],{"class":290},[273,4318,1509],{"class":294},[273,4320,340],{"class":290},[273,4322,1550],{"class":294},[273,4324,585],{"class":290},[273,4326,321],{"class":290},[273,4328,4329,4331,4333,4336,4338,4340,4342,4345],{"class":275,"line":1182},[273,4330,1559],{"class":330},[273,4332,340],{"class":290},[273,4334,4335],{"class":314},"PageNumber",[273,4337,346],{"class":290},[273,4339,1509],{"class":330},[273,4341,340],{"class":290},[273,4343,4344],{"class":314},"AlignRight",[273,4346,2690],{"class":290},[273,4348,4349,4351,4353,4355,4357,4359,4361,4363,4365,4367,4369,4371,4373,4375,4377,4379],{"class":275,"line":1212},[273,4350,2683],{"class":330},[273,4352,340],{"class":290},[273,4354,1582],{"class":314},[273,4356,346],{"class":290},[273,4358,3822],{"class":1176},[273,4360,490],{"class":290},[273,4362,1577],{"class":330},[273,4364,340],{"class":290},[273,4366,2699],{"class":314},[273,4368,346],{"class":290},[273,4370,2704],{"class":330},[273,4372,340],{"class":290},[273,4374,4112],{"class":314},[273,4376,346],{"class":290},[273,4378,1802],{"class":1176},[273,4380,4120],{"class":290},[273,4382,4383],{"class":275,"line":1227},[273,4384,1603],{"class":290},[273,4386,4387],{"class":275,"line":1232},[273,4388,1608],{"class":290},[273,4390,4391],{"class":275,"line":1237},[273,4392,2780],{"class":290},[273,4394,4395],{"class":275,"line":1272},[273,4396,305],{"emptyLinePlaceholder":304},[273,4398,4399,4401,4404,4406,4409,4412,4414,4417,4420,4422,4425,4428],{"class":275,"line":1287},[273,4400,2092],{"class":286},[273,4402,4403],{"class":330}," i ",[273,4405,334],{"class":290},[273,4407,4408],{"class":1176}," 0",[273,4410,4411],{"class":290},";",[273,4413,4403],{"class":330},[273,4415,4416],{"class":290},"\u003C",[273,4418,4419],{"class":1176}," 10",[273,4421,4411],{"class":290},[273,4423,4424],{"class":330}," i",[273,4426,4427],{"class":290},"++",[273,4429,321],{"class":290},[273,4431,4432,4434,4436,4438,4440,4442],{"class":275,"line":1292},[273,4433,1474],{"class":330},[273,4435,334],{"class":290},[273,4437,1479],{"class":330},[273,4439,340],{"class":290},[273,4441,1484],{"class":314},[273,4443,1106],{"class":290},[273,4445,4446,4448,4450,4452,4454,4456,4458,4460,4462,4464,4466],{"class":275,"line":1722},[273,4447,1491],{"class":330},[273,4449,340],{"class":290},[273,4451,1496],{"class":314},[273,4453,1499],{"class":290},[273,4455,1503],{"class":1502},[273,4457,1506],{"class":290},[273,4459,1509],{"class":294},[273,4461,340],{"class":290},[273,4463,1514],{"class":294},[273,4465,585],{"class":290},[273,4467,321],{"class":290},[273,4469,4470,4472,4474,4476,4478,4480,4482,4484,4486,4488,4490,4492,4494,4496],{"class":275,"line":1727},[273,4471,1523],{"class":330},[273,4473,340],{"class":290},[273,4475,1528],{"class":314},[273,4477,346],{"class":290},[273,4479,1533],{"class":1176},[273,4481,437],{"class":290},[273,4483,1538],{"class":290},[273,4485,1541],{"class":1502},[273,4487,1506],{"class":290},[273,4489,1509],{"class":294},[273,4491,340],{"class":290},[273,4493,1550],{"class":294},[273,4495,585],{"class":290},[273,4497,321],{"class":290},[273,4499,4500,4502,4504,4506,4508,4510,4512,4514,4516,4518,4521,4523,4525,4527,4529,4531,4534,4537],{"class":275,"line":2321},[273,4501,1559],{"class":330},[273,4503,340],{"class":290},[273,4505,1564],{"class":314},[273,4507,346],{"class":290},[273,4509,3768],{"class":330},[273,4511,340],{"class":290},[273,4513,3773],{"class":314},[273,4515,346],{"class":290},[273,4517,359],{"class":290},[273,4519,4520],{"class":362},"Cuerpo de la página ",[273,4522,3784],{"class":3783},[273,4524,340],{"class":362},[273,4526,359],{"class":290},[273,4528,437],{"class":290},[273,4530,4424],{"class":330},[273,4532,4533],{"class":290},"+",[273,4535,4536],{"class":1176},"1",[273,4538,1976],{"class":290},[273,4540,4541],{"class":275,"line":2326},[273,4542,1603],{"class":290},[273,4544,4545],{"class":275,"line":2331},[273,4546,1608],{"class":290},[273,4548,4549],{"class":275,"line":2361},[273,4550,409],{"class":290},[19,4552,4553,3577,4555,4557],{},[35,4554,4335],{},[35,4556,3586],{}," son placeholders que el motor de layout resuelve después de paginar. El encabezado y el pie son árboles, no blocks que posicionas a mano. El motor reserva espacio para ellos en cada página automáticamente; si cambias el tamaño de página de A4 a Letter, no tienes que mover nada más.",[14,4559,4561],{"id":4560},"antes-después-5-cifrado-con-aes-256","Antes / Después 5: cifrado con AES-256",[19,4563,4564,4565,4567],{},"El par donde la foto de la licencia es más nítida. El cifrado de unipdf va por ",[35,4566,804],{},", que cuenta como uso comercial y dispara el camino de registro de licencia. El de gpdf vive detrás de una sola opción funcional, y la implementación AES-256 (ISO 32000-2 Rev 6) está en el core MIT de código abierto.",[19,4569,4570],{},[22,4571,920],{},[264,4573,4575],{"className":266,"code":4574,"language":268,"meta":269,"style":269},"// Renderiza contenido con creator y luego re-codifica con model.PdfWriter\n// para adjuntar el cifrado. El check de licencia se dispara aquí.\nc := creator.New()\n// ... dibujar contenido ...\n\nvar buf bytes.Buffer\nif err := c.Write(&buf); err != nil {\n    log.Fatal(err)\n}\n\nreader, err := model.NewPdfReader(bytes.NewReader(buf.Bytes()))\nif err != nil {\n    log.Fatal(err)\n}\n\nwriter := model.NewPdfWriter()\nencryptOpts := &model.EncryptOptions{Algorithm: model.RC4_128bit, Permissions: model.PermPrinting}\nif err := writer.Encrypt([]byte(\"user-pwd\"), []byte(\"owner-pwd\"), encryptOpts); err != nil {\n    log.Fatal(err)\n}\n\nfor i := 1; i \u003C= reader.NumPage; i++ {\n    page, _ := reader.GetPage(i)\n    writer.AddPage(page)\n}\n\nf, _ := os.Create(\"encrypted.pdf\")\ndefer f.Close()\nwriter.Write(f)\n",[35,4576,4577,4582,4587,4601,4606,4610,4624,4655,4669,4673,4677,4716,4728,4742,4746,4750,4766,4815,4875,4889,4893,4897,4931,4955,4970,4974,4978,5007,5022],{"__ignoreMap":269},[273,4578,4579],{"class":275,"line":276},[273,4580,4581],{"class":279},"// Renderiza contenido con creator y luego re-codifica con model.PdfWriter\n",[273,4583,4584],{"class":275,"line":283},[273,4585,4586],{"class":279},"// para adjuntar el cifrado. El check de licencia se dispara aquí.\n",[273,4588,4589,4591,4593,4595,4597,4599],{"class":275,"line":301},[273,4590,2895],{"class":330},[273,4592,334],{"class":290},[273,4594,1098],{"class":330},[273,4596,340],{"class":290},[273,4598,1103],{"class":314},[273,4600,1106],{"class":290},[273,4602,4603],{"class":275,"line":308},[273,4604,4605],{"class":279},"// ... dibujar contenido ...\n",[273,4607,4608],{"class":275,"line":324},[273,4609,305],{"emptyLinePlaceholder":304},[273,4611,4612,4614,4617,4619,4621],{"class":275,"line":381},[273,4613,3190],{"class":290},[273,4615,4616],{"class":330}," buf ",[273,4618,3555],{"class":294},[273,4620,340],{"class":290},[273,4622,4623],{"class":294},"Buffer\n",[273,4625,4626,4628,4630,4632,4634,4636,4639,4642,4645,4647,4649,4651,4653],{"class":275,"line":400},[273,4627,2334],{"class":286},[273,4629,331],{"class":330},[273,4631,334],{"class":290},[273,4633,1144],{"class":330},[273,4635,340],{"class":290},[273,4637,4638],{"class":314},"Write",[273,4640,4641],{"class":290},"(&",[273,4643,4644],{"class":330},"buf",[273,4646,500],{"class":290},[273,4648,331],{"class":330},[273,4650,373],{"class":290},[273,4652,376],{"class":290},[273,4654,321],{"class":290},[273,4656,4657,4659,4661,4663,4665,4667],{"class":275,"line":406},[273,4658,2364],{"class":330},[273,4660,340],{"class":290},[273,4662,389],{"class":314},[273,4664,346],{"class":290},[273,4666,394],{"class":330},[273,4668,397],{"class":290},[273,4670,4671],{"class":275,"line":986},[273,4672,409],{"class":290},[273,4674,4675],{"class":275,"line":991},[273,4676,305],{"emptyLinePlaceholder":304},[273,4678,4679,4682,4684,4686,4688,4690,4692,4695,4697,4699,4701,4704,4706,4708,4710,4713],{"class":275,"line":996},[273,4680,4681],{"class":330},"reader",[273,4683,437],{"class":290},[273,4685,331],{"class":330},[273,4687,334],{"class":290},[273,4689,1858],{"class":330},[273,4691,340],{"class":290},[273,4693,4694],{"class":314},"NewPdfReader",[273,4696,346],{"class":290},[273,4698,3555],{"class":330},[273,4700,340],{"class":290},[273,4702,4703],{"class":314},"NewReader",[273,4705,346],{"class":290},[273,4707,4644],{"class":330},[273,4709,340],{"class":290},[273,4711,4712],{"class":314},"Bytes",[273,4714,4715],{"class":290},"()))\n",[273,4717,4718,4720,4722,4724,4726],{"class":275,"line":1007},[273,4719,2334],{"class":286},[273,4721,331],{"class":330},[273,4723,373],{"class":290},[273,4725,376],{"class":290},[273,4727,321],{"class":290},[273,4729,4730,4732,4734,4736,4738,4740],{"class":275,"line":1048},[273,4731,2364],{"class":330},[273,4733,340],{"class":290},[273,4735,389],{"class":314},[273,4737,346],{"class":290},[273,4739,394],{"class":330},[273,4741,397],{"class":290},[273,4743,4744],{"class":275,"line":1063},[273,4745,409],{"class":290},[273,4747,4748],{"class":275,"line":1068},[273,4749,305],{"emptyLinePlaceholder":304},[273,4751,4752,4755,4757,4759,4761,4764],{"class":275,"line":1073},[273,4753,4754],{"class":330},"writer ",[273,4756,334],{"class":290},[273,4758,1858],{"class":330},[273,4760,340],{"class":290},[273,4762,4763],{"class":314},"NewPdfWriter",[273,4765,1106],{"class":290},[273,4767,4768,4771,4773,4776,4779,4781,4784,4786,4789,4792,4794,4796,4799,4801,4804,4806,4808,4810,4813],{"class":275,"line":1078},[273,4769,4770],{"class":330},"encryptOpts ",[273,4772,334],{"class":290},[273,4774,4775],{"class":290}," &",[273,4777,4778],{"class":294},"model",[273,4780,340],{"class":290},[273,4782,4783],{"class":294},"EncryptOptions",[273,4785,2113],{"class":290},[273,4787,4788],{"class":330},"Algorithm",[273,4790,4791],{"class":290},":",[273,4793,1858],{"class":330},[273,4795,340],{"class":290},[273,4797,4798],{"class":330},"RC4_128bit",[273,4800,437],{"class":290},[273,4802,4803],{"class":330}," Permissions",[273,4805,4791],{"class":290},[273,4807,1858],{"class":330},[273,4809,340],{"class":290},[273,4811,4812],{"class":330},"PermPrinting",[273,4814,409],{"class":290},[273,4816,4817,4819,4821,4823,4826,4828,4830,4833,4836,4838,4840,4843,4845,4847,4849,4851,4853,4855,4858,4860,4862,4865,4867,4869,4871,4873],{"class":275,"line":1090},[273,4818,2334],{"class":286},[273,4820,331],{"class":330},[273,4822,334],{"class":290},[273,4824,4825],{"class":330}," writer",[273,4827,340],{"class":290},[273,4829,808],{"class":314},[273,4831,4832],{"class":290},"([]",[273,4834,4835],{"class":481},"byte",[273,4837,346],{"class":290},[273,4839,359],{"class":290},[273,4841,4842],{"class":362},"user-pwd",[273,4844,359],{"class":290},[273,4846,490],{"class":290},[273,4848,2108],{"class":290},[273,4850,4835],{"class":481},[273,4852,346],{"class":290},[273,4854,359],{"class":290},[273,4856,4857],{"class":362},"owner-pwd",[273,4859,359],{"class":290},[273,4861,490],{"class":290},[273,4863,4864],{"class":330}," encryptOpts",[273,4866,500],{"class":290},[273,4868,331],{"class":330},[273,4870,373],{"class":290},[273,4872,376],{"class":290},[273,4874,321],{"class":290},[273,4876,4877,4879,4881,4883,4885,4887],{"class":275,"line":1109},[273,4878,2364],{"class":330},[273,4880,340],{"class":290},[273,4882,389],{"class":314},[273,4884,346],{"class":290},[273,4886,394],{"class":330},[273,4888,397],{"class":290},[273,4890,4891],{"class":275,"line":1131},[273,4892,409],{"class":290},[273,4894,4895],{"class":275,"line":1136},[273,4896,305],{"emptyLinePlaceholder":304},[273,4898,4899,4901,4903,4905,4908,4910,4912,4915,4918,4920,4923,4925,4927,4929],{"class":275,"line":1163},[273,4900,2092],{"class":286},[273,4902,4403],{"class":330},[273,4904,334],{"class":290},[273,4906,4907],{"class":1176}," 1",[273,4909,4411],{"class":290},[273,4911,4403],{"class":330},[273,4913,4914],{"class":290},"\u003C=",[273,4916,4917],{"class":330}," reader",[273,4919,340],{"class":290},[273,4921,4922],{"class":330},"NumPage",[273,4924,4411],{"class":290},[273,4926,4424],{"class":330},[273,4928,4427],{"class":290},[273,4930,321],{"class":290},[273,4932,4933,4935,4937,4939,4941,4943,4945,4948,4950,4953],{"class":275,"line":1182},[273,4934,1491],{"class":330},[273,4936,437],{"class":290},[273,4938,440],{"class":330},[273,4940,334],{"class":290},[273,4942,4917],{"class":330},[273,4944,340],{"class":290},[273,4946,4947],{"class":314},"GetPage",[273,4949,346],{"class":290},[273,4951,4952],{"class":330},"i",[273,4954,397],{"class":290},[273,4956,4957,4960,4962,4964,4966,4968],{"class":275,"line":1212},[273,4958,4959],{"class":330},"    writer",[273,4961,340],{"class":290},[273,4963,1484],{"class":314},[273,4965,346],{"class":290},[273,4967,2396],{"class":330},[273,4969,397],{"class":290},[273,4971,4972],{"class":275,"line":1227},[273,4973,409],{"class":290},[273,4975,4976],{"class":275,"line":1232},[273,4977,305],{"emptyLinePlaceholder":304},[273,4979,4980,4983,4985,4987,4989,4991,4993,4996,4998,5000,5003,5005],{"class":275,"line":1237},[273,4981,4982],{"class":330},"f",[273,4984,437],{"class":290},[273,4986,440],{"class":330},[273,4988,334],{"class":290},[273,4990,445],{"class":330},[273,4992,340],{"class":290},[273,4994,4995],{"class":314},"Create",[273,4997,346],{"class":290},[273,4999,359],{"class":290},[273,5001,5002],{"class":362},"encrypted.pdf",[273,5004,359],{"class":290},[273,5006,397],{"class":290},[273,5008,5009,5012,5015,5017,5020],{"class":275,"line":1272},[273,5010,5011],{"class":286},"defer",[273,5013,5014],{"class":330}," f",[273,5016,340],{"class":290},[273,5018,5019],{"class":314},"Close",[273,5021,1106],{"class":290},[273,5023,5024,5027,5029,5031,5033,5035],{"class":275,"line":1287},[273,5025,5026],{"class":330},"writer",[273,5028,340],{"class":290},[273,5030,4638],{"class":314},[273,5032,346],{"class":290},[273,5034,4982],{"class":330},[273,5036,397],{"class":290},[19,5038,5039],{},[22,5040,1299],{},[264,5042,5044],{"className":266,"code":5043,"language":268,"meta":269,"style":269},"doc := gpdf.NewDocument(\n    gpdf.WithPageSize(document.A4),\n    gpdf.WithMargins(document.UniformEdges(document.Mm(20))),\n    gpdf.WithEncryption(\n        gpdf.AES256,\n        \"user-pwd\",\n        \"owner-pwd\",\n        gpdf.PermPrinting|gpdf.PermCopyContent,\n    ),\n)\n\npage := doc.AddPage()\npage.AutoRow(func(r *template.RowBuilder) {\n    r.Col(12, func(c *template.ColBuilder) {\n        c.Text(\"Confidencial.\")\n    })\n})\n\ndata, _ := doc.Generate()\nos.WriteFile(\"encrypted.pdf\", data, 0o644)\n",[35,5045,5046,5060,5078,5108,5119,5130,5141,5151,5171,5176,5180,5184,5199,5223,5253,5272,5276,5280,5284,5303],{"__ignoreMap":269},[273,5047,5048,5050,5052,5054,5056,5058],{"class":275,"line":276},[273,5049,3898],{"class":330},[273,5051,334],{"class":290},[273,5053,1394],{"class":330},[273,5055,340],{"class":290},[273,5057,1399],{"class":314},[273,5059,1402],{"class":290},[273,5061,5062,5064,5066,5068,5070,5072,5074,5076],{"class":275,"line":283},[273,5063,3913],{"class":330},[273,5065,340],{"class":290},[273,5067,1412],{"class":314},[273,5069,346],{"class":290},[273,5071,1417],{"class":330},[273,5073,340],{"class":290},[273,5075,1422],{"class":330},[273,5077,1425],{"class":290},[273,5079,5080,5082,5084,5086,5088,5090,5092,5094,5096,5098,5100,5102,5104,5106],{"class":275,"line":301},[273,5081,3913],{"class":330},[273,5083,340],{"class":290},[273,5085,1434],{"class":314},[273,5087,346],{"class":290},[273,5089,1417],{"class":330},[273,5091,340],{"class":290},[273,5093,1443],{"class":314},[273,5095,346],{"class":290},[273,5097,1417],{"class":330},[273,5099,340],{"class":290},[273,5101,1452],{"class":314},[273,5103,346],{"class":290},[273,5105,1457],{"class":1176},[273,5107,1460],{"class":290},[273,5109,5110,5112,5114,5117],{"class":275,"line":308},[273,5111,3913],{"class":330},[273,5113,340],{"class":290},[273,5115,5116],{"class":314},"WithEncryption",[273,5118,1402],{"class":290},[273,5120,5121,5123,5125,5128],{"class":275,"line":324},[273,5122,1407],{"class":330},[273,5124,340],{"class":290},[273,5126,5127],{"class":330},"AES256",[273,5129,4258],{"class":290},[273,5131,5132,5135,5137,5139],{"class":275,"line":381},[273,5133,5134],{"class":290},"        \"",[273,5136,4842],{"class":362},[273,5138,359],{"class":290},[273,5140,4258],{"class":290},[273,5142,5143,5145,5147,5149],{"class":275,"line":400},[273,5144,5134],{"class":290},[273,5146,4857],{"class":362},[273,5148,359],{"class":290},[273,5150,4258],{"class":290},[273,5152,5153,5155,5157,5159,5162,5164,5166,5169],{"class":275,"line":406},[273,5154,1407],{"class":330},[273,5156,340],{"class":290},[273,5158,4812],{"class":330},[273,5160,5161],{"class":290},"|",[273,5163,24],{"class":330},[273,5165,340],{"class":290},[273,5167,5168],{"class":330},"PermCopyContent",[273,5170,4258],{"class":290},[273,5172,5173],{"class":275,"line":986},[273,5174,5175],{"class":290},"    ),\n",[273,5177,5178],{"class":275,"line":991},[273,5179,397],{"class":290},[273,5181,5182],{"class":275,"line":996},[273,5183,305],{"emptyLinePlaceholder":304},[273,5185,5186,5189,5191,5193,5195,5197],{"class":275,"line":1007},[273,5187,5188],{"class":330},"page ",[273,5190,334],{"class":290},[273,5192,1479],{"class":330},[273,5194,340],{"class":290},[273,5196,1484],{"class":314},[273,5198,1106],{"class":290},[273,5200,5201,5203,5205,5207,5209,5211,5213,5215,5217,5219,5221],{"class":275,"line":1048},[273,5202,2396],{"class":330},[273,5204,340],{"class":290},[273,5206,1496],{"class":314},[273,5208,1499],{"class":290},[273,5210,1503],{"class":1502},[273,5212,1506],{"class":290},[273,5214,1509],{"class":294},[273,5216,340],{"class":290},[273,5218,1514],{"class":294},[273,5220,585],{"class":290},[273,5222,321],{"class":290},[273,5224,5225,5227,5229,5231,5233,5235,5237,5239,5241,5243,5245,5247,5249,5251],{"class":275,"line":1063},[273,5226,2421],{"class":330},[273,5228,340],{"class":290},[273,5230,1528],{"class":314},[273,5232,346],{"class":290},[273,5234,1533],{"class":1176},[273,5236,437],{"class":290},[273,5238,1538],{"class":290},[273,5240,1541],{"class":1502},[273,5242,1506],{"class":290},[273,5244,1509],{"class":294},[273,5246,340],{"class":290},[273,5248,1550],{"class":294},[273,5250,585],{"class":290},[273,5252,321],{"class":290},[273,5254,5255,5257,5259,5261,5263,5265,5268,5270],{"class":275,"line":1068},[273,5256,2452],{"class":330},[273,5258,340],{"class":290},[273,5260,1564],{"class":314},[273,5262,346],{"class":290},[273,5264,359],{"class":290},[273,5266,5267],{"class":362},"Confidencial.",[273,5269,359],{"class":290},[273,5271,397],{"class":290},[273,5273,5274],{"class":275,"line":1073},[273,5275,1608],{"class":290},[273,5277,5278],{"class":275,"line":1078},[273,5279,2780],{"class":290},[273,5281,5282],{"class":275,"line":1090},[273,5283,305],{"emptyLinePlaceholder":304},[273,5285,5286,5289,5291,5293,5295,5297,5299,5301],{"class":275,"line":1109},[273,5287,5288],{"class":330},"data",[273,5290,437],{"class":290},[273,5292,440],{"class":330},[273,5294,334],{"class":290},[273,5296,1479],{"class":330},[273,5298,340],{"class":290},[273,5300,1630],{"class":314},[273,5302,1106],{"class":290},[273,5304,5305,5307,5309,5311,5313,5315,5317,5319,5321,5323,5325,5327],{"class":275,"line":1131},[273,5306,349],{"class":330},[273,5308,340],{"class":290},[273,5310,1677],{"class":314},[273,5312,346],{"class":290},[273,5314,359],{"class":290},[273,5316,5002],{"class":362},[273,5318,359],{"class":290},[273,5320,437],{"class":290},[273,5322,1690],{"class":330},[273,5324,437],{"class":290},[273,5326,1695],{"class":1176},[273,5328,397],{"class":290},[19,5330,5331,5332,5335,5336,5339],{},"Una opción, AES-256 por defecto, sin pasada de writer separada. Todo el camino de cifrado vive dentro del core MIT — mismo módulo, mismo ",[35,5333,5334],{},"go get",". Misma historia para firma digital: ",[35,5337,5338],{},"gpdf.SignDocument(pdfBytes, signer, gpdf.WithTSA(\"http://timestamp.digicert.com\"))"," pos-procesa los bytes con un timestamp PKCS#7 + RFC 3161, sin paquete extra ni registro de clave.",[14,5341,5343],{"id":5342},"qué-tan-rápido-es-el-resultado","¿Qué tan rápido es el resultado?",[19,5345,5346,5347,5350],{},"Benchmarks de ",[35,5348,5349],{},"_benchmark/benchmark_test.go"," en un Apple M1 con Go 1.25. unipdf no está en nuestra suite directamente porque sus términos de licencia hacían incómodo distribuir el código de comparación; los números de abajo son lo que recogimos en el mismo hardware contra las mismas cargas.",[120,5352,5353,5371],{},[123,5354,5355],{},[126,5356,5357,5360,5362,5365,5368],{},[129,5358,5359],{},"Benchmark",[129,5361,24],{},[129,5363,5364],{},"unipdf*",[129,5366,5367],{},"gofpdf",[129,5369,5370],{},"Maroto v2",[138,5372,5373,5392,5409,5428],{},[126,5374,5375,5378,5383,5386,5389],{},[143,5376,5377],{},"Página única",[143,5379,5380],{},[22,5381,5382],{},"13 µs",[143,5384,5385],{},"~180 µs",[143,5387,5388],{},"132 µs",[143,5390,5391],{},"237 µs",[126,5393,5394,5397,5401,5404,5407],{},[143,5395,5396],{},"Tabla 4×10 factura",[143,5398,5399],{},[22,5400,2803],{},[143,5402,5403],{},"~8,6 ms",[143,5405,5406],{},"241 µs",[143,5408,2799],{},[126,5410,5411,5414,5419,5422,5425],{},[143,5412,5413],{},"Reporte 100 páginas",[143,5415,5416],{},[22,5417,5418],{},"683 µs",[143,5420,5421],{},"~95 ms",[143,5423,5424],{},"11,7 ms",[143,5426,5427],{},"19,8 ms",[126,5429,5430,5433,5438,5441,5444],{},[143,5431,5432],{},"Factura CJK compleja",[143,5434,5435],{},[22,5436,5437],{},"133 µs",[143,5439,5440],{},"~12 ms",[143,5442,5443],{},"254 µs",[143,5445,5446],{},"10,4 ms",[19,5448,5449],{},"* Los números de unipdf son de una corrida aparte en el mismo Apple M1 / Go 1.25, capturados por nosotros contra el último unipdf v3 al momento de escribir. Trátalos como aproximados; no forman parte de nuestra suite versionada.",[19,5451,5452],{},"La forma es la misma que en la comparativa con gofpdf: gpdf es entre 10 y 80× más rápido en las cargas que la gente ejecuta de verdad. A 108 µs por página con tabla, un solo core puede producir ~9.000 facturas por segundo. El punto no es el alarde — es que puedes dejar de pensar si conviene cachear o encolar la generación de PDFs. Generar en el camino de la request alcanza para casi todo.",[14,5454,5456],{"id":5455},"y-las-partes-que-gpdf-no-tiene","¿Y las partes que gpdf no tiene?",[19,5458,5459],{},"Si tu factura de unipdf paga OCR, redacción o parsing de PDF, esta migración no llega hasta el final. Las opciones honestas:",[5461,5462,5463,5477,5489,5495],"ul",{},[91,5464,5465,5468,5469,5476],{},[22,5466,5467],{},"OCR."," gpdf no hace OCR y es improbable que lo haga. Usa ",[5470,5471,5475],"a",{"href":5472,"rel":5473},"https://github.com/tesseract-ocr/tesseract",[5474],"nofollow","Tesseract"," vía gosseract, o una API de OCR alojada. La generación se queda en gpdf, el parsing se queda en lo que elijas.",[91,5478,5479,5482,5483,5488],{},[22,5480,5481],{},"Parsing / extracción de texto."," gpdf es solo de generación por diseño. Para cargas de lectura, ",[5470,5484,5487],{"href":5485,"rel":5486},"https://github.com/pdfcpu/pdfcpu",[5474],"pdfcpu"," cubre muchos casos comunes (Apache 2.0). Mantén unipdf solo para parsing y puede que reduzcas asientos.",[91,5490,5491,5494],{},[22,5492,5493],{},"Creación de campos AcroForm."," gpdf puede aplanar campos AcroForm existentes; aún no puede crear nuevos. Si produces formularios para que los usuarios rellenen en un visor, este es el hueco que vas a sentir. Está en el roadmap.",[91,5496,5497,5500],{},[22,5498,5499],{},"Redacción."," No está en el roadmap de gpdf. La redacción necesita un renderer real para saber qué tachar, que es una arquitectura diferente a la generación.",[19,5502,5503,5504,5506],{},"Para el camino de ",[22,5505,254],{}," — el destino real de la mayoría de las facturas de unipdf — el cambio es completo.",[14,5508,5510],{"id":5509},"faq","FAQ",[19,5512,5513,5516],{},[22,5514,5515],{},"¿gpdf es un fork de unipdf?","\nNo. gpdf es una reimplementación limpia en Go puro. Formato de cable PDF, motor de layout, subseteador TrueType, AES, PKCS#7 — todo escrito desde cero. No hay código compartido, no hay linaje compartido, y no hay riesgo de que un argumento legal salga mal porque no se copió nada.",[19,5518,5519,5522,5523,5528],{},[22,5520,5521],{},"¿De verdad gpdf es MIT? ¿Sin \"AGPL bajo cierta condición\"?","\nSí. La ",[5470,5524,5527],{"href":5525,"rel":5526},"https://github.com/gpdf-dev/gpdf/blob/main/LICENSE",[5474],"LICENSE"," del repositorio es la licencia MIT literal, sin anexos, sin cláusulas de campo de uso, sin recortes de tier comercial. Úsalo en productos cerrados distribuibles, embébelo en SaaS comercial, súbelo dentro de appliances on-prem. La única obligación es la nota de licencia y copyright en tu distribución.",[19,5530,5531,5534,5535,5538,5539,5542,5543,5546,5547,340],{},[22,5532,5533],{},"¿Y las dependencias transitivas? ¿No hay copyleft escondido por ahí?","\nEl ",[35,5536,5537],{},"require"," del ",[35,5540,5541],{},"go.mod"," del core de gpdf está vacío. Sin AGPL transitiva, sin GPL transitiva, sin nada transitivo. Lo verificas con ",[35,5544,5545],{},"go mod graph | grep gpdf"," después del ",[35,5548,5334],{},[19,5550,5551,5554],{},[22,5552,5553],{},"¿En serio quitar la clave de licencia importa tanto?","\nPara algunos equipos es todo el partido. La clave debe vivir en tu gestor de secretos, rotarse, auditarse, ir en cada imagen de contenedor y no fugarse en logs. Para un SaaS multi-tenant con cientos de pods, eso es una superficie operacional real. Borrar el requisito elimina toda una clase de incidentes.",[19,5556,5557,5564,5565,5568,5569,5573],{},[22,5558,5559,5560,5563],{},"Mi código actual de unipdf usa ",[35,5561,5562],{},"creator.Block.SetPos"," para posiciones absolutas en todas partes. ¿Hay equivalente en gpdf?","\nSí — ",[35,5566,5567],{},"page.Absolute(x, y, fn)"," te deja meter un sub-árbol en una coordenada explícita. Pero si tu código está estructurado alrededor de manipulación de cursor, el modelo de motor de layout es un cambio mental, no sintáctico. Lee la ",[5470,5570,5572],{"href":5571},"/es/blog/12-column-grid","nota sobre la rejilla de 12 columnas"," antes de estimar; el código reescrito suele ser más corto que el original.",[19,5575,5576,5579],{},[22,5577,5578],{},"¿Y si UniDoc relicencia unipdf a MIT algún día?","\nTienes una opción más. La apuesta detrás de gpdf no es que unipdf vaya a quedarse en AGPL para siempre; es que una licencia que requiere una llamada de registro al arranque y una renovación por desarrollador a nivel financiero es un impuesto que no tiene por qué existir para la mayoría de las cargas. Aunque unipdf relicencie mañana, la superficie operacional de la clave seguiría ahí hasta que la quiten.",[14,5581,5583],{"id":5582},"probar-gpdf","Probar gpdf",[19,5585,5586],{},"gpdf es una biblioteca Go para generar PDFs. Licencia MIT, cero dependencias externas, sin clave de licencia, soporte CJK nativo.",[264,5588,5592],{"className":5589,"code":5590,"language":5591,"meta":269,"style":269},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","go get github.com/gpdf-dev/gpdf\n","bash",[35,5593,5594],{"__ignoreMap":269},[273,5595,5596,5598,5601],{"class":275,"line":276},[273,5597,268],{"class":294},[273,5599,5600],{"class":362}," get",[273,5602,5603],{"class":362}," github.com/gpdf-dev/gpdf\n",[19,5605,5606,5611,5612],{},[5470,5607,5610],{"href":5608,"rel":5609},"https://github.com/gpdf-dev/gpdf",[5474],"⭐ Star en GitHub"," · ",[5470,5613,5616],{"href":5614,"rel":5615},"https://gpdf.dev/es/docs/quickstart",[5474],"Lee los docs",[14,5618,5620],{"id":5619},"lecturas-siguientes","Lecturas siguientes",[5461,5622,5623,5629,5634,5640],{},[91,5624,5625],{},[5470,5626,5628],{"href":5627},"/es/blog/embed-japanese-font","Cómo embeber una fuente japonesa en gpdf",[91,5630,5631],{},[5470,5632,5633],{"href":5571},"La rejilla de 12 columnas: pensamiento Bootstrap aplicado al PDF",[91,5635,5636],{},[5470,5637,5639],{"href":5638},"/es/blog/gofpdf-migration","gofpdf está archivado. Cómo migrar a gpdf",[91,5641,5642,5646],{},[5470,5643,5645],{"href":5614,"rel":5644},[5474],"Quickstart"," — setup en cinco minutos",[2947,5648,5649],{},"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 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 .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 .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}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 .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}",{"title":269,"searchDepth":283,"depth":283,"links":5651},[5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664,5665,5666],{"id":16,"depth":283,"text":17},{"id":79,"depth":283,"text":80},{"id":114,"depth":283,"text":115},{"id":258,"depth":283,"text":259},{"id":558,"depth":283,"text":559},{"id":911,"depth":283,"text":912},{"id":1741,"depth":283,"text":1742},{"id":2814,"depth":283,"text":2815},{"id":3570,"depth":283,"text":3571},{"id":4560,"depth":283,"text":4561},{"id":5342,"depth":283,"text":5343},{"id":5455,"depth":283,"text":5456},{"id":5509,"depth":283,"text":5510},{"id":5582,"depth":283,"text":5583},{"id":5619,"depth":283,"text":5620},"2026-04-29","El unipdf de UniDoc obliga a AGPL v3 o a licencia comercial por desarrollador. Mapea la API creator de unipdf al gpdf — MIT, cero deps, sin clave.",false,"md",{"name":5672,"totalTime":5673,"tools":5674,"steps":5676},"Migrar un proyecto Go de unidoc/unipdf a gpdf","PT45M",[5675],"Go 1.22+",[5677,5679,5682,5685,5688,5691,5694],{"name":259,"text":5678},"Quita la llamada a license.SetMeteredKey o license.SetLicenseKey de unipdf en main y en cualquier bloque init(). gpdf no tiene clave de licencia, ni API de medición, ni registro al arranque.",{"name":5680,"text":5681},"Reemplazar las rutas de import","Cambia github.com/unidoc/unipdf/v3/creator y github.com/unidoc/unipdf/v3/model por github.com/gpdf-dev/gpdf, github.com/gpdf-dev/gpdf/document y github.com/gpdf-dev/gpdf/template.",{"name":5683,"text":5684},"Sustituir creator.New por gpdf.NewDocument","Construye el documento con gpdf.NewDocument(WithPageSize(document.A4), WithMargins(...)). Las páginas vienen de doc.AddPage() y devuelven un PageBuilder, no un cursor libre.",{"name":5686,"text":5687},"Convertir Paragraph y StyledParagraph en c.Text","Dentro de una columna, llama a c.Text(string, options...) en vez de construir un Paragraph y pasarlo a c.Draw. Fuente, tamaño y color pasan de campos de struct a opciones por texto.",{"name":5689,"text":5690},"Reescribir tablas con la rejilla de 12 columnas","Sustituye creator.NewTable(cols).SetColumnWidths y SetCellSpan por row.Col(span, fn) dentro de un AutoRow. La rejilla maneja anchos como porcentajes y reparte tablas entre páginas automáticamente.",{"name":5692,"text":5693},"Registrar fuentes como bytes, no como rutas","Reemplaza model.NewCompositePdfFontFromTTFFile por gpdf.WithFont(name, ttfBytes) en la construcción. Embebe el TTF con //go:embed para que el binario deje de necesitar una ruta de fuente en runtime.",{"name":5695,"text":5696},"Cambiar la llamada de salida","Sustituye c.WriteToFile(path) por doc.Generate() seguido de os.WriteFile(path, data, 0o644), o usa doc.Render(w) para escribir directo en un io.Writer.",null,{},"/es/blog/unidoc-migration",{"title":5,"description":5668},"es/blog/016.unidoc-migration",[5703,5704,5705],"migration","comparison","tutorial","sBS7f1wGL3O534er0SczLArloMZWwb20v1T0aY41iDs",1779199041867]