[{"data":1,"prerenderedAt":5360},["ShallowReactive",2],{"blog-es-signintech-gopdf-migration":3},{"id":4,"title":5,"author":6,"body":10,"date":5319,"description":5320,"draft":5321,"extension":5322,"howTo":5323,"image":5350,"meta":5351,"navigation":548,"path":5352,"seo":5353,"stem":5354,"tags":5355,"updated":5350,"__hash__":5359},"blogEs/es/blog/021.signintech-gopdf-migration.md","De signintech/gopdf a gpdf: menos cálculos de coordenadas",{"name":7,"url":8,"avatar":9},"Taiki Noda","https://nadai.dev/en/about","https://nadai.dev/og-default.png",{"type":11,"value":12,"toc":5302},"minimark",[13,18,39,59,62,65,69,72,75,84,87,91,94,104,126,129,133,136,485,509,513,516,521,1000,1005,1439,1446,1450,1453,1457,1916,1926,1930,2212,2229,2233,2239,2243,3034,3040,3044,3302,3308,3319,3323,3326,3330,3732,3739,3743,4000,4010,4014,4017,4021,4296,4299,4303,4655,4662,4666,4669,4929,4932,4936,4939,5034,5040,5047,5051,5054,5110,5117,5121,5127,5133,5147,5169,5191,5206,5223,5227,5230,5247,5262,5266,5298],[14,15,17],"h2",{"id":16},"tldr","TL;DR",[19,20,21,25,26,29,30,34,35,38],"p",{},[22,23,24],"strong",{},"gpdf"," es una biblioteca de PDF en Go puro con motor de layout de 12 columnas. ",[22,27,28],{},"signintech/gopdf"," es un binding de bajo nivel sobre el sistema de coordenadas PDF. Si llevas tiempo usando gopdf y la base de código ya es mayormente ",[31,32,33],"code",{},"SetXY",", ",[31,36,37],{},"Cell"," y aritmética de anchos, esta guía muestra en qué se colapsan esas llamadas cuando hay un motor de layout debajo.",[19,40,41,42,44,45,44,47,50,51,54,55,58],{},"La semana pasada estuve con alguien refactorizando un generador de facturas sobre signintech/gopdf. Cinco años de acumulación. La función que dibujaba la tabla de líneas de detalle tenía 280 líneas. Unas 40 hacían trabajo real: formatear el monto, formatear la fecha, repetir por fila. Las otras 240 calculaban posiciones x, rastreaban y, llamaban ",[31,43,33],{},", llamaban ",[31,46,37],{},[31,48,49],{},"Br",", dibujaban líneas de borde con ",[31,52,53],{},"Line(x1, y1, x2, y2)",", decidían si la fila cabía en la página o requería un ",[31,56,57],{},"AddPage"," manual y reimprimir el encabezado.",[19,60,61],{},"Esa es la experiencia gopdf en producción. No es una mala biblioteca. Es un binding delgado, rápido y sin CGO sobre el modelo de imaging de PDF — exactamente lo que el nombre promete. Hay un cursor, hay coordenadas, y el ingeniero hace de motor de layout.",[19,63,64],{},"Este artículo mapea la API de gopdf a gpdf, función por función. La tesis está en el título: la mayoría de las líneas desaparecen porque hacían matemática de layout que el runtime puede hacer por ti.",[14,66,68],{"id":67},"qué-es-signintechgopdf-y-qué-no","Qué es signintech/gopdf — y qué no",[19,70,71],{},"Vale la pena dejarlo claro antes de cualquier framing de \"migra ya\", porque gopdf tiene virtudes reales.",[19,73,74],{},"Está mantenido activamente. Es Go puro (sin CGO), así que la cross-compilación e imágenes Alpine simplemente funcionan. Soporta fuentes TrueType incluyendo CJK. La salida es rápida — gopdf está en la misma liga que gpdf en las primitivas de imaging porque ambos escriben el wire format PDF directamente sin un motor pesado delante. La API mapea limpiamente al modelo PDF subyacente: hay un punto actual, lo mueves, dibujas en él. Si ya piensas en coordenadas PDF, gopdf es cómodo.",[19,76,77,78,80,81,83],{},"Lo que no es, es un sistema de layout. No hay noción de fila, columna, contenedor flex o grilla. No hay salto de página automático: cuando tu contenido pasa el margen inferior, obtienes contenido pasando el margen inferior (o fuera de la página) hasta que llamas ",[31,79,57],{}," tú mismo. Las tablas no existen como primitiva — son un patrón que reimplementas en cada proyecto, con llamadas ",[31,82,37],{}," celda a celda, líneas de borde manuales y tu propia lógica de salto de página.",[19,85,86],{},"Para un certificado de una página o un formulario de plantilla fija muy controlado, el modelo de cursor está bien. Para facturas, reportes, estados de cuenta, cualquier cosa con contenido de longitud variable — la matemática de coordenadas crece con la superficie del documento. Esa es la carga de trabajo para la que gpdf está construido.",[14,88,90],{"id":89},"el-cambio-de-modelo-mental","El cambio de modelo mental",[19,92,93],{},"Esta es la parte que cambia realmente cómo se lee el código. gpdf tiene dos ideas que gopdf no:",[19,95,96,99,100,103],{},[22,97,98],{},"Árbol declarativo."," No le dices al renderer dónde poner las cosas. Describes un árbol de páginas → filas → columnas → contenido, y el motor de layout resuelve posiciones en una sola pasada. No hay cursor que avanzar. Dos ",[31,101,102],{},"r.Col(...)"," consecutivos no necesitan saber el uno del otro.",[19,105,106,109,110,113,114,117,118,121,122,125],{},[22,107,108],{},"Grilla de 12 columnas."," Cada fila es implícitamente de 12 unidades de ancho. Las gastas entre columnas: ",[31,111,112],{},"r.Col(8, ...)"," toma dos tercios, ",[31,115,116],{},"r.Col(4, ...)"," toma un tercio. La grilla es la misma idea que Bootstrap y Tailwind usan para HTML, aplicada a PDF. Dejas de calcular ",[31,119,120],{},"pageWidth - leftMargin - rightMargin"," dividido entre 4. Escribes ",[31,123,124],{},"r.Col(3, ...)"," cuatro veces.",[19,127,128],{},"Estas dos ideas eliminan la mayor parte de la matemática. Los pares before/after que siguen colapsan todos de la misma manera: un bucle imperativo que avanza un cursor se convierte en un pequeño árbol declarativo.",[14,130,132],{"id":131},"la-tabla-de-mapeo-de-api","La tabla de mapeo de API",[19,134,135],{},"Hoja de referencia primero. Las secciones después recorren cinco pares concretos.",[137,138,139,153],"table",{},[140,141,142],"thead",{},[143,144,145,149,151],"tr",{},[146,147,148],"th",{},"Lo que quieres hacer",[146,150,28],{},[146,152,24],{},[154,155,156,172,187,202,222,240,258,277,295,311,326,341,356,371,392,414,437,452,467],"tbody",{},[143,157,158,162,167],{},[159,160,161],"td",{},"Construir",[159,163,164],{},[31,165,166],{},"pdf := gopdf.GoPdf{}; pdf.Start(gopdf.Config{...})",[159,168,169],{},[31,170,171],{},"doc := gpdf.NewDocument(gpdf.WithPageSize(document.A4), ...)",[143,173,174,177,182],{},[159,175,176],{},"Tamaño de página",[159,178,179],{},[31,180,181],{},"Config{PageSize: gopdf.PageSizeA4}",[159,183,184],{},[31,185,186],{},"gpdf.WithPageSize(document.A4)",[143,188,189,192,197],{},[159,190,191],{},"Añadir página",[159,193,194],{},[31,195,196],{},"pdf.AddPage()",[159,198,199],{},[31,200,201],{},"page := doc.AddPage()",[143,203,204,207,217],{},[159,205,206],{},"Mover cursor",[159,208,209,212,213],{},[31,210,211],{},"pdf.SetX(40); pdf.SetY(80)"," ",[214,215,216],"em",{},"(en todas partes)",[159,218,219],{},[214,220,221],{},"(sin cursor)",[143,223,224,227,232],{},[159,225,226],{},"Una línea de texto",[159,228,229],{},[31,230,231],{},"pdf.SetXY(x, y); pdf.Cell(nil, \"hi\")",[159,233,234,212,237],{},[31,235,236],{},"c.Text(\"hi\")",[214,238,239],{},"(dentro de una columna)",[143,241,242,245,250],{},[159,243,244],{},"Texto con ajuste",[159,246,247],{},[31,248,249],{},"pdf.MultiCell(&gopdf.Rect{W: 200, H: 100}, body)",[159,251,252,212,255],{},[31,253,254],{},"c.Text(body)",[214,256,257],{},"(ajusta solo)",[143,259,260,263,268],{},[159,261,262],{},"Salto de línea",[159,264,265],{},[31,266,267],{},"pdf.Br(20)",[159,269,270],{},[214,271,272,273,276],{},"(implícito entre filas; ",[31,274,275],{},"c.Spacer(document.Mm(4))"," si hace falta)",[143,278,279,282,287],{},[159,280,281],{},"Registro de fuente",[159,283,284],{},[31,285,286],{},"pdf.AddTTFFont(\"noto\", \"fonts/Noto.ttf\")",[159,288,289,212,292],{},[31,290,291],{},"gpdf.WithFont(\"Noto\", ttfBytes)",[214,293,294],{},"(en construcción)",[143,296,297,300,305],{},[159,298,299],{},"Fuente activa",[159,301,302],{},[31,303,304],{},"pdf.SetFont(\"noto\", \"\", 14)",[159,306,307,308],{},"por texto: ",[31,309,310],{},"template.FontFamily(\"Noto\"), template.FontSize(14)",[143,312,313,316,321],{},[159,314,315],{},"Color",[159,317,318],{},[31,319,320],{},"pdf.SetTextColor(26, 35, 126)",[159,322,323],{},[31,324,325],{},"template.TextColor(pdf.RGBHex(0x1A237E))",[143,327,328,331,336],{},[159,329,330],{},"Línea horizontal",[159,332,333],{},[31,334,335],{},"pdf.Line(40, 100, 555, 100)",[159,337,338],{},[31,339,340],{},"c.Line(template.LineColor(pdf.Gray(0.7)))",[143,342,343,346,351],{},[159,344,345],{},"Rectángulo",[159,347,348],{},[31,349,350],{},"pdf.RectFromUpperLeftWithStyle(x, y, w, h, \"FD\")",[159,352,353],{},[31,354,355],{},"c.Box(template.BgColor(...), template.Border(...))",[143,357,358,361,366],{},[159,359,360],{},"Imagen",[159,362,363],{},[31,364,365],{},"pdf.Image(\"logo.png\", x, y, &gopdf.Rect{W: 100, H: 50})",[159,367,368],{},[31,369,370],{},"c.Image(imgBytes, template.FitWidth(document.Mm(35)))",[143,372,373,376,387],{},[159,374,375],{},"Tabla manual",[159,377,378,379,381,382,381,385],{},"docenas de ",[31,380,37],{}," + ",[31,383,384],{},"Line",[31,386,33],{},[159,388,389],{},[31,390,391],{},"c.Table(headers, rows, template.ColumnWidths(...))",[143,393,394,397,406],{},[159,395,396],{},"Encabezado / pie",[159,398,399,402,403],{},[31,400,401],{},"pdf.AddHeader(fn)"," / ",[31,404,405],{},"pdf.AddFooter(fn)",[159,407,408,402,411],{},[31,409,410],{},"doc.Header(fn)",[31,412,413],{},"doc.Footer(fn)",[143,415,416,419,426],{},[159,417,418],{},"Número de página",[159,420,421,422,425],{},"formateas ",[31,423,424],{},"\"Page %d of %d\""," desde un contador propio",[159,427,428,402,431,212,434],{},[31,429,430],{},"c.PageNumber()",[31,432,433],{},"c.TotalPages()",[214,435,436],{},"(placeholders)",[143,438,439,442,447],{},[159,440,441],{},"Cifrar",[159,443,444],{},[31,445,446],{},"Config{Protection: PDFProtectionConfig{...}}",[159,448,449],{},[31,450,451],{},"gpdf.WithEncryption(gpdf.AES256, \"user\", \"owner\", perms)",[143,453,454,457,462],{},[159,455,456],{},"Salida",[159,458,459],{},[31,460,461],{},"pdf.WritePdf(\"out.pdf\")",[159,463,464],{},[31,465,466],{},"data, _ := doc.Generate(); os.WriteFile(\"out.pdf\", data, 0o644)",[143,468,469,472,480],{},[159,470,471],{},"Salida a writer",[159,473,474,402,477],{},[31,475,476],{},"pdf.Write(w)",[31,478,479],{},"pdf.ToBuffer()",[159,481,482],{},[31,483,484],{},"doc.Render(w)",[19,486,487,488,491,492,494,495,497,498,500,501,504,505,508],{},"Dos cambios estructurales. Primero, ",[22,489,490],{},"el cursor desaparece",". Las filas marcadas ",[214,493,216],{}," en la tabla no son exageración — en una base de código gopdf real, las llamadas a ",[31,496,33],{}," superan en número a las de ",[31,499,37],{},". Todas colapsan a nada en gpdf. Segundo, ",[22,502,503],{},"los píxeles se vuelven porcentajes",". ",[31,506,507],{},"Rect{W: 200, H: 100}"," se vuelve \"esta columna toma 4 de 12 unidades de cualquier contenedor en el que esté\". Pon la misma columna dentro de una fila a media anchura y escala sin cambios.",[14,510,512],{"id":511},"before-after-1-hello-world","Before / After 1: hello world",[19,514,515],{},"La diferencia más corta posible. Mira lo que falta a la derecha.",[19,517,518],{},[22,519,520],{},"Before — signintech/gopdf:",[522,523,528],"pre",{"className":524,"code":525,"language":526,"meta":527,"style":527},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","package main\n\nimport (\n    \"log\"\n\n    \"github.com/signintech/gopdf\"\n)\n\nfunc main() {\n    pdf := gopdf.GoPdf{}\n    pdf.Start(gopdf.Config{PageSize: *gopdf.PageSizeA4})\n    pdf.AddPage()\n\n    if err := pdf.AddTTFFont(\"helvetica\", \"fonts/Helvetica.ttf\"); err != nil {\n        log.Fatal(err)\n    }\n    if err := pdf.SetFont(\"helvetica\", \"\", 24); err != nil {\n        log.Fatal(err)\n    }\n\n    pdf.SetX(40)\n    pdf.SetY(80)\n    if err := pdf.Cell(nil, \"¡Hola, mundo!\"); err != nil {\n        log.Fatal(err)\n    }\n\n    if err := pdf.WritePdf(\"hello.pdf\"); err != nil {\n        log.Fatal(err)\n    }\n}\n","go","",[31,529,530,543,550,560,572,577,587,593,598,614,636,680,692,697,751,769,775,820,835,840,845,862,879,914,929,934,939,974,989,994],{"__ignoreMap":527},[531,532,535,539],"span",{"class":533,"line":534},"line",1,[531,536,538],{"class":537},"sMK4o","package",[531,540,542],{"class":541},"sBMFI"," main\n",[531,544,546],{"class":533,"line":545},2,[531,547,549],{"emptyLinePlaceholder":548},true,"\n",[531,551,553,557],{"class":533,"line":552},3,[531,554,556],{"class":555},"s7zQu","import",[531,558,559],{"class":537}," (\n",[531,561,563,566,569],{"class":533,"line":562},4,[531,564,565],{"class":537},"    \"",[531,567,568],{"class":541},"log",[531,570,571],{"class":537},"\"\n",[531,573,575],{"class":533,"line":574},5,[531,576,549],{"emptyLinePlaceholder":548},[531,578,580,582,585],{"class":533,"line":579},6,[531,581,565],{"class":537},[531,583,584],{"class":541},"github.com/signintech/gopdf",[531,586,571],{"class":537},[531,588,590],{"class":533,"line":589},7,[531,591,592],{"class":537},")\n",[531,594,596],{"class":533,"line":595},8,[531,597,549],{"emptyLinePlaceholder":548},[531,599,601,604,608,611],{"class":533,"line":600},9,[531,602,603],{"class":537},"func",[531,605,607],{"class":606},"s2Zo4"," main",[531,609,610],{"class":537},"()",[531,612,613],{"class":537}," {\n",[531,615,617,621,624,627,630,633],{"class":533,"line":616},10,[531,618,620],{"class":619},"sTEyZ","    pdf ",[531,622,623],{"class":537},":=",[531,625,626],{"class":541}," gopdf",[531,628,629],{"class":537},".",[531,631,632],{"class":541},"GoPdf",[531,634,635],{"class":537},"{}\n",[531,637,639,642,644,647,650,653,655,658,661,664,667,670,672,674,677],{"class":533,"line":638},11,[531,640,641],{"class":619},"    pdf",[531,643,629],{"class":537},[531,645,646],{"class":606},"Start",[531,648,649],{"class":537},"(",[531,651,652],{"class":541},"gopdf",[531,654,629],{"class":537},[531,656,657],{"class":541},"Config",[531,659,660],{"class":537},"{",[531,662,663],{"class":619},"PageSize",[531,665,666],{"class":537},":",[531,668,669],{"class":537}," *",[531,671,652],{"class":619},[531,673,629],{"class":537},[531,675,676],{"class":619},"PageSizeA4",[531,678,679],{"class":537},"})\n",[531,681,683,685,687,689],{"class":533,"line":682},12,[531,684,641],{"class":619},[531,686,629],{"class":537},[531,688,57],{"class":606},[531,690,691],{"class":537},"()\n",[531,693,695],{"class":533,"line":694},13,[531,696,549],{"emptyLinePlaceholder":548},[531,698,700,703,706,708,711,713,716,718,721,725,727,730,733,736,738,741,743,746,749],{"class":533,"line":699},14,[531,701,702],{"class":555},"    if",[531,704,705],{"class":619}," err ",[531,707,623],{"class":537},[531,709,710],{"class":619}," pdf",[531,712,629],{"class":537},[531,714,715],{"class":606},"AddTTFFont",[531,717,649],{"class":537},[531,719,720],{"class":537},"\"",[531,722,724],{"class":723},"sfazB","helvetica",[531,726,720],{"class":537},[531,728,729],{"class":537},",",[531,731,732],{"class":537}," \"",[531,734,735],{"class":723},"fonts/Helvetica.ttf",[531,737,720],{"class":537},[531,739,740],{"class":537},");",[531,742,705],{"class":619},[531,744,745],{"class":537},"!=",[531,747,748],{"class":537}," nil",[531,750,613],{"class":537},[531,752,754,757,759,762,764,767],{"class":533,"line":753},15,[531,755,756],{"class":619},"        log",[531,758,629],{"class":537},[531,760,761],{"class":606},"Fatal",[531,763,649],{"class":537},[531,765,766],{"class":619},"err",[531,768,592],{"class":537},[531,770,772],{"class":533,"line":771},16,[531,773,774],{"class":537},"    }\n",[531,776,778,780,782,784,786,788,791,793,795,797,799,801,804,806,810,812,814,816,818],{"class":533,"line":777},17,[531,779,702],{"class":555},[531,781,705],{"class":619},[531,783,623],{"class":537},[531,785,710],{"class":619},[531,787,629],{"class":537},[531,789,790],{"class":606},"SetFont",[531,792,649],{"class":537},[531,794,720],{"class":537},[531,796,724],{"class":723},[531,798,720],{"class":537},[531,800,729],{"class":537},[531,802,803],{"class":537}," \"\"",[531,805,729],{"class":537},[531,807,809],{"class":808},"sbssI"," 24",[531,811,740],{"class":537},[531,813,705],{"class":619},[531,815,745],{"class":537},[531,817,748],{"class":537},[531,819,613],{"class":537},[531,821,823,825,827,829,831,833],{"class":533,"line":822},18,[531,824,756],{"class":619},[531,826,629],{"class":537},[531,828,761],{"class":606},[531,830,649],{"class":537},[531,832,766],{"class":619},[531,834,592],{"class":537},[531,836,838],{"class":533,"line":837},19,[531,839,774],{"class":537},[531,841,843],{"class":533,"line":842},20,[531,844,549],{"emptyLinePlaceholder":548},[531,846,848,850,852,855,857,860],{"class":533,"line":847},21,[531,849,641],{"class":619},[531,851,629],{"class":537},[531,853,854],{"class":606},"SetX",[531,856,649],{"class":537},[531,858,859],{"class":808},"40",[531,861,592],{"class":537},[531,863,865,867,869,872,874,877],{"class":533,"line":864},22,[531,866,641],{"class":619},[531,868,629],{"class":537},[531,870,871],{"class":606},"SetY",[531,873,649],{"class":537},[531,875,876],{"class":808},"80",[531,878,592],{"class":537},[531,880,882,884,886,888,890,892,894,897,899,902,904,906,908,910,912],{"class":533,"line":881},23,[531,883,702],{"class":555},[531,885,705],{"class":619},[531,887,623],{"class":537},[531,889,710],{"class":619},[531,891,629],{"class":537},[531,893,37],{"class":606},[531,895,896],{"class":537},"(nil,",[531,898,732],{"class":537},[531,900,901],{"class":723},"¡Hola, mundo!",[531,903,720],{"class":537},[531,905,740],{"class":537},[531,907,705],{"class":619},[531,909,745],{"class":537},[531,911,748],{"class":537},[531,913,613],{"class":537},[531,915,917,919,921,923,925,927],{"class":533,"line":916},24,[531,918,756],{"class":619},[531,920,629],{"class":537},[531,922,761],{"class":606},[531,924,649],{"class":537},[531,926,766],{"class":619},[531,928,592],{"class":537},[531,930,932],{"class":533,"line":931},25,[531,933,774],{"class":537},[531,935,937],{"class":533,"line":936},26,[531,938,549],{"emptyLinePlaceholder":548},[531,940,942,944,946,948,950,952,955,957,959,962,964,966,968,970,972],{"class":533,"line":941},27,[531,943,702],{"class":555},[531,945,705],{"class":619},[531,947,623],{"class":537},[531,949,710],{"class":619},[531,951,629],{"class":537},[531,953,954],{"class":606},"WritePdf",[531,956,649],{"class":537},[531,958,720],{"class":537},[531,960,961],{"class":723},"hello.pdf",[531,963,720],{"class":537},[531,965,740],{"class":537},[531,967,705],{"class":619},[531,969,745],{"class":537},[531,971,748],{"class":537},[531,973,613],{"class":537},[531,975,977,979,981,983,985,987],{"class":533,"line":976},28,[531,978,756],{"class":619},[531,980,629],{"class":537},[531,982,761],{"class":606},[531,984,649],{"class":537},[531,986,766],{"class":619},[531,988,592],{"class":537},[531,990,992],{"class":533,"line":991},29,[531,993,774],{"class":537},[531,995,997],{"class":533,"line":996},30,[531,998,999],{"class":537},"}\n",[19,1001,1002],{},[22,1003,1004],{},"After — gpdf:",[522,1006,1008],{"className":524,"code":1007,"language":526,"meta":527,"style":527},"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(\"¡Hola, mundo!\", 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",[31,1009,1010,1016,1020,1026,1034,1043,1047,1056,1065,1074,1078,1082,1092,1110,1133,1168,1173,1177,1193,1225,1261,1307,1312,1317,1321,1341,1353,1367,1371,1415,1429,1434],{"__ignoreMap":527},[531,1011,1012,1014],{"class":533,"line":534},[531,1013,538],{"class":537},[531,1015,542],{"class":541},[531,1017,1018],{"class":533,"line":545},[531,1019,549],{"emptyLinePlaceholder":548},[531,1021,1022,1024],{"class":533,"line":552},[531,1023,556],{"class":555},[531,1025,559],{"class":537},[531,1027,1028,1030,1032],{"class":533,"line":562},[531,1029,565],{"class":537},[531,1031,568],{"class":541},[531,1033,571],{"class":537},[531,1035,1036,1038,1041],{"class":533,"line":574},[531,1037,565],{"class":537},[531,1039,1040],{"class":541},"os",[531,1042,571],{"class":537},[531,1044,1045],{"class":533,"line":579},[531,1046,549],{"emptyLinePlaceholder":548},[531,1048,1049,1051,1054],{"class":533,"line":589},[531,1050,565],{"class":537},[531,1052,1053],{"class":541},"github.com/gpdf-dev/gpdf",[531,1055,571],{"class":537},[531,1057,1058,1060,1063],{"class":533,"line":595},[531,1059,565],{"class":537},[531,1061,1062],{"class":541},"github.com/gpdf-dev/gpdf/document",[531,1064,571],{"class":537},[531,1066,1067,1069,1072],{"class":533,"line":600},[531,1068,565],{"class":537},[531,1070,1071],{"class":541},"github.com/gpdf-dev/gpdf/template",[531,1073,571],{"class":537},[531,1075,1076],{"class":533,"line":616},[531,1077,592],{"class":537},[531,1079,1080],{"class":533,"line":638},[531,1081,549],{"emptyLinePlaceholder":548},[531,1083,1084,1086,1088,1090],{"class":533,"line":682},[531,1085,603],{"class":537},[531,1087,607],{"class":606},[531,1089,610],{"class":537},[531,1091,613],{"class":537},[531,1093,1094,1097,1099,1102,1104,1107],{"class":533,"line":694},[531,1095,1096],{"class":619},"    doc ",[531,1098,623],{"class":537},[531,1100,1101],{"class":619}," gpdf",[531,1103,629],{"class":537},[531,1105,1106],{"class":606},"NewDocument",[531,1108,1109],{"class":537},"(\n",[531,1111,1112,1115,1117,1120,1122,1125,1127,1130],{"class":533,"line":699},[531,1113,1114],{"class":619},"        gpdf",[531,1116,629],{"class":537},[531,1118,1119],{"class":606},"WithPageSize",[531,1121,649],{"class":537},[531,1123,1124],{"class":619},"document",[531,1126,629],{"class":537},[531,1128,1129],{"class":619},"A4",[531,1131,1132],{"class":537},"),\n",[531,1134,1135,1137,1139,1142,1144,1146,1148,1151,1153,1155,1157,1160,1162,1165],{"class":533,"line":753},[531,1136,1114],{"class":619},[531,1138,629],{"class":537},[531,1140,1141],{"class":606},"WithMargins",[531,1143,649],{"class":537},[531,1145,1124],{"class":619},[531,1147,629],{"class":537},[531,1149,1150],{"class":606},"UniformEdges",[531,1152,649],{"class":537},[531,1154,1124],{"class":619},[531,1156,629],{"class":537},[531,1158,1159],{"class":606},"Mm",[531,1161,649],{"class":537},[531,1163,1164],{"class":808},"20",[531,1166,1167],{"class":537},"))),\n",[531,1169,1170],{"class":533,"line":771},[531,1171,1172],{"class":537},"    )\n",[531,1174,1175],{"class":533,"line":777},[531,1176,549],{"emptyLinePlaceholder":548},[531,1178,1179,1182,1184,1187,1189,1191],{"class":533,"line":822},[531,1180,1181],{"class":619},"    page ",[531,1183,623],{"class":537},[531,1185,1186],{"class":619}," doc",[531,1188,629],{"class":537},[531,1190,57],{"class":606},[531,1192,691],{"class":537},[531,1194,1195,1198,1200,1203,1206,1210,1212,1215,1217,1220,1223],{"class":533,"line":837},[531,1196,1197],{"class":619},"    page",[531,1199,629],{"class":537},[531,1201,1202],{"class":606},"AutoRow",[531,1204,1205],{"class":537},"(func(",[531,1207,1209],{"class":1208},"sHdIc","r",[531,1211,669],{"class":537},[531,1213,1214],{"class":541},"template",[531,1216,629],{"class":537},[531,1218,1219],{"class":541},"RowBuilder",[531,1221,1222],{"class":537},")",[531,1224,613],{"class":537},[531,1226,1227,1230,1232,1235,1237,1240,1242,1245,1248,1250,1252,1254,1257,1259],{"class":533,"line":842},[531,1228,1229],{"class":619},"        r",[531,1231,629],{"class":537},[531,1233,1234],{"class":606},"Col",[531,1236,649],{"class":537},[531,1238,1239],{"class":808},"12",[531,1241,729],{"class":537},[531,1243,1244],{"class":537}," func(",[531,1246,1247],{"class":1208},"c",[531,1249,669],{"class":537},[531,1251,1214],{"class":541},[531,1253,629],{"class":537},[531,1255,1256],{"class":541},"ColBuilder",[531,1258,1222],{"class":537},[531,1260,613],{"class":537},[531,1262,1263,1266,1268,1271,1273,1275,1277,1279,1281,1284,1286,1289,1291,1294,1297,1299,1301,1304],{"class":533,"line":847},[531,1264,1265],{"class":619},"            c",[531,1267,629],{"class":537},[531,1269,1270],{"class":606},"Text",[531,1272,649],{"class":537},[531,1274,720],{"class":537},[531,1276,901],{"class":723},[531,1278,720],{"class":537},[531,1280,729],{"class":537},[531,1282,1283],{"class":619}," template",[531,1285,629],{"class":537},[531,1287,1288],{"class":606},"FontSize",[531,1290,649],{"class":537},[531,1292,1293],{"class":808},"24",[531,1295,1296],{"class":537},"),",[531,1298,1283],{"class":619},[531,1300,629],{"class":537},[531,1302,1303],{"class":606},"Bold",[531,1305,1306],{"class":537},"())\n",[531,1308,1309],{"class":533,"line":864},[531,1310,1311],{"class":537},"        })\n",[531,1313,1314],{"class":533,"line":881},[531,1315,1316],{"class":537},"    })\n",[531,1318,1319],{"class":533,"line":916},[531,1320,549],{"emptyLinePlaceholder":548},[531,1322,1323,1326,1328,1330,1332,1334,1336,1339],{"class":533,"line":931},[531,1324,1325],{"class":619},"    data",[531,1327,729],{"class":537},[531,1329,705],{"class":619},[531,1331,623],{"class":537},[531,1333,1186],{"class":619},[531,1335,629],{"class":537},[531,1337,1338],{"class":606},"Generate",[531,1340,691],{"class":537},[531,1342,1343,1345,1347,1349,1351],{"class":533,"line":936},[531,1344,702],{"class":555},[531,1346,705],{"class":619},[531,1348,745],{"class":537},[531,1350,748],{"class":537},[531,1352,613],{"class":537},[531,1354,1355,1357,1359,1361,1363,1365],{"class":533,"line":941},[531,1356,756],{"class":619},[531,1358,629],{"class":537},[531,1360,761],{"class":606},[531,1362,649],{"class":537},[531,1364,766],{"class":619},[531,1366,592],{"class":537},[531,1368,1369],{"class":533,"line":976},[531,1370,774],{"class":537},[531,1372,1373,1375,1377,1379,1382,1384,1387,1389,1391,1393,1395,1397,1400,1402,1405,1407,1409,1411,1413],{"class":533,"line":991},[531,1374,702],{"class":555},[531,1376,705],{"class":619},[531,1378,623],{"class":537},[531,1380,1381],{"class":619}," os",[531,1383,629],{"class":537},[531,1385,1386],{"class":606},"WriteFile",[531,1388,649],{"class":537},[531,1390,720],{"class":537},[531,1392,961],{"class":723},[531,1394,720],{"class":537},[531,1396,729],{"class":537},[531,1398,1399],{"class":619}," data",[531,1401,729],{"class":537},[531,1403,1404],{"class":808}," 0o644",[531,1406,740],{"class":537},[531,1408,705],{"class":619},[531,1410,745],{"class":537},[531,1412,748],{"class":537},[531,1414,613],{"class":537},[531,1416,1417,1419,1421,1423,1425,1427],{"class":533,"line":996},[531,1418,756],{"class":619},[531,1420,629],{"class":537},[531,1422,761],{"class":606},[531,1424,649],{"class":537},[531,1426,766],{"class":619},[531,1428,592],{"class":537},[531,1430,1432],{"class":533,"line":1431},31,[531,1433,774],{"class":537},[531,1435,1437],{"class":533,"line":1436},32,[531,1438,999],{"class":537},[19,1440,1441,1442,1445],{},"Dos cosas que faltan. El archivo TTF ya no es requerido en runtime — Helvetica es parte de las 14 fuentes estándar y gpdf las trae incluidas. El ",[31,1443,1444],{},"SetX(40); SetY(80)"," desapareció — la fila se sienta dentro de los márgenes de la página automáticamente. Lo añadido: una fila con una columna que abarca las 12 unidades. Ese andamiaje se ve pesado para \"¡Hola, mundo!\", pero es el mismo andamiaje que sostiene un reporte de 100 páginas, que es justamente el punto.",[14,1447,1449],{"id":1448},"before-after-2-una-fila-de-encabezado-de-4-columnas","Before / After 2: una fila de encabezado de 4 columnas",[19,1451,1452],{},"Aquí es donde la matemática de coordenadas se ve más. Quieres una franja de encabezado a través de la página con cuatro celdas iguales: ancho de página menos márgenes, dividido entre cuatro. En gopdf haces esa división. En gpdf gastas 12 unidades en cuatro maneras.",[19,1454,1455],{},[22,1456,520],{},[522,1458,1460],{"className":524,"code":1459,"language":526,"meta":527,"style":527},"const (\n    pageWidth   = 595.28 // A4 (pt)\n    leftMargin  = 40.0\n    rightMargin = 40.0\n    rowY        = 100.0\n    rowH        = 24.0\n)\n\ncontentWidth := pageWidth - leftMargin - rightMargin // 515.28\ncolW := contentWidth / 4                              // 128.82\n\npdf.SetFont(\"helvetica-bold\", \"\", 11)\npdf.SetFillColor(26, 35, 126)\npdf.SetTextColor(255, 255, 255)\n\nheaders := []string{\"Concepto\", \"Cant.\", \"Unitario\", \"Importe\"}\nfor i, h := range headers {\n    x := leftMargin + colW*float64(i)\n    pdf.RectFromUpperLeftWithStyle(x, rowY, colW, rowH, \"F\")\n\n    pdf.SetXY(x+6, rowY+7)\n    if err := pdf.Cell(nil, h); err != nil {\n        log.Fatal(err)\n    }\n}\n\npdf.SetTextColor(0, 0, 0)\n",[31,1461,1462,1469,1484,1494,1503,1513,1523,1527,1531,1555,1574,1578,1607,1633,1658,1662,1714,1738,1766,1805,1809,1837,1866,1880,1884,1888,1892],{"__ignoreMap":527},[531,1463,1464,1467],{"class":533,"line":534},[531,1465,1466],{"class":537},"const",[531,1468,559],{"class":537},[531,1470,1471,1474,1477,1480],{"class":533,"line":545},[531,1472,1473],{"class":619},"    pageWidth   ",[531,1475,1476],{"class":537},"=",[531,1478,1479],{"class":808}," 595.28",[531,1481,1483],{"class":1482},"sHwdD"," // A4 (pt)\n",[531,1485,1486,1489,1491],{"class":533,"line":552},[531,1487,1488],{"class":619},"    leftMargin  ",[531,1490,1476],{"class":537},[531,1492,1493],{"class":808}," 40.0\n",[531,1495,1496,1499,1501],{"class":533,"line":562},[531,1497,1498],{"class":619},"    rightMargin ",[531,1500,1476],{"class":537},[531,1502,1493],{"class":808},[531,1504,1505,1508,1510],{"class":533,"line":574},[531,1506,1507],{"class":619},"    rowY        ",[531,1509,1476],{"class":537},[531,1511,1512],{"class":808}," 100.0\n",[531,1514,1515,1518,1520],{"class":533,"line":579},[531,1516,1517],{"class":619},"    rowH        ",[531,1519,1476],{"class":537},[531,1521,1522],{"class":808}," 24.0\n",[531,1524,1525],{"class":533,"line":589},[531,1526,592],{"class":537},[531,1528,1529],{"class":533,"line":595},[531,1530,549],{"emptyLinePlaceholder":548},[531,1532,1533,1536,1538,1541,1544,1547,1549,1552],{"class":533,"line":600},[531,1534,1535],{"class":619},"contentWidth ",[531,1537,623],{"class":537},[531,1539,1540],{"class":619}," pageWidth ",[531,1542,1543],{"class":537},"-",[531,1545,1546],{"class":619}," leftMargin ",[531,1548,1543],{"class":537},[531,1550,1551],{"class":619}," rightMargin ",[531,1553,1554],{"class":1482},"// 515.28\n",[531,1556,1557,1560,1562,1565,1568,1571],{"class":533,"line":616},[531,1558,1559],{"class":619},"colW ",[531,1561,623],{"class":537},[531,1563,1564],{"class":619}," contentWidth ",[531,1566,1567],{"class":537},"/",[531,1569,1570],{"class":808}," 4",[531,1572,1573],{"class":1482},"                              // 128.82\n",[531,1575,1576],{"class":533,"line":638},[531,1577,549],{"emptyLinePlaceholder":548},[531,1579,1580,1583,1585,1587,1589,1591,1594,1596,1598,1600,1602,1605],{"class":533,"line":682},[531,1581,1582],{"class":619},"pdf",[531,1584,629],{"class":537},[531,1586,790],{"class":606},[531,1588,649],{"class":537},[531,1590,720],{"class":537},[531,1592,1593],{"class":723},"helvetica-bold",[531,1595,720],{"class":537},[531,1597,729],{"class":537},[531,1599,803],{"class":537},[531,1601,729],{"class":537},[531,1603,1604],{"class":808}," 11",[531,1606,592],{"class":537},[531,1608,1609,1611,1613,1616,1618,1621,1623,1626,1628,1631],{"class":533,"line":694},[531,1610,1582],{"class":619},[531,1612,629],{"class":537},[531,1614,1615],{"class":606},"SetFillColor",[531,1617,649],{"class":537},[531,1619,1620],{"class":808},"26",[531,1622,729],{"class":537},[531,1624,1625],{"class":808}," 35",[531,1627,729],{"class":537},[531,1629,1630],{"class":808}," 126",[531,1632,592],{"class":537},[531,1634,1635,1637,1639,1642,1644,1647,1649,1652,1654,1656],{"class":533,"line":699},[531,1636,1582],{"class":619},[531,1638,629],{"class":537},[531,1640,1641],{"class":606},"SetTextColor",[531,1643,649],{"class":537},[531,1645,1646],{"class":808},"255",[531,1648,729],{"class":537},[531,1650,1651],{"class":808}," 255",[531,1653,729],{"class":537},[531,1655,1651],{"class":808},[531,1657,592],{"class":537},[531,1659,1660],{"class":533,"line":753},[531,1661,549],{"emptyLinePlaceholder":548},[531,1663,1664,1667,1669,1672,1676,1678,1680,1683,1685,1687,1689,1692,1694,1696,1698,1701,1703,1705,1707,1710,1712],{"class":533,"line":771},[531,1665,1666],{"class":619},"headers ",[531,1668,623],{"class":537},[531,1670,1671],{"class":537}," []",[531,1673,1675],{"class":1674},"spNyl","string",[531,1677,660],{"class":537},[531,1679,720],{"class":537},[531,1681,1682],{"class":723},"Concepto",[531,1684,720],{"class":537},[531,1686,729],{"class":537},[531,1688,732],{"class":537},[531,1690,1691],{"class":723},"Cant.",[531,1693,720],{"class":537},[531,1695,729],{"class":537},[531,1697,732],{"class":537},[531,1699,1700],{"class":723},"Unitario",[531,1702,720],{"class":537},[531,1704,729],{"class":537},[531,1706,732],{"class":537},[531,1708,1709],{"class":723},"Importe",[531,1711,720],{"class":537},[531,1713,999],{"class":537},[531,1715,1716,1719,1722,1724,1727,1729,1732,1735],{"class":533,"line":777},[531,1717,1718],{"class":555},"for",[531,1720,1721],{"class":619}," i",[531,1723,729],{"class":537},[531,1725,1726],{"class":619}," h ",[531,1728,623],{"class":537},[531,1730,1731],{"class":555}," range",[531,1733,1734],{"class":619}," headers ",[531,1736,1737],{"class":537},"{\n",[531,1739,1740,1743,1745,1747,1750,1753,1756,1759,1761,1764],{"class":533,"line":822},[531,1741,1742],{"class":619},"    x ",[531,1744,623],{"class":537},[531,1746,1546],{"class":619},[531,1748,1749],{"class":537},"+",[531,1751,1752],{"class":619}," colW",[531,1754,1755],{"class":537},"*",[531,1757,1758],{"class":1674},"float64",[531,1760,649],{"class":537},[531,1762,1763],{"class":619},"i",[531,1765,592],{"class":537},[531,1767,1768,1770,1772,1775,1777,1780,1782,1785,1787,1789,1791,1794,1796,1798,1801,1803],{"class":533,"line":837},[531,1769,641],{"class":619},[531,1771,629],{"class":537},[531,1773,1774],{"class":606},"RectFromUpperLeftWithStyle",[531,1776,649],{"class":537},[531,1778,1779],{"class":619},"x",[531,1781,729],{"class":537},[531,1783,1784],{"class":619}," rowY",[531,1786,729],{"class":537},[531,1788,1752],{"class":619},[531,1790,729],{"class":537},[531,1792,1793],{"class":619}," rowH",[531,1795,729],{"class":537},[531,1797,732],{"class":537},[531,1799,1800],{"class":723},"F",[531,1802,720],{"class":537},[531,1804,592],{"class":537},[531,1806,1807],{"class":533,"line":842},[531,1808,549],{"emptyLinePlaceholder":548},[531,1810,1811,1813,1815,1817,1819,1821,1823,1826,1828,1830,1832,1835],{"class":533,"line":847},[531,1812,641],{"class":619},[531,1814,629],{"class":537},[531,1816,33],{"class":606},[531,1818,649],{"class":537},[531,1820,1779],{"class":619},[531,1822,1749],{"class":537},[531,1824,1825],{"class":808},"6",[531,1827,729],{"class":537},[531,1829,1784],{"class":619},[531,1831,1749],{"class":537},[531,1833,1834],{"class":808},"7",[531,1836,592],{"class":537},[531,1838,1839,1841,1843,1845,1847,1849,1851,1853,1856,1858,1860,1862,1864],{"class":533,"line":864},[531,1840,702],{"class":555},[531,1842,705],{"class":619},[531,1844,623],{"class":537},[531,1846,710],{"class":619},[531,1848,629],{"class":537},[531,1850,37],{"class":606},[531,1852,896],{"class":537},[531,1854,1855],{"class":619}," h",[531,1857,740],{"class":537},[531,1859,705],{"class":619},[531,1861,745],{"class":537},[531,1863,748],{"class":537},[531,1865,613],{"class":537},[531,1867,1868,1870,1872,1874,1876,1878],{"class":533,"line":881},[531,1869,756],{"class":619},[531,1871,629],{"class":537},[531,1873,761],{"class":606},[531,1875,649],{"class":537},[531,1877,766],{"class":619},[531,1879,592],{"class":537},[531,1881,1882],{"class":533,"line":916},[531,1883,774],{"class":537},[531,1885,1886],{"class":533,"line":931},[531,1887,999],{"class":537},[531,1889,1890],{"class":533,"line":936},[531,1891,549],{"emptyLinePlaceholder":548},[531,1893,1894,1896,1898,1900,1902,1905,1907,1910,1912,1914],{"class":533,"line":941},[531,1895,1582],{"class":619},[531,1897,629],{"class":537},[531,1899,1641],{"class":606},[531,1901,649],{"class":537},[531,1903,1904],{"class":808},"0",[531,1906,729],{"class":537},[531,1908,1909],{"class":808}," 0",[531,1911,729],{"class":537},[531,1913,1909],{"class":808},[531,1915,592],{"class":537},[19,1917,1918,1919,1922,1923,1925],{},"Hay cuatro constantes. Hay una resta de anchos. Hay una división. Hay un bucle con ",[31,1920,1921],{},"colW*float64(i)"," — y ese cast a float estaba ahí solo porque el ",[31,1924,1755],{}," de Go no promueve int a float64. Ninguno de estos existe en la versión gpdf.",[19,1927,1928],{},[22,1929,1004],{},[522,1931,1933],{"className":524,"code":1932,"language":526,"meta":527,"style":527},"page.AutoRow(func(r *template.RowBuilder) {\n    headers := []string{\"Concepto\", \"Cant.\", \"Unitario\", \"Importe\"}\n    for _, h := range headers {\n        r.Col(3, func(c *template.ColBuilder) {\n            c.Box(\n                template.BgColor(pdf.RGBHex(0x1A237E)),\n                template.Padding(document.Mm(2), document.Mm(3)),\n            )\n            c.Text(h,\n                template.Bold(), template.FontSize(11),\n                template.TextColor(pdf.White),\n            )\n        })\n    }\n})\n",[31,1934,1935,1960,2005,2025,2056,2067,2094,2131,2136,2152,2176,2196,2200,2204,2208],{"__ignoreMap":527},[531,1936,1937,1940,1942,1944,1946,1948,1950,1952,1954,1956,1958],{"class":533,"line":534},[531,1938,1939],{"class":619},"page",[531,1941,629],{"class":537},[531,1943,1202],{"class":606},[531,1945,1205],{"class":537},[531,1947,1209],{"class":1208},[531,1949,669],{"class":537},[531,1951,1214],{"class":541},[531,1953,629],{"class":537},[531,1955,1219],{"class":541},[531,1957,1222],{"class":537},[531,1959,613],{"class":537},[531,1961,1962,1965,1967,1969,1971,1973,1975,1977,1979,1981,1983,1985,1987,1989,1991,1993,1995,1997,1999,2001,2003],{"class":533,"line":545},[531,1963,1964],{"class":619},"    headers ",[531,1966,623],{"class":537},[531,1968,1671],{"class":537},[531,1970,1675],{"class":1674},[531,1972,660],{"class":537},[531,1974,720],{"class":537},[531,1976,1682],{"class":723},[531,1978,720],{"class":537},[531,1980,729],{"class":537},[531,1982,732],{"class":537},[531,1984,1691],{"class":723},[531,1986,720],{"class":537},[531,1988,729],{"class":537},[531,1990,732],{"class":537},[531,1992,1700],{"class":723},[531,1994,720],{"class":537},[531,1996,729],{"class":537},[531,1998,732],{"class":537},[531,2000,1709],{"class":723},[531,2002,720],{"class":537},[531,2004,999],{"class":537},[531,2006,2007,2010,2013,2015,2017,2019,2021,2023],{"class":533,"line":552},[531,2008,2009],{"class":555},"    for",[531,2011,2012],{"class":619}," _",[531,2014,729],{"class":537},[531,2016,1726],{"class":619},[531,2018,623],{"class":537},[531,2020,1731],{"class":555},[531,2022,1734],{"class":619},[531,2024,1737],{"class":537},[531,2026,2027,2029,2031,2033,2035,2038,2040,2042,2044,2046,2048,2050,2052,2054],{"class":533,"line":562},[531,2028,1229],{"class":619},[531,2030,629],{"class":537},[531,2032,1234],{"class":606},[531,2034,649],{"class":537},[531,2036,2037],{"class":808},"3",[531,2039,729],{"class":537},[531,2041,1244],{"class":537},[531,2043,1247],{"class":1208},[531,2045,669],{"class":537},[531,2047,1214],{"class":541},[531,2049,629],{"class":537},[531,2051,1256],{"class":541},[531,2053,1222],{"class":537},[531,2055,613],{"class":537},[531,2057,2058,2060,2062,2065],{"class":533,"line":574},[531,2059,1265],{"class":619},[531,2061,629],{"class":537},[531,2063,2064],{"class":606},"Box",[531,2066,1109],{"class":537},[531,2068,2069,2072,2074,2077,2079,2081,2083,2086,2088,2091],{"class":533,"line":579},[531,2070,2071],{"class":619},"                template",[531,2073,629],{"class":537},[531,2075,2076],{"class":606},"BgColor",[531,2078,649],{"class":537},[531,2080,1582],{"class":619},[531,2082,629],{"class":537},[531,2084,2085],{"class":606},"RGBHex",[531,2087,649],{"class":537},[531,2089,2090],{"class":808},"0x1A237E",[531,2092,2093],{"class":537},")),\n",[531,2095,2096,2098,2100,2103,2105,2107,2109,2111,2113,2116,2118,2121,2123,2125,2127,2129],{"class":533,"line":589},[531,2097,2071],{"class":619},[531,2099,629],{"class":537},[531,2101,2102],{"class":606},"Padding",[531,2104,649],{"class":537},[531,2106,1124],{"class":619},[531,2108,629],{"class":537},[531,2110,1159],{"class":606},[531,2112,649],{"class":537},[531,2114,2115],{"class":808},"2",[531,2117,1296],{"class":537},[531,2119,2120],{"class":619}," document",[531,2122,629],{"class":537},[531,2124,1159],{"class":606},[531,2126,649],{"class":537},[531,2128,2037],{"class":808},[531,2130,2093],{"class":537},[531,2132,2133],{"class":533,"line":595},[531,2134,2135],{"class":537},"            )\n",[531,2137,2138,2140,2142,2144,2146,2149],{"class":533,"line":600},[531,2139,1265],{"class":619},[531,2141,629],{"class":537},[531,2143,1270],{"class":606},[531,2145,649],{"class":537},[531,2147,2148],{"class":619},"h",[531,2150,2151],{"class":537},",\n",[531,2153,2154,2156,2158,2160,2163,2165,2167,2169,2171,2174],{"class":533,"line":616},[531,2155,2071],{"class":619},[531,2157,629],{"class":537},[531,2159,1303],{"class":606},[531,2161,2162],{"class":537},"(),",[531,2164,1283],{"class":619},[531,2166,629],{"class":537},[531,2168,1288],{"class":606},[531,2170,649],{"class":537},[531,2172,2173],{"class":808},"11",[531,2175,1132],{"class":537},[531,2177,2178,2180,2182,2185,2187,2189,2191,2194],{"class":533,"line":638},[531,2179,2071],{"class":619},[531,2181,629],{"class":537},[531,2183,2184],{"class":606},"TextColor",[531,2186,649],{"class":537},[531,2188,1582],{"class":619},[531,2190,629],{"class":537},[531,2192,2193],{"class":619},"White",[531,2195,1132],{"class":537},[531,2197,2198],{"class":533,"line":682},[531,2199,2135],{"class":537},[531,2201,2202],{"class":533,"line":694},[531,2203,1311],{"class":537},[531,2205,2206],{"class":533,"line":699},[531,2207,774],{"class":537},[531,2209,2210],{"class":533,"line":753},[531,2211,679],{"class":537},[19,2213,2214,2216,2217,2220,2221,2224,2225,2228],{},[31,2215,124],{}," cuatro veces suma 12. La grilla maneja los anchos. Si cambias A4 por Letter, o reduces los márgenes, el encabezado sigue alineado correctamente porque nada en este código depende de ",[31,2218,2219],{},"pageWidth",". Si decides que la columna 1 debe ser el doble de ancha que las otras tres, cámbiala a ",[31,2222,2223],{},"r.Col(6, ...)"," y a una de las otras a ",[31,2226,2227],{},"r.Col(2, ...)",". Sin aritmética.",[14,2230,2232],{"id":2231},"before-after-3-una-tabla-de-factura-que-cruza-páginas","Before / After 3: una tabla de factura que cruza páginas",[19,2234,2235,2236,2238],{},"La grande. En gopdf, dibujar una tabla que fluye sobre múltiples páginas es mayormente contabilidad: rastreas la y actual, dibujas cada fila, verificas si la siguiente cabe, y si no, llamas ",[31,2237,57],{}," y reimprimes el encabezado. La máquina de estados está en tu código.",[19,2240,2241],{},[22,2242,520],{},[522,2244,2246],{"className":524,"code":2245,"language":526,"meta":527,"style":527},"func drawInvoiceTable(pdf *gopdf.GoPdf, items [][4]string) error {\n    const (\n        pageH       = 841.89 // alto A4\n        bottomLimit = pageH - 40\n        rowH        = 22.0\n        leftX       = 40.0\n    )\n    cols := []float64{260, 80, 80, 95}\n\n    drawHeader := func(y float64) float64 {\n        pdf.SetFont(\"helvetica-bold\", \"\", 11)\n        pdf.SetFillColor(26, 35, 126)\n        pdf.SetTextColor(255, 255, 255)\n        x := leftX\n        for i, h := range []string{\"Concepto\", \"Cant.\", \"Unitario\", \"Importe\"} {\n            pdf.RectFromUpperLeftWithStyle(x, y, cols[i], rowH, \"F\")\n            pdf.SetXY(x+6, y+7)\n            if err := pdf.Cell(nil, h); err != nil {\n                log.Println(err)\n            }\n            x += cols[i]\n        }\n        pdf.SetTextColor(0, 0, 0)\n        pdf.SetFont(\"helvetica\", \"\", 11)\n        return y + rowH\n    }\n\n    y := drawHeader(100)\n    for _, row := range items {\n        if y+rowH > bottomLimit {\n            pdf.AddPage()\n            y = drawHeader(60)\n        }\n\n        x := leftX\n        for i, cell := range row {\n            pdf.RectFromUpperLeftWithStyle(x, y, cols[i], rowH, \"D\")\n            pdf.SetXY(x+6, y+7)\n            if err := pdf.Cell(nil, cell); err != nil {\n                return err\n            }\n            x += cols[i]\n        }\n        y += rowH\n    }\n    return nil\n}\n",[31,2247,2248,2290,2297,2310,2325,2335,2344,2348,2380,2384,2405,2432,2454,2476,2486,2542,2585,2611,2640,2656,2661,2678,2683,2705,2731,2744,2748,2752,2769,2789,2809,2819,2835,2840,2845,2854,2874,2914,2941,2971,2980,2985,3000,3005,3015,3020,3029],{"__ignoreMap":527},[531,2249,2250,2252,2255,2257,2259,2261,2263,2265,2267,2269,2272,2275,2278,2281,2283,2285,2288],{"class":533,"line":534},[531,2251,603],{"class":537},[531,2253,2254],{"class":606}," drawInvoiceTable",[531,2256,649],{"class":537},[531,2258,1582],{"class":1208},[531,2260,669],{"class":537},[531,2262,652],{"class":541},[531,2264,629],{"class":537},[531,2266,632],{"class":541},[531,2268,729],{"class":537},[531,2270,2271],{"class":1208}," items",[531,2273,2274],{"class":537}," [][",[531,2276,2277],{"class":808},"4",[531,2279,2280],{"class":537},"]",[531,2282,1675],{"class":1674},[531,2284,1222],{"class":537},[531,2286,2287],{"class":1674}," error",[531,2289,613],{"class":537},[531,2291,2292,2295],{"class":533,"line":545},[531,2293,2294],{"class":537},"    const",[531,2296,559],{"class":537},[531,2298,2299,2302,2304,2307],{"class":533,"line":552},[531,2300,2301],{"class":619},"        pageH       ",[531,2303,1476],{"class":537},[531,2305,2306],{"class":808}," 841.89",[531,2308,2309],{"class":1482}," // alto A4\n",[531,2311,2312,2315,2317,2320,2322],{"class":533,"line":562},[531,2313,2314],{"class":619},"        bottomLimit ",[531,2316,1476],{"class":537},[531,2318,2319],{"class":619}," pageH ",[531,2321,1543],{"class":537},[531,2323,2324],{"class":808}," 40\n",[531,2326,2327,2330,2332],{"class":533,"line":574},[531,2328,2329],{"class":619},"        rowH        ",[531,2331,1476],{"class":537},[531,2333,2334],{"class":808}," 22.0\n",[531,2336,2337,2340,2342],{"class":533,"line":579},[531,2338,2339],{"class":619},"        leftX       ",[531,2341,1476],{"class":537},[531,2343,1493],{"class":808},[531,2345,2346],{"class":533,"line":589},[531,2347,1172],{"class":537},[531,2349,2350,2353,2355,2357,2359,2361,2364,2366,2369,2371,2373,2375,2378],{"class":533,"line":595},[531,2351,2352],{"class":619},"    cols ",[531,2354,623],{"class":537},[531,2356,1671],{"class":537},[531,2358,1758],{"class":1674},[531,2360,660],{"class":537},[531,2362,2363],{"class":808},"260",[531,2365,729],{"class":537},[531,2367,2368],{"class":808}," 80",[531,2370,729],{"class":537},[531,2372,2368],{"class":808},[531,2374,729],{"class":537},[531,2376,2377],{"class":808}," 95",[531,2379,999],{"class":537},[531,2381,2382],{"class":533,"line":600},[531,2383,549],{"emptyLinePlaceholder":548},[531,2385,2386,2389,2391,2393,2396,2399,2401,2403],{"class":533,"line":616},[531,2387,2388],{"class":619},"    drawHeader ",[531,2390,623],{"class":537},[531,2392,1244],{"class":537},[531,2394,2395],{"class":1208},"y",[531,2397,2398],{"class":1674}," float64",[531,2400,1222],{"class":537},[531,2402,2398],{"class":1674},[531,2404,613],{"class":537},[531,2406,2407,2410,2412,2414,2416,2418,2420,2422,2424,2426,2428,2430],{"class":533,"line":638},[531,2408,2409],{"class":619},"        pdf",[531,2411,629],{"class":537},[531,2413,790],{"class":606},[531,2415,649],{"class":537},[531,2417,720],{"class":537},[531,2419,1593],{"class":723},[531,2421,720],{"class":537},[531,2423,729],{"class":537},[531,2425,803],{"class":537},[531,2427,729],{"class":537},[531,2429,1604],{"class":808},[531,2431,592],{"class":537},[531,2433,2434,2436,2438,2440,2442,2444,2446,2448,2450,2452],{"class":533,"line":682},[531,2435,2409],{"class":619},[531,2437,629],{"class":537},[531,2439,1615],{"class":606},[531,2441,649],{"class":537},[531,2443,1620],{"class":808},[531,2445,729],{"class":537},[531,2447,1625],{"class":808},[531,2449,729],{"class":537},[531,2451,1630],{"class":808},[531,2453,592],{"class":537},[531,2455,2456,2458,2460,2462,2464,2466,2468,2470,2472,2474],{"class":533,"line":694},[531,2457,2409],{"class":619},[531,2459,629],{"class":537},[531,2461,1641],{"class":606},[531,2463,649],{"class":537},[531,2465,1646],{"class":808},[531,2467,729],{"class":537},[531,2469,1651],{"class":808},[531,2471,729],{"class":537},[531,2473,1651],{"class":808},[531,2475,592],{"class":537},[531,2477,2478,2481,2483],{"class":533,"line":699},[531,2479,2480],{"class":619},"        x ",[531,2482,623],{"class":537},[531,2484,2485],{"class":619}," leftX\n",[531,2487,2488,2491,2493,2495,2497,2499,2501,2503,2505,2507,2509,2511,2513,2515,2517,2519,2521,2523,2525,2527,2529,2531,2533,2535,2537,2540],{"class":533,"line":753},[531,2489,2490],{"class":555},"        for",[531,2492,1721],{"class":619},[531,2494,729],{"class":537},[531,2496,1726],{"class":619},[531,2498,623],{"class":537},[531,2500,1731],{"class":555},[531,2502,1671],{"class":537},[531,2504,1675],{"class":1674},[531,2506,660],{"class":537},[531,2508,720],{"class":537},[531,2510,1682],{"class":723},[531,2512,720],{"class":537},[531,2514,729],{"class":537},[531,2516,732],{"class":537},[531,2518,1691],{"class":723},[531,2520,720],{"class":537},[531,2522,729],{"class":537},[531,2524,732],{"class":537},[531,2526,1700],{"class":723},[531,2528,720],{"class":537},[531,2530,729],{"class":537},[531,2532,732],{"class":537},[531,2534,1709],{"class":723},[531,2536,720],{"class":537},[531,2538,2539],{"class":537},"}",[531,2541,613],{"class":537},[531,2543,2544,2547,2549,2551,2553,2555,2557,2560,2562,2565,2568,2570,2573,2575,2577,2579,2581,2583],{"class":533,"line":771},[531,2545,2546],{"class":619},"            pdf",[531,2548,629],{"class":537},[531,2550,1774],{"class":606},[531,2552,649],{"class":537},[531,2554,1779],{"class":619},[531,2556,729],{"class":537},[531,2558,2559],{"class":619}," y",[531,2561,729],{"class":537},[531,2563,2564],{"class":619}," cols",[531,2566,2567],{"class":537},"[",[531,2569,1763],{"class":619},[531,2571,2572],{"class":537},"],",[531,2574,1793],{"class":619},[531,2576,729],{"class":537},[531,2578,732],{"class":537},[531,2580,1800],{"class":723},[531,2582,720],{"class":537},[531,2584,592],{"class":537},[531,2586,2587,2589,2591,2593,2595,2597,2599,2601,2603,2605,2607,2609],{"class":533,"line":777},[531,2588,2546],{"class":619},[531,2590,629],{"class":537},[531,2592,33],{"class":606},[531,2594,649],{"class":537},[531,2596,1779],{"class":619},[531,2598,1749],{"class":537},[531,2600,1825],{"class":808},[531,2602,729],{"class":537},[531,2604,2559],{"class":619},[531,2606,1749],{"class":537},[531,2608,1834],{"class":808},[531,2610,592],{"class":537},[531,2612,2613,2616,2618,2620,2622,2624,2626,2628,2630,2632,2634,2636,2638],{"class":533,"line":822},[531,2614,2615],{"class":555},"            if",[531,2617,705],{"class":619},[531,2619,623],{"class":537},[531,2621,710],{"class":619},[531,2623,629],{"class":537},[531,2625,37],{"class":606},[531,2627,896],{"class":537},[531,2629,1855],{"class":619},[531,2631,740],{"class":537},[531,2633,705],{"class":619},[531,2635,745],{"class":537},[531,2637,748],{"class":537},[531,2639,613],{"class":537},[531,2641,2642,2645,2647,2650,2652,2654],{"class":533,"line":837},[531,2643,2644],{"class":619},"                log",[531,2646,629],{"class":537},[531,2648,2649],{"class":606},"Println",[531,2651,649],{"class":537},[531,2653,766],{"class":619},[531,2655,592],{"class":537},[531,2657,2658],{"class":533,"line":842},[531,2659,2660],{"class":537},"            }\n",[531,2662,2663,2666,2669,2671,2673,2675],{"class":533,"line":847},[531,2664,2665],{"class":619},"            x ",[531,2667,2668],{"class":537},"+=",[531,2670,2564],{"class":619},[531,2672,2567],{"class":537},[531,2674,1763],{"class":619},[531,2676,2677],{"class":537},"]\n",[531,2679,2680],{"class":533,"line":864},[531,2681,2682],{"class":537},"        }\n",[531,2684,2685,2687,2689,2691,2693,2695,2697,2699,2701,2703],{"class":533,"line":881},[531,2686,2409],{"class":619},[531,2688,629],{"class":537},[531,2690,1641],{"class":606},[531,2692,649],{"class":537},[531,2694,1904],{"class":808},[531,2696,729],{"class":537},[531,2698,1909],{"class":808},[531,2700,729],{"class":537},[531,2702,1909],{"class":808},[531,2704,592],{"class":537},[531,2706,2707,2709,2711,2713,2715,2717,2719,2721,2723,2725,2727,2729],{"class":533,"line":916},[531,2708,2409],{"class":619},[531,2710,629],{"class":537},[531,2712,790],{"class":606},[531,2714,649],{"class":537},[531,2716,720],{"class":537},[531,2718,724],{"class":723},[531,2720,720],{"class":537},[531,2722,729],{"class":537},[531,2724,803],{"class":537},[531,2726,729],{"class":537},[531,2728,1604],{"class":808},[531,2730,592],{"class":537},[531,2732,2733,2736,2739,2741],{"class":533,"line":931},[531,2734,2735],{"class":555},"        return",[531,2737,2738],{"class":619}," y ",[531,2740,1749],{"class":537},[531,2742,2743],{"class":619}," rowH\n",[531,2745,2746],{"class":533,"line":936},[531,2747,774],{"class":537},[531,2749,2750],{"class":533,"line":941},[531,2751,549],{"emptyLinePlaceholder":548},[531,2753,2754,2757,2759,2762,2764,2767],{"class":533,"line":976},[531,2755,2756],{"class":619},"    y ",[531,2758,623],{"class":537},[531,2760,2761],{"class":606}," drawHeader",[531,2763,649],{"class":537},[531,2765,2766],{"class":808},"100",[531,2768,592],{"class":537},[531,2770,2771,2773,2775,2777,2780,2782,2784,2787],{"class":533,"line":991},[531,2772,2009],{"class":555},[531,2774,2012],{"class":619},[531,2776,729],{"class":537},[531,2778,2779],{"class":619}," row ",[531,2781,623],{"class":537},[531,2783,1731],{"class":555},[531,2785,2786],{"class":619}," items ",[531,2788,1737],{"class":537},[531,2790,2791,2794,2796,2798,2801,2804,2807],{"class":533,"line":996},[531,2792,2793],{"class":555},"        if",[531,2795,2559],{"class":619},[531,2797,1749],{"class":537},[531,2799,2800],{"class":619},"rowH ",[531,2802,2803],{"class":537},">",[531,2805,2806],{"class":619}," bottomLimit ",[531,2808,1737],{"class":537},[531,2810,2811,2813,2815,2817],{"class":533,"line":1431},[531,2812,2546],{"class":619},[531,2814,629],{"class":537},[531,2816,57],{"class":606},[531,2818,691],{"class":537},[531,2820,2821,2824,2826,2828,2830,2833],{"class":533,"line":1436},[531,2822,2823],{"class":619},"            y ",[531,2825,1476],{"class":537},[531,2827,2761],{"class":606},[531,2829,649],{"class":537},[531,2831,2832],{"class":808},"60",[531,2834,592],{"class":537},[531,2836,2838],{"class":533,"line":2837},33,[531,2839,2682],{"class":537},[531,2841,2843],{"class":533,"line":2842},34,[531,2844,549],{"emptyLinePlaceholder":548},[531,2846,2848,2850,2852],{"class":533,"line":2847},35,[531,2849,2480],{"class":619},[531,2851,623],{"class":537},[531,2853,2485],{"class":619},[531,2855,2857,2859,2861,2863,2866,2868,2870,2872],{"class":533,"line":2856},36,[531,2858,2490],{"class":555},[531,2860,1721],{"class":619},[531,2862,729],{"class":537},[531,2864,2865],{"class":619}," cell ",[531,2867,623],{"class":537},[531,2869,1731],{"class":555},[531,2871,2779],{"class":619},[531,2873,1737],{"class":537},[531,2875,2877,2879,2881,2883,2885,2887,2889,2891,2893,2895,2897,2899,2901,2903,2905,2907,2910,2912],{"class":533,"line":2876},37,[531,2878,2546],{"class":619},[531,2880,629],{"class":537},[531,2882,1774],{"class":606},[531,2884,649],{"class":537},[531,2886,1779],{"class":619},[531,2888,729],{"class":537},[531,2890,2559],{"class":619},[531,2892,729],{"class":537},[531,2894,2564],{"class":619},[531,2896,2567],{"class":537},[531,2898,1763],{"class":619},[531,2900,2572],{"class":537},[531,2902,1793],{"class":619},[531,2904,729],{"class":537},[531,2906,732],{"class":537},[531,2908,2909],{"class":723},"D",[531,2911,720],{"class":537},[531,2913,592],{"class":537},[531,2915,2917,2919,2921,2923,2925,2927,2929,2931,2933,2935,2937,2939],{"class":533,"line":2916},38,[531,2918,2546],{"class":619},[531,2920,629],{"class":537},[531,2922,33],{"class":606},[531,2924,649],{"class":537},[531,2926,1779],{"class":619},[531,2928,1749],{"class":537},[531,2930,1825],{"class":808},[531,2932,729],{"class":537},[531,2934,2559],{"class":619},[531,2936,1749],{"class":537},[531,2938,1834],{"class":808},[531,2940,592],{"class":537},[531,2942,2944,2946,2948,2950,2952,2954,2956,2958,2961,2963,2965,2967,2969],{"class":533,"line":2943},39,[531,2945,2615],{"class":555},[531,2947,705],{"class":619},[531,2949,623],{"class":537},[531,2951,710],{"class":619},[531,2953,629],{"class":537},[531,2955,37],{"class":606},[531,2957,896],{"class":537},[531,2959,2960],{"class":619}," cell",[531,2962,740],{"class":537},[531,2964,705],{"class":619},[531,2966,745],{"class":537},[531,2968,748],{"class":537},[531,2970,613],{"class":537},[531,2972,2974,2977],{"class":533,"line":2973},40,[531,2975,2976],{"class":555},"                return",[531,2978,2979],{"class":619}," err\n",[531,2981,2983],{"class":533,"line":2982},41,[531,2984,2660],{"class":537},[531,2986,2988,2990,2992,2994,2996,2998],{"class":533,"line":2987},42,[531,2989,2665],{"class":619},[531,2991,2668],{"class":537},[531,2993,2564],{"class":619},[531,2995,2567],{"class":537},[531,2997,1763],{"class":619},[531,2999,2677],{"class":537},[531,3001,3003],{"class":533,"line":3002},43,[531,3004,2682],{"class":537},[531,3006,3008,3011,3013],{"class":533,"line":3007},44,[531,3009,3010],{"class":619},"        y ",[531,3012,2668],{"class":537},[531,3014,2743],{"class":619},[531,3016,3018],{"class":533,"line":3017},45,[531,3019,774],{"class":537},[531,3021,3023,3026],{"class":533,"line":3022},46,[531,3024,3025],{"class":555},"    return",[531,3027,3028],{"class":537}," nil\n",[531,3030,3032],{"class":533,"line":3031},47,[531,3033,999],{"class":537},[19,3035,3036,3037,3039],{},"La función de tabla tiene 30 líneas y solo 5 son sobre los datos. El resto es layout: alturas hardcodeadas, límite inferior hardcodeado, una closure para redibujar el encabezado tras saltos, dos ",[31,3038,1718],{},", dos avances de cursor por celda. Esta es la mediana de las tablas gopdf.",[19,3041,3042],{},[22,3043,1004],{},[522,3045,3047],{"className":524,"code":3046,"language":526,"meta":527,"style":527},"page.AutoRow(func(r *template.RowBuilder) {\n    r.Col(12, func(c *template.ColBuilder) {\n        c.Table(\n            []string{\"Concepto\", \"Cant.\", \"Unitario\", \"Importe\"},\n            items, // [][]string\n            template.ColumnWidths(55, 15, 15, 15),\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",[31,3048,3049,3073,3104,3116,3158,3168,3198,3209,3220,3238,3260,3265,3289,3294,3298],{"__ignoreMap":527},[531,3050,3051,3053,3055,3057,3059,3061,3063,3065,3067,3069,3071],{"class":533,"line":534},[531,3052,1939],{"class":619},[531,3054,629],{"class":537},[531,3056,1202],{"class":606},[531,3058,1205],{"class":537},[531,3060,1209],{"class":1208},[531,3062,669],{"class":537},[531,3064,1214],{"class":541},[531,3066,629],{"class":537},[531,3068,1219],{"class":541},[531,3070,1222],{"class":537},[531,3072,613],{"class":537},[531,3074,3075,3078,3080,3082,3084,3086,3088,3090,3092,3094,3096,3098,3100,3102],{"class":533,"line":545},[531,3076,3077],{"class":619},"    r",[531,3079,629],{"class":537},[531,3081,1234],{"class":606},[531,3083,649],{"class":537},[531,3085,1239],{"class":808},[531,3087,729],{"class":537},[531,3089,1244],{"class":537},[531,3091,1247],{"class":1208},[531,3093,669],{"class":537},[531,3095,1214],{"class":541},[531,3097,629],{"class":537},[531,3099,1256],{"class":541},[531,3101,1222],{"class":537},[531,3103,613],{"class":537},[531,3105,3106,3109,3111,3114],{"class":533,"line":552},[531,3107,3108],{"class":619},"        c",[531,3110,629],{"class":537},[531,3112,3113],{"class":606},"Table",[531,3115,1109],{"class":537},[531,3117,3118,3121,3123,3125,3127,3129,3131,3133,3135,3137,3139,3141,3143,3145,3147,3149,3151,3153,3155],{"class":533,"line":562},[531,3119,3120],{"class":537},"            []",[531,3122,1675],{"class":1674},[531,3124,660],{"class":537},[531,3126,720],{"class":537},[531,3128,1682],{"class":723},[531,3130,720],{"class":537},[531,3132,729],{"class":537},[531,3134,732],{"class":537},[531,3136,1691],{"class":723},[531,3138,720],{"class":537},[531,3140,729],{"class":537},[531,3142,732],{"class":537},[531,3144,1700],{"class":723},[531,3146,720],{"class":537},[531,3148,729],{"class":537},[531,3150,732],{"class":537},[531,3152,1709],{"class":723},[531,3154,720],{"class":537},[531,3156,3157],{"class":537},"},\n",[531,3159,3160,3163,3165],{"class":533,"line":574},[531,3161,3162],{"class":619},"            items",[531,3164,729],{"class":537},[531,3166,3167],{"class":1482}," // [][]string\n",[531,3169,3170,3173,3175,3178,3180,3183,3185,3188,3190,3192,3194,3196],{"class":533,"line":579},[531,3171,3172],{"class":619},"            template",[531,3174,629],{"class":537},[531,3176,3177],{"class":606},"ColumnWidths",[531,3179,649],{"class":537},[531,3181,3182],{"class":808},"55",[531,3184,729],{"class":537},[531,3186,3187],{"class":808}," 15",[531,3189,729],{"class":537},[531,3191,3187],{"class":808},[531,3193,729],{"class":537},[531,3195,3187],{"class":808},[531,3197,1132],{"class":537},[531,3199,3200,3202,3204,3207],{"class":533,"line":589},[531,3201,3172],{"class":619},[531,3203,629],{"class":537},[531,3205,3206],{"class":606},"TableHeaderStyle",[531,3208,1109],{"class":537},[531,3210,3211,3213,3215,3217],{"class":533,"line":595},[531,3212,2071],{"class":619},[531,3214,629],{"class":537},[531,3216,1303],{"class":606},[531,3218,3219],{"class":537},"(),\n",[531,3221,3222,3224,3226,3228,3230,3232,3234,3236],{"class":533,"line":600},[531,3223,2071],{"class":619},[531,3225,629],{"class":537},[531,3227,2184],{"class":606},[531,3229,649],{"class":537},[531,3231,1582],{"class":619},[531,3233,629],{"class":537},[531,3235,2193],{"class":619},[531,3237,1132],{"class":537},[531,3239,3240,3242,3244,3246,3248,3250,3252,3254,3256,3258],{"class":533,"line":616},[531,3241,2071],{"class":619},[531,3243,629],{"class":537},[531,3245,2076],{"class":606},[531,3247,649],{"class":537},[531,3249,1582],{"class":619},[531,3251,629],{"class":537},[531,3253,2085],{"class":606},[531,3255,649],{"class":537},[531,3257,2090],{"class":808},[531,3259,2093],{"class":537},[531,3261,3262],{"class":533,"line":638},[531,3263,3264],{"class":537},"            ),\n",[531,3266,3267,3269,3271,3274,3276,3278,3280,3282,3284,3287],{"class":533,"line":682},[531,3268,3172],{"class":619},[531,3270,629],{"class":537},[531,3272,3273],{"class":606},"TableStripe",[531,3275,649],{"class":537},[531,3277,1582],{"class":619},[531,3279,629],{"class":537},[531,3281,2085],{"class":606},[531,3283,649],{"class":537},[531,3285,3286],{"class":808},"0xF5F5F5",[531,3288,2093],{"class":537},[531,3290,3291],{"class":533,"line":694},[531,3292,3293],{"class":537},"        )\n",[531,3295,3296],{"class":533,"line":699},[531,3297,1316],{"class":537},[531,3299,3300],{"class":533,"line":753},[531,3301,679],{"class":537},[19,3303,3304,3305,3307],{},"Eso es todo. Saltos de página automáticos. El encabezado se repite en cada página donde el cuerpo continúa. Filas en zebra con una sola opción. Anchos de columna en porcentajes del contenedor, así que esta misma tabla dentro de ",[31,3306,2223],{}," se renderiza a media anchura con las mismas proporciones, sin reescritura. La función gopdf de 25 líneas desaparece.",[19,3309,3310,3311,3314,3315,3318],{},"Un número concreto. La factura de 100 filas mide en gpdf alrededor de ",[22,3312,3313],{},"108 µs"," y en signintech/gopdf alrededor de ",[22,3316,3317],{},"2.4 ms"," — y el número de gopdf depende del patrón celda a celda que escribiste. El factor no es el titular; la desaparición de la función sí.",[14,3320,3322],{"id":3321},"before-after-4-una-imagen-junto-a-un-párrafo","Before / After 4: una imagen junto a un párrafo",[19,3324,3325],{},"Patrón común: logo a la izquierda, bloque de dirección a la derecha.",[19,3327,3328],{},[22,3329,520],{},[522,3331,3333],{"className":524,"code":3332,"language":526,"meta":527,"style":527},"const (\n    leftX  = 40.0\n    rightX = 380.0\n    blockY = 50.0\n)\n\nif err := pdf.Image(\"logo.png\", leftX, blockY, &gopdf.Rect{W: 100, H: 60}); err != nil {\n    log.Fatal(err)\n}\n\npdf.SetFont(\"helvetica-bold\", \"\", 14)\npdf.SetXY(rightX, blockY)\nif err := pdf.Cell(nil, \"ACME S.A.\"); err != nil {\n    log.Fatal(err)\n}\n\npdf.SetFont(\"helvetica\", \"\", 10)\npdf.SetXY(rightX, blockY+20)\npdf.Cell(nil, \"Calle Gran Vía 28\")\npdf.SetXY(rightX, blockY+34)\npdf.Cell(nil, \"28013 Madrid\")\npdf.SetXY(rightX, blockY+48)\npdf.Cell(nil, \"billing@acme.example\")\n",[31,3334,3335,3341,3350,3360,3370,3374,3378,3456,3471,3475,3479,3506,3525,3558,3572,3576,3580,3607,3629,3648,3671,3690,3713],{"__ignoreMap":527},[531,3336,3337,3339],{"class":533,"line":534},[531,3338,1466],{"class":537},[531,3340,559],{"class":537},[531,3342,3343,3346,3348],{"class":533,"line":545},[531,3344,3345],{"class":619},"    leftX  ",[531,3347,1476],{"class":537},[531,3349,1493],{"class":808},[531,3351,3352,3355,3357],{"class":533,"line":552},[531,3353,3354],{"class":619},"    rightX ",[531,3356,1476],{"class":537},[531,3358,3359],{"class":808}," 380.0\n",[531,3361,3362,3365,3367],{"class":533,"line":562},[531,3363,3364],{"class":619},"    blockY ",[531,3366,1476],{"class":537},[531,3368,3369],{"class":808}," 50.0\n",[531,3371,3372],{"class":533,"line":574},[531,3373,592],{"class":537},[531,3375,3376],{"class":533,"line":579},[531,3377,549],{"emptyLinePlaceholder":548},[531,3379,3380,3383,3385,3387,3389,3391,3394,3396,3398,3401,3403,3405,3408,3410,3413,3415,3418,3420,3422,3425,3427,3430,3432,3435,3437,3440,3442,3445,3448,3450,3452,3454],{"class":533,"line":589},[531,3381,3382],{"class":555},"if",[531,3384,705],{"class":619},[531,3386,623],{"class":537},[531,3388,710],{"class":619},[531,3390,629],{"class":537},[531,3392,3393],{"class":606},"Image",[531,3395,649],{"class":537},[531,3397,720],{"class":537},[531,3399,3400],{"class":723},"logo.png",[531,3402,720],{"class":537},[531,3404,729],{"class":537},[531,3406,3407],{"class":619}," leftX",[531,3409,729],{"class":537},[531,3411,3412],{"class":619}," blockY",[531,3414,729],{"class":537},[531,3416,3417],{"class":537}," &",[531,3419,652],{"class":541},[531,3421,629],{"class":537},[531,3423,3424],{"class":541},"Rect",[531,3426,660],{"class":537},[531,3428,3429],{"class":619},"W",[531,3431,666],{"class":537},[531,3433,3434],{"class":808}," 100",[531,3436,729],{"class":537},[531,3438,3439],{"class":619}," H",[531,3441,666],{"class":537},[531,3443,3444],{"class":808}," 60",[531,3446,3447],{"class":537},"});",[531,3449,705],{"class":619},[531,3451,745],{"class":537},[531,3453,748],{"class":537},[531,3455,613],{"class":537},[531,3457,3458,3461,3463,3465,3467,3469],{"class":533,"line":595},[531,3459,3460],{"class":619},"    log",[531,3462,629],{"class":537},[531,3464,761],{"class":606},[531,3466,649],{"class":537},[531,3468,766],{"class":619},[531,3470,592],{"class":537},[531,3472,3473],{"class":533,"line":600},[531,3474,999],{"class":537},[531,3476,3477],{"class":533,"line":616},[531,3478,549],{"emptyLinePlaceholder":548},[531,3480,3481,3483,3485,3487,3489,3491,3493,3495,3497,3499,3501,3504],{"class":533,"line":638},[531,3482,1582],{"class":619},[531,3484,629],{"class":537},[531,3486,790],{"class":606},[531,3488,649],{"class":537},[531,3490,720],{"class":537},[531,3492,1593],{"class":723},[531,3494,720],{"class":537},[531,3496,729],{"class":537},[531,3498,803],{"class":537},[531,3500,729],{"class":537},[531,3502,3503],{"class":808}," 14",[531,3505,592],{"class":537},[531,3507,3508,3510,3512,3514,3516,3519,3521,3523],{"class":533,"line":682},[531,3509,1582],{"class":619},[531,3511,629],{"class":537},[531,3513,33],{"class":606},[531,3515,649],{"class":537},[531,3517,3518],{"class":619},"rightX",[531,3520,729],{"class":537},[531,3522,3412],{"class":619},[531,3524,592],{"class":537},[531,3526,3527,3529,3531,3533,3535,3537,3539,3541,3543,3546,3548,3550,3552,3554,3556],{"class":533,"line":694},[531,3528,3382],{"class":555},[531,3530,705],{"class":619},[531,3532,623],{"class":537},[531,3534,710],{"class":619},[531,3536,629],{"class":537},[531,3538,37],{"class":606},[531,3540,896],{"class":537},[531,3542,732],{"class":537},[531,3544,3545],{"class":723},"ACME S.A.",[531,3547,720],{"class":537},[531,3549,740],{"class":537},[531,3551,705],{"class":619},[531,3553,745],{"class":537},[531,3555,748],{"class":537},[531,3557,613],{"class":537},[531,3559,3560,3562,3564,3566,3568,3570],{"class":533,"line":699},[531,3561,3460],{"class":619},[531,3563,629],{"class":537},[531,3565,761],{"class":606},[531,3567,649],{"class":537},[531,3569,766],{"class":619},[531,3571,592],{"class":537},[531,3573,3574],{"class":533,"line":753},[531,3575,999],{"class":537},[531,3577,3578],{"class":533,"line":771},[531,3579,549],{"emptyLinePlaceholder":548},[531,3581,3582,3584,3586,3588,3590,3592,3594,3596,3598,3600,3602,3605],{"class":533,"line":777},[531,3583,1582],{"class":619},[531,3585,629],{"class":537},[531,3587,790],{"class":606},[531,3589,649],{"class":537},[531,3591,720],{"class":537},[531,3593,724],{"class":723},[531,3595,720],{"class":537},[531,3597,729],{"class":537},[531,3599,803],{"class":537},[531,3601,729],{"class":537},[531,3603,3604],{"class":808}," 10",[531,3606,592],{"class":537},[531,3608,3609,3611,3613,3615,3617,3619,3621,3623,3625,3627],{"class":533,"line":822},[531,3610,1582],{"class":619},[531,3612,629],{"class":537},[531,3614,33],{"class":606},[531,3616,649],{"class":537},[531,3618,3518],{"class":619},[531,3620,729],{"class":537},[531,3622,3412],{"class":619},[531,3624,1749],{"class":537},[531,3626,1164],{"class":808},[531,3628,592],{"class":537},[531,3630,3631,3633,3635,3637,3639,3641,3644,3646],{"class":533,"line":837},[531,3632,1582],{"class":619},[531,3634,629],{"class":537},[531,3636,37],{"class":606},[531,3638,896],{"class":537},[531,3640,732],{"class":537},[531,3642,3643],{"class":723},"Calle Gran Vía 28",[531,3645,720],{"class":537},[531,3647,592],{"class":537},[531,3649,3650,3652,3654,3656,3658,3660,3662,3664,3666,3669],{"class":533,"line":842},[531,3651,1582],{"class":619},[531,3653,629],{"class":537},[531,3655,33],{"class":606},[531,3657,649],{"class":537},[531,3659,3518],{"class":619},[531,3661,729],{"class":537},[531,3663,3412],{"class":619},[531,3665,1749],{"class":537},[531,3667,3668],{"class":808},"34",[531,3670,592],{"class":537},[531,3672,3673,3675,3677,3679,3681,3683,3686,3688],{"class":533,"line":847},[531,3674,1582],{"class":619},[531,3676,629],{"class":537},[531,3678,37],{"class":606},[531,3680,896],{"class":537},[531,3682,732],{"class":537},[531,3684,3685],{"class":723},"28013 Madrid",[531,3687,720],{"class":537},[531,3689,592],{"class":537},[531,3691,3692,3694,3696,3698,3700,3702,3704,3706,3708,3711],{"class":533,"line":864},[531,3693,1582],{"class":619},[531,3695,629],{"class":537},[531,3697,33],{"class":606},[531,3699,649],{"class":537},[531,3701,3518],{"class":619},[531,3703,729],{"class":537},[531,3705,3412],{"class":619},[531,3707,1749],{"class":537},[531,3709,3710],{"class":808},"48",[531,3712,592],{"class":537},[531,3714,3715,3717,3719,3721,3723,3725,3728,3730],{"class":533,"line":881},[531,3716,1582],{"class":619},[531,3718,629],{"class":537},[531,3720,37],{"class":606},[531,3722,896],{"class":537},[531,3724,732],{"class":537},[531,3726,3727],{"class":723},"billing@acme.example",[531,3729,720],{"class":537},[531,3731,592],{"class":537},[19,3733,3734,3735,3738],{},"Hay seis coordenadas y explícitas, y la columna derecha empieza en ",[31,3736,3737],{},"rightX = 380"," porque alguien decidió que el logo medía 100 y el bloque derecho necesitaba un hueco de 240. Mueve el logo a la derecha y todos los números cambian.",[19,3740,3741],{},[22,3742,1004],{},[522,3744,3746],{"className":524,"code":3745,"language":526,"meta":527,"style":527},"//go:embed logo.png\nvar logoData []byte\n\npage.AutoRow(func(r *template.RowBuilder) {\n    r.Col(4, func(c *template.ColBuilder) {\n        c.Image(logoData, template.FitWidth(document.Mm(35)))\n    })\n    r.Col(8, func(c *template.ColBuilder) {\n        c.Text(\"ACME S.A.\", template.Bold(), template.FontSize(14))\n        c.Text(\"Calle Gran Vía 28\")\n        c.Text(\"28013 Madrid\")\n        c.Text(\"billing@acme.example\")\n    })\n})\n",[31,3747,3748,3753,3767,3771,3795,3825,3863,3867,3898,3938,3956,3974,3992,3996],{"__ignoreMap":527},[531,3749,3750],{"class":533,"line":534},[531,3751,3752],{"class":1482},"//go:embed logo.png\n",[531,3754,3755,3758,3761,3764],{"class":533,"line":545},[531,3756,3757],{"class":537},"var",[531,3759,3760],{"class":619}," logoData ",[531,3762,3763],{"class":537},"[]",[531,3765,3766],{"class":1674},"byte\n",[531,3768,3769],{"class":533,"line":552},[531,3770,549],{"emptyLinePlaceholder":548},[531,3772,3773,3775,3777,3779,3781,3783,3785,3787,3789,3791,3793],{"class":533,"line":562},[531,3774,1939],{"class":619},[531,3776,629],{"class":537},[531,3778,1202],{"class":606},[531,3780,1205],{"class":537},[531,3782,1209],{"class":1208},[531,3784,669],{"class":537},[531,3786,1214],{"class":541},[531,3788,629],{"class":537},[531,3790,1219],{"class":541},[531,3792,1222],{"class":537},[531,3794,613],{"class":537},[531,3796,3797,3799,3801,3803,3805,3807,3809,3811,3813,3815,3817,3819,3821,3823],{"class":533,"line":574},[531,3798,3077],{"class":619},[531,3800,629],{"class":537},[531,3802,1234],{"class":606},[531,3804,649],{"class":537},[531,3806,2277],{"class":808},[531,3808,729],{"class":537},[531,3810,1244],{"class":537},[531,3812,1247],{"class":1208},[531,3814,669],{"class":537},[531,3816,1214],{"class":541},[531,3818,629],{"class":537},[531,3820,1256],{"class":541},[531,3822,1222],{"class":537},[531,3824,613],{"class":537},[531,3826,3827,3829,3831,3833,3835,3838,3840,3842,3844,3847,3849,3851,3853,3855,3857,3860],{"class":533,"line":579},[531,3828,3108],{"class":619},[531,3830,629],{"class":537},[531,3832,3393],{"class":606},[531,3834,649],{"class":537},[531,3836,3837],{"class":619},"logoData",[531,3839,729],{"class":537},[531,3841,1283],{"class":619},[531,3843,629],{"class":537},[531,3845,3846],{"class":606},"FitWidth",[531,3848,649],{"class":537},[531,3850,1124],{"class":619},[531,3852,629],{"class":537},[531,3854,1159],{"class":606},[531,3856,649],{"class":537},[531,3858,3859],{"class":808},"35",[531,3861,3862],{"class":537},")))\n",[531,3864,3865],{"class":533,"line":589},[531,3866,1316],{"class":537},[531,3868,3869,3871,3873,3875,3877,3880,3882,3884,3886,3888,3890,3892,3894,3896],{"class":533,"line":595},[531,3870,3077],{"class":619},[531,3872,629],{"class":537},[531,3874,1234],{"class":606},[531,3876,649],{"class":537},[531,3878,3879],{"class":808},"8",[531,3881,729],{"class":537},[531,3883,1244],{"class":537},[531,3885,1247],{"class":1208},[531,3887,669],{"class":537},[531,3889,1214],{"class":541},[531,3891,629],{"class":537},[531,3893,1256],{"class":541},[531,3895,1222],{"class":537},[531,3897,613],{"class":537},[531,3899,3900,3902,3904,3906,3908,3910,3912,3914,3916,3918,3920,3922,3924,3926,3928,3930,3932,3935],{"class":533,"line":600},[531,3901,3108],{"class":619},[531,3903,629],{"class":537},[531,3905,1270],{"class":606},[531,3907,649],{"class":537},[531,3909,720],{"class":537},[531,3911,3545],{"class":723},[531,3913,720],{"class":537},[531,3915,729],{"class":537},[531,3917,1283],{"class":619},[531,3919,629],{"class":537},[531,3921,1303],{"class":606},[531,3923,2162],{"class":537},[531,3925,1283],{"class":619},[531,3927,629],{"class":537},[531,3929,1288],{"class":606},[531,3931,649],{"class":537},[531,3933,3934],{"class":808},"14",[531,3936,3937],{"class":537},"))\n",[531,3939,3940,3942,3944,3946,3948,3950,3952,3954],{"class":533,"line":616},[531,3941,3108],{"class":619},[531,3943,629],{"class":537},[531,3945,1270],{"class":606},[531,3947,649],{"class":537},[531,3949,720],{"class":537},[531,3951,3643],{"class":723},[531,3953,720],{"class":537},[531,3955,592],{"class":537},[531,3957,3958,3960,3962,3964,3966,3968,3970,3972],{"class":533,"line":638},[531,3959,3108],{"class":619},[531,3961,629],{"class":537},[531,3963,1270],{"class":606},[531,3965,649],{"class":537},[531,3967,720],{"class":537},[531,3969,3685],{"class":723},[531,3971,720],{"class":537},[531,3973,592],{"class":537},[531,3975,3976,3978,3980,3982,3984,3986,3988,3990],{"class":533,"line":682},[531,3977,3108],{"class":619},[531,3979,629],{"class":537},[531,3981,1270],{"class":606},[531,3983,649],{"class":537},[531,3985,720],{"class":537},[531,3987,3727],{"class":723},[531,3989,720],{"class":537},[531,3991,592],{"class":537},[531,3993,3994],{"class":533,"line":694},[531,3995,1316],{"class":537},[531,3997,3998],{"class":533,"line":699},[531,3999,679],{"class":537},[19,4001,4002,4003,4006,4007,4009],{},"Dos columnas, 4 + 8 = 12. La imagen se ajusta a un ancho fijo y deja que gpdf calcule la altura por la relación de aspecto. Cada ",[31,4004,4005],{},"c.Text"," fluye debajo del anterior — sin ",[31,4008,49],{},", sin aritmética y. Cambia el orden de columnas si quieres el logo a la derecha.",[14,4011,4013],{"id":4012},"before-after-5-números-de-página-en-el-pie","Before / After 5: números de página en el pie",[19,4015,4016],{},"En gopdf mantienes la cuenta tú mismo, porque el render es de una sola pasada y el total no se conoce cuando dibujas el primer pie. La mayoría de bases de código hacen un workaround de dos pasadas: renderizar una vez para contar, renderizar de nuevo con el total ya conocido.",[19,4018,4019],{},[22,4020,520],{},[522,4022,4024],{"className":524,"code":4023,"language":526,"meta":527,"style":527},"totalPages := 0\npdf.AddFooter(func() {\n    totalPages++\n})\n\nbuildContent(&pdf)\nfinalTotal := totalPages\n\npdf2 := gopdf.GoPdf{}\npdf2.Start(gopdf.Config{PageSize: *gopdf.PageSizeA4})\npageNum := 0\npdf2.AddFooter(func() {\n    pageNum++\n    pdf2.SetFont(\"helvetica\", \"\", 8)\n    pdf2.SetXY(40, 800)\n    pdf2.Cell(nil, fmt.Sprintf(\"Página %d de %d\", pageNum, finalTotal))\n})\nbuildContent(&pdf2)\npdf2.WritePdf(\"report.pdf\")\n",[31,4025,4026,4036,4050,4058,4062,4066,4078,4088,4092,4107,4140,4149,4161,4168,4196,4215,4263,4267,4277],{"__ignoreMap":527},[531,4027,4028,4031,4033],{"class":533,"line":534},[531,4029,4030],{"class":619},"totalPages ",[531,4032,623],{"class":537},[531,4034,4035],{"class":808}," 0\n",[531,4037,4038,4040,4042,4045,4048],{"class":533,"line":545},[531,4039,1582],{"class":619},[531,4041,629],{"class":537},[531,4043,4044],{"class":606},"AddFooter",[531,4046,4047],{"class":537},"(func()",[531,4049,613],{"class":537},[531,4051,4052,4055],{"class":533,"line":552},[531,4053,4054],{"class":619},"    totalPages",[531,4056,4057],{"class":537},"++\n",[531,4059,4060],{"class":533,"line":562},[531,4061,679],{"class":537},[531,4063,4064],{"class":533,"line":574},[531,4065,549],{"emptyLinePlaceholder":548},[531,4067,4068,4071,4074,4076],{"class":533,"line":579},[531,4069,4070],{"class":606},"buildContent",[531,4072,4073],{"class":537},"(&",[531,4075,1582],{"class":619},[531,4077,592],{"class":537},[531,4079,4080,4083,4085],{"class":533,"line":589},[531,4081,4082],{"class":619},"finalTotal ",[531,4084,623],{"class":537},[531,4086,4087],{"class":619}," totalPages\n",[531,4089,4090],{"class":533,"line":595},[531,4091,549],{"emptyLinePlaceholder":548},[531,4093,4094,4097,4099,4101,4103,4105],{"class":533,"line":600},[531,4095,4096],{"class":619},"pdf2 ",[531,4098,623],{"class":537},[531,4100,626],{"class":541},[531,4102,629],{"class":537},[531,4104,632],{"class":541},[531,4106,635],{"class":537},[531,4108,4109,4112,4114,4116,4118,4120,4122,4124,4126,4128,4130,4132,4134,4136,4138],{"class":533,"line":616},[531,4110,4111],{"class":619},"pdf2",[531,4113,629],{"class":537},[531,4115,646],{"class":606},[531,4117,649],{"class":537},[531,4119,652],{"class":541},[531,4121,629],{"class":537},[531,4123,657],{"class":541},[531,4125,660],{"class":537},[531,4127,663],{"class":619},[531,4129,666],{"class":537},[531,4131,669],{"class":537},[531,4133,652],{"class":619},[531,4135,629],{"class":537},[531,4137,676],{"class":619},[531,4139,679],{"class":537},[531,4141,4142,4145,4147],{"class":533,"line":638},[531,4143,4144],{"class":619},"pageNum ",[531,4146,623],{"class":537},[531,4148,4035],{"class":808},[531,4150,4151,4153,4155,4157,4159],{"class":533,"line":682},[531,4152,4111],{"class":619},[531,4154,629],{"class":537},[531,4156,4044],{"class":606},[531,4158,4047],{"class":537},[531,4160,613],{"class":537},[531,4162,4163,4166],{"class":533,"line":694},[531,4164,4165],{"class":619},"    pageNum",[531,4167,4057],{"class":537},[531,4169,4170,4173,4175,4177,4179,4181,4183,4185,4187,4189,4191,4194],{"class":533,"line":699},[531,4171,4172],{"class":619},"    pdf2",[531,4174,629],{"class":537},[531,4176,790],{"class":606},[531,4178,649],{"class":537},[531,4180,720],{"class":537},[531,4182,724],{"class":723},[531,4184,720],{"class":537},[531,4186,729],{"class":537},[531,4188,803],{"class":537},[531,4190,729],{"class":537},[531,4192,4193],{"class":808}," 8",[531,4195,592],{"class":537},[531,4197,4198,4200,4202,4204,4206,4208,4210,4213],{"class":533,"line":753},[531,4199,4172],{"class":619},[531,4201,629],{"class":537},[531,4203,33],{"class":606},[531,4205,649],{"class":537},[531,4207,859],{"class":808},[531,4209,729],{"class":537},[531,4211,4212],{"class":808}," 800",[531,4214,592],{"class":537},[531,4216,4217,4219,4221,4223,4225,4228,4230,4233,4235,4237,4240,4244,4247,4249,4251,4253,4256,4258,4261],{"class":533,"line":771},[531,4218,4172],{"class":619},[531,4220,629],{"class":537},[531,4222,37],{"class":606},[531,4224,896],{"class":537},[531,4226,4227],{"class":619}," fmt",[531,4229,629],{"class":537},[531,4231,4232],{"class":606},"Sprintf",[531,4234,649],{"class":537},[531,4236,720],{"class":537},[531,4238,4239],{"class":723},"Página ",[531,4241,4243],{"class":4242},"swJcz","%d",[531,4245,4246],{"class":723}," de ",[531,4248,4243],{"class":4242},[531,4250,720],{"class":537},[531,4252,729],{"class":537},[531,4254,4255],{"class":619}," pageNum",[531,4257,729],{"class":537},[531,4259,4260],{"class":619}," finalTotal",[531,4262,3937],{"class":537},[531,4264,4265],{"class":533,"line":777},[531,4266,679],{"class":537},[531,4268,4269,4271,4273,4275],{"class":533,"line":822},[531,4270,4070],{"class":606},[531,4272,4073],{"class":537},[531,4274,4111],{"class":619},[531,4276,592],{"class":537},[531,4278,4279,4281,4283,4285,4287,4289,4292,4294],{"class":533,"line":837},[531,4280,4111],{"class":619},[531,4282,629],{"class":537},[531,4284,954],{"class":606},[531,4286,649],{"class":537},[531,4288,720],{"class":537},[531,4290,4291],{"class":723},"report.pdf",[531,4293,720],{"class":537},[531,4295,592],{"class":537},[19,4297,4298],{},"Si has mantenido código gopdf, has escrito esto. No está en ningún FAQ, pero es la única forma de obtener un pie honesto \"Página X de Y\" sin parsear la salida.",[19,4300,4301],{},[22,4302,1004],{},[522,4304,4306],{"className":524,"code":4305,"language":526,"meta":527,"style":527},"doc.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.Stack(template.AlignRight(), func(c *template.ColBuilder) {\n                c.Text(\"Página \", template.Inline())\n                c.PageNumber(template.Inline())\n                c.Text(\" de \", template.Inline())\n                c.TotalPages(template.Inline())\n            }, template.FontSize(8), template.TextColor(pdf.Gray(0.5)))\n        })\n    })\n})\n",[31,4307,4308,4335,4360,4390,4408,4444,4448,4478,4514,4542,4561,4587,4606,4643,4647,4651],{"__ignoreMap":527},[531,4309,4310,4313,4315,4318,4320,4322,4324,4326,4328,4331,4333],{"class":533,"line":534},[531,4311,4312],{"class":619},"doc",[531,4314,629],{"class":537},[531,4316,4317],{"class":606},"Footer",[531,4319,1205],{"class":537},[531,4321,19],{"class":1208},[531,4323,669],{"class":537},[531,4325,1214],{"class":541},[531,4327,629],{"class":537},[531,4329,4330],{"class":541},"PageBuilder",[531,4332,1222],{"class":537},[531,4334,613],{"class":537},[531,4336,4337,4340,4342,4344,4346,4348,4350,4352,4354,4356,4358],{"class":533,"line":545},[531,4338,4339],{"class":619},"    p",[531,4341,629],{"class":537},[531,4343,1202],{"class":606},[531,4345,1205],{"class":537},[531,4347,1209],{"class":1208},[531,4349,669],{"class":537},[531,4351,1214],{"class":541},[531,4353,629],{"class":537},[531,4355,1219],{"class":541},[531,4357,1222],{"class":537},[531,4359,613],{"class":537},[531,4361,4362,4364,4366,4368,4370,4372,4374,4376,4378,4380,4382,4384,4386,4388],{"class":533,"line":552},[531,4363,1229],{"class":619},[531,4365,629],{"class":537},[531,4367,1234],{"class":606},[531,4369,649],{"class":537},[531,4371,1825],{"class":808},[531,4373,729],{"class":537},[531,4375,1244],{"class":537},[531,4377,1247],{"class":1208},[531,4379,669],{"class":537},[531,4381,1214],{"class":541},[531,4383,629],{"class":537},[531,4385,1256],{"class":541},[531,4387,1222],{"class":537},[531,4389,613],{"class":537},[531,4391,4392,4394,4396,4398,4400,4402,4404,4406],{"class":533,"line":562},[531,4393,1265],{"class":619},[531,4395,629],{"class":537},[531,4397,1270],{"class":606},[531,4399,649],{"class":537},[531,4401,720],{"class":537},[531,4403,3545],{"class":723},[531,4405,720],{"class":537},[531,4407,2151],{"class":537},[531,4409,4410,4412,4414,4416,4418,4420,4422,4424,4426,4428,4430,4432,4434,4437,4439,4442],{"class":533,"line":574},[531,4411,2071],{"class":619},[531,4413,629],{"class":537},[531,4415,1288],{"class":606},[531,4417,649],{"class":537},[531,4419,3879],{"class":808},[531,4421,1296],{"class":537},[531,4423,1283],{"class":619},[531,4425,629],{"class":537},[531,4427,2184],{"class":606},[531,4429,649],{"class":537},[531,4431,1582],{"class":619},[531,4433,629],{"class":537},[531,4435,4436],{"class":606},"Gray",[531,4438,649],{"class":537},[531,4440,4441],{"class":808},"0.5",[531,4443,3862],{"class":537},[531,4445,4446],{"class":533,"line":579},[531,4447,1311],{"class":537},[531,4449,4450,4452,4454,4456,4458,4460,4462,4464,4466,4468,4470,4472,4474,4476],{"class":533,"line":589},[531,4451,1229],{"class":619},[531,4453,629],{"class":537},[531,4455,1234],{"class":606},[531,4457,649],{"class":537},[531,4459,1825],{"class":808},[531,4461,729],{"class":537},[531,4463,1244],{"class":537},[531,4465,1247],{"class":1208},[531,4467,669],{"class":537},[531,4469,1214],{"class":541},[531,4471,629],{"class":537},[531,4473,1256],{"class":541},[531,4475,1222],{"class":537},[531,4477,613],{"class":537},[531,4479,4480,4482,4484,4487,4489,4491,4493,4496,4498,4500,4502,4504,4506,4508,4510,4512],{"class":533,"line":595},[531,4481,1265],{"class":619},[531,4483,629],{"class":537},[531,4485,4486],{"class":606},"Stack",[531,4488,649],{"class":537},[531,4490,1214],{"class":619},[531,4492,629],{"class":537},[531,4494,4495],{"class":606},"AlignRight",[531,4497,2162],{"class":537},[531,4499,1244],{"class":537},[531,4501,1247],{"class":1208},[531,4503,669],{"class":537},[531,4505,1214],{"class":541},[531,4507,629],{"class":537},[531,4509,1256],{"class":541},[531,4511,1222],{"class":537},[531,4513,613],{"class":537},[531,4515,4516,4519,4521,4523,4525,4527,4529,4531,4533,4535,4537,4540],{"class":533,"line":600},[531,4517,4518],{"class":619},"                c",[531,4520,629],{"class":537},[531,4522,1270],{"class":606},[531,4524,649],{"class":537},[531,4526,720],{"class":537},[531,4528,4239],{"class":723},[531,4530,720],{"class":537},[531,4532,729],{"class":537},[531,4534,1283],{"class":619},[531,4536,629],{"class":537},[531,4538,4539],{"class":606},"Inline",[531,4541,1306],{"class":537},[531,4543,4544,4546,4548,4551,4553,4555,4557,4559],{"class":533,"line":616},[531,4545,4518],{"class":619},[531,4547,629],{"class":537},[531,4549,4550],{"class":606},"PageNumber",[531,4552,649],{"class":537},[531,4554,1214],{"class":619},[531,4556,629],{"class":537},[531,4558,4539],{"class":606},[531,4560,1306],{"class":537},[531,4562,4563,4565,4567,4569,4571,4573,4575,4577,4579,4581,4583,4585],{"class":533,"line":638},[531,4564,4518],{"class":619},[531,4566,629],{"class":537},[531,4568,1270],{"class":606},[531,4570,649],{"class":537},[531,4572,720],{"class":537},[531,4574,4246],{"class":723},[531,4576,720],{"class":537},[531,4578,729],{"class":537},[531,4580,1283],{"class":619},[531,4582,629],{"class":537},[531,4584,4539],{"class":606},[531,4586,1306],{"class":537},[531,4588,4589,4591,4593,4596,4598,4600,4602,4604],{"class":533,"line":682},[531,4590,4518],{"class":619},[531,4592,629],{"class":537},[531,4594,4595],{"class":606},"TotalPages",[531,4597,649],{"class":537},[531,4599,1214],{"class":619},[531,4601,629],{"class":537},[531,4603,4539],{"class":606},[531,4605,1306],{"class":537},[531,4607,4608,4611,4613,4615,4617,4619,4621,4623,4625,4627,4629,4631,4633,4635,4637,4639,4641],{"class":533,"line":694},[531,4609,4610],{"class":537},"            },",[531,4612,1283],{"class":619},[531,4614,629],{"class":537},[531,4616,1288],{"class":606},[531,4618,649],{"class":537},[531,4620,3879],{"class":808},[531,4622,1296],{"class":537},[531,4624,1283],{"class":619},[531,4626,629],{"class":537},[531,4628,2184],{"class":606},[531,4630,649],{"class":537},[531,4632,1582],{"class":619},[531,4634,629],{"class":537},[531,4636,4436],{"class":606},[531,4638,649],{"class":537},[531,4640,4441],{"class":808},[531,4642,3862],{"class":537},[531,4644,4645],{"class":533,"line":699},[531,4646,1311],{"class":537},[531,4648,4649],{"class":533,"line":753},[531,4650,1316],{"class":537},[531,4652,4653],{"class":533,"line":771},[531,4654,679],{"class":537},[19,4656,4657,2738,4659,4661],{},[31,4658,4550],{},[31,4660,4595],{}," son placeholders. El motor de layout pagina primero, resuelve los totales y luego los escribe. Una pasada, sin contador manual, sin doble render.",[14,4663,4665],{"id":4664},"texto-cjk-sin-la-danza-del-subset-manual","Texto CJK sin la danza del subset manual",[19,4667,4668],{},"signintech/gopdf soporta CJK bien, pero el camino es bookkeeping de conjunto de caracteres a mano. Añades el TTF, fijas el mapa de caracteres, y si tu texto contiene un glifo fuera del subset que registraste, sale tofu. El subseter TrueType de gpdf recorre el cmap (formatos 4, 6, 12) e incrusta exactamente los glifos que usaste — sin lista manual de subset.",[522,4670,4672],{"className":524,"code":4671,"language":526,"meta":527,"style":527},"//go:embed NotoSansJP-Regular.ttf\nvar notoJP []byte\n\ndoc := gpdf.NewDocument(\n    gpdf.WithPageSize(document.A4),\n    gpdf.WithMargins(document.UniformEdges(document.Mm(20))),\n    gpdf.WithFont(\"NotoSansJP\", notoJP),\n    gpdf.WithDefaultFont(\"NotoSansJP\", 14),\n)\n\npage := doc.AddPage()\npage.AutoRow(func(r *template.RowBuilder) {\n    r.Col(12, func(c *template.ColBuilder) {\n        c.Text(\"こんにちは、世界。\")\n        c.Text(\"吾輩は猫である。名前はまだ無い。\")\n    })\n})\n",[31,4673,4674,4679,4690,4694,4709,4728,4758,4783,4806,4810,4814,4829,4853,4883,4902,4921,4925],{"__ignoreMap":527},[531,4675,4676],{"class":533,"line":534},[531,4677,4678],{"class":1482},"//go:embed NotoSansJP-Regular.ttf\n",[531,4680,4681,4683,4686,4688],{"class":533,"line":545},[531,4682,3757],{"class":537},[531,4684,4685],{"class":619}," notoJP ",[531,4687,3763],{"class":537},[531,4689,3766],{"class":1674},[531,4691,4692],{"class":533,"line":552},[531,4693,549],{"emptyLinePlaceholder":548},[531,4695,4696,4699,4701,4703,4705,4707],{"class":533,"line":562},[531,4697,4698],{"class":619},"doc ",[531,4700,623],{"class":537},[531,4702,1101],{"class":619},[531,4704,629],{"class":537},[531,4706,1106],{"class":606},[531,4708,1109],{"class":537},[531,4710,4711,4714,4716,4718,4720,4722,4724,4726],{"class":533,"line":574},[531,4712,4713],{"class":619},"    gpdf",[531,4715,629],{"class":537},[531,4717,1119],{"class":606},[531,4719,649],{"class":537},[531,4721,1124],{"class":619},[531,4723,629],{"class":537},[531,4725,1129],{"class":619},[531,4727,1132],{"class":537},[531,4729,4730,4732,4734,4736,4738,4740,4742,4744,4746,4748,4750,4752,4754,4756],{"class":533,"line":579},[531,4731,4713],{"class":619},[531,4733,629],{"class":537},[531,4735,1141],{"class":606},[531,4737,649],{"class":537},[531,4739,1124],{"class":619},[531,4741,629],{"class":537},[531,4743,1150],{"class":606},[531,4745,649],{"class":537},[531,4747,1124],{"class":619},[531,4749,629],{"class":537},[531,4751,1159],{"class":606},[531,4753,649],{"class":537},[531,4755,1164],{"class":808},[531,4757,1167],{"class":537},[531,4759,4760,4762,4764,4767,4769,4771,4774,4776,4778,4781],{"class":533,"line":589},[531,4761,4713],{"class":619},[531,4763,629],{"class":537},[531,4765,4766],{"class":606},"WithFont",[531,4768,649],{"class":537},[531,4770,720],{"class":537},[531,4772,4773],{"class":723},"NotoSansJP",[531,4775,720],{"class":537},[531,4777,729],{"class":537},[531,4779,4780],{"class":619}," notoJP",[531,4782,1132],{"class":537},[531,4784,4785,4787,4789,4792,4794,4796,4798,4800,4802,4804],{"class":533,"line":595},[531,4786,4713],{"class":619},[531,4788,629],{"class":537},[531,4790,4791],{"class":606},"WithDefaultFont",[531,4793,649],{"class":537},[531,4795,720],{"class":537},[531,4797,4773],{"class":723},[531,4799,720],{"class":537},[531,4801,729],{"class":537},[531,4803,3503],{"class":808},[531,4805,1132],{"class":537},[531,4807,4808],{"class":533,"line":600},[531,4809,592],{"class":537},[531,4811,4812],{"class":533,"line":616},[531,4813,549],{"emptyLinePlaceholder":548},[531,4815,4816,4819,4821,4823,4825,4827],{"class":533,"line":638},[531,4817,4818],{"class":619},"page ",[531,4820,623],{"class":537},[531,4822,1186],{"class":619},[531,4824,629],{"class":537},[531,4826,57],{"class":606},[531,4828,691],{"class":537},[531,4830,4831,4833,4835,4837,4839,4841,4843,4845,4847,4849,4851],{"class":533,"line":682},[531,4832,1939],{"class":619},[531,4834,629],{"class":537},[531,4836,1202],{"class":606},[531,4838,1205],{"class":537},[531,4840,1209],{"class":1208},[531,4842,669],{"class":537},[531,4844,1214],{"class":541},[531,4846,629],{"class":537},[531,4848,1219],{"class":541},[531,4850,1222],{"class":537},[531,4852,613],{"class":537},[531,4854,4855,4857,4859,4861,4863,4865,4867,4869,4871,4873,4875,4877,4879,4881],{"class":533,"line":694},[531,4856,3077],{"class":619},[531,4858,629],{"class":537},[531,4860,1234],{"class":606},[531,4862,649],{"class":537},[531,4864,1239],{"class":808},[531,4866,729],{"class":537},[531,4868,1244],{"class":537},[531,4870,1247],{"class":1208},[531,4872,669],{"class":537},[531,4874,1214],{"class":541},[531,4876,629],{"class":537},[531,4878,1256],{"class":541},[531,4880,1222],{"class":537},[531,4882,613],{"class":537},[531,4884,4885,4887,4889,4891,4893,4895,4898,4900],{"class":533,"line":699},[531,4886,3108],{"class":619},[531,4888,629],{"class":537},[531,4890,1270],{"class":606},[531,4892,649],{"class":537},[531,4894,720],{"class":537},[531,4896,4897],{"class":723},"こんにちは、世界。",[531,4899,720],{"class":537},[531,4901,592],{"class":537},[531,4903,4904,4906,4908,4910,4912,4914,4917,4919],{"class":533,"line":753},[531,4905,3108],{"class":619},[531,4907,629],{"class":537},[531,4909,1270],{"class":606},[531,4911,649],{"class":537},[531,4913,720],{"class":537},[531,4915,4916],{"class":723},"吾輩は猫である。名前はまだ無い。",[531,4918,720],{"class":537},[531,4920,592],{"class":537},[531,4922,4923],{"class":533,"line":771},[531,4924,1316],{"class":537},[531,4926,4927],{"class":533,"line":777},[531,4928,679],{"class":537},[19,4930,4931],{},"Una factura japonesa de 200 caracteres produce un subset de fuente de ~30 KB en lugar de un embed completo de 4 MB.",[14,4933,4935],{"id":4934},"benchmarks","Benchmarks",[19,4937,4938],{},"Mismo hardware, mismas cargas, Apple M1 con Go 1.25.",[137,4940,4941,4958],{},[140,4942,4943],{},[143,4944,4945,4948,4950,4952,4955],{},[146,4946,4947],{},"Benchmark",[146,4949,24],{},[146,4951,28],{},[146,4953,4954],{},"gofpdf",[146,4956,4957],{},"Maroto v2",[154,4959,4960,4979,4997,5015],{},[143,4961,4962,4965,4970,4973,4976],{},[159,4963,4964],{},"Página única",[159,4966,4967],{},[22,4968,4969],{},"13 µs",[159,4971,4972],{},"423 µs",[159,4974,4975],{},"132 µs",[159,4977,4978],{},"237 µs",[143,4980,4981,4984,4988,4991,4994],{},[159,4982,4983],{},"Tabla 4×10",[159,4985,4986],{},[22,4987,3313],{},[159,4989,4990],{},"835 µs",[159,4992,4993],{},"241 µs",[159,4995,4996],{},"8.6 ms",[143,4998,4999,5002,5007,5009,5012],{},[159,5000,5001],{},"Reporte 100 páginas",[159,5003,5004],{},[22,5005,5006],{},"683 µs",[159,5008,4996],{},[159,5010,5011],{},"11.7 ms",[159,5013,5014],{},"19.8 ms",[143,5016,5017,5020,5025,5028,5031],{},[159,5018,5019],{},"Factura CJK compleja",[159,5021,5022],{},[22,5023,5024],{},"133 µs",[159,5026,5027],{},"997 µs",[159,5029,5030],{},"254 µs",[159,5032,5033],{},"10.4 ms",[19,5035,5036,5037,629],{},"Números de ",[31,5038,5039],{},"gpdf/_benchmark/benchmark_test.go",[19,5041,5042,5043,5046],{},"A ",[22,5044,5045],{},"108 µs por página con tabla"," en un solo core son ~9.000 facturas/segundo. Para la mayoría de cargas, la generación PDF puede vivir en la ruta de la request.",[14,5048,5050],{"id":5049},"lo-que-gopdf-hace-y-gpdf-no","Lo que gopdf hace y gpdf no",[19,5052,5053],{},"Sección honesta. Si tu uso de gopdf depende de esto, la migración no te llevará todo el camino con este artículo.",[5055,5056,5057,5074,5080,5094],"ul",{},[5058,5059,5060,5065,5066,5069,5070,5073],"li",{},[22,5061,5062,629],{},[31,5063,5064],{},"ImportPage"," Importar una página de un PDF existente y estampar contenido encima. El overlay de gpdf (",[31,5067,5068],{},"gpdf.Overlay",") cubre el caso común, pero no expone la primitiva ",[31,5071,5072],{},"UseImportedTemplate"," exacta.",[5058,5075,5076,5079],{},[22,5077,5078],{},"Polígonos y óvalos como primitivas."," El conjunto primitivo de gpdf es rectángulos, líneas, imágenes, texto y tablas; el dibujo de paths arbitrarios no es de primera clase. Para visualización, renderiza con una librería de charts a PNG/SVG y embebe.",[5058,5081,5082,5085,5086,5089,5090,5093],{},[22,5083,5084],{},"Posicionamiento directo de cursor."," Si necesitas colocación pixel-perfect (un sello exactamente en ",[31,5087,5088],{},"(420, 240)","), ",[31,5091,5092],{},"page.Absolute(x, y, fn)"," existe, pero es la salida de emergencia.",[5058,5095,5096,5104,5105,402,5107,5109],{},[22,5097,5098,402,5101,629],{},[31,5099,5100],{},"PlaceHolderText",[31,5102,5103],{},"FillInPlaceHoldText"," Un mecanismo general \"rellena este hueco después\" no existe aún en gpdf; los placeholders ",[31,5106,4550],{},[31,5108,4595],{}," cubren el caso de numeración.",[19,5111,5112,5113,5116],{},"Para ",[22,5114,5115],{},"facturas, estados de cuenta, reportes, certificados, contratos, recibos, etiquetas de envío, albaranes y documentos CJK"," — lo que la mayoría de presupuestos gopdf realmente generan — el cambio es completo.",[14,5118,5120],{"id":5119},"faq","FAQ",[19,5122,5123,5126],{},[22,5124,5125],{},"¿Es gpdf un fork de signintech/gopdf?","\nNo. gpdf es una reimplementación limpia en Go puro. Sin código compartido ni linaje compartido.",[19,5128,5129,5132],{},[22,5130,5131],{},"Ambas son Go puro y sin CGO. ¿Cuál es el valor real del cambio?","\nEl motor de layout. Las secciones de migración arriba son 80% sobre eliminar matemática de coordenadas, y esa es la diferencia día a día. Los benchmarks son una victoria secundaria. La licencia MIT es idéntica a la MIT de gopdf, así que la licencia no es un factor.",[19,5134,5135,5138,5139,5142,5143,5146],{},[22,5136,5137],{},"¿Puedo migrar incrementalmente?","\nSí — las dos librerías no entran en conflicto. Producen ",[31,5140,5141],{},"[]byte"," independientes. Renderiza una sección con gpdf, otra con gopdf, y ",[31,5144,5145],{},"gpdf.Merge(a, b)"," las pega. En la práctica, la mayoría encuentra más fácil migrar un documento entero a la vez.",[19,5148,5149,5156,5157,5160,5161,5164,5165,5168],{},[22,5150,5151,5152,5155],{},"Mi código existente usa ",[31,5153,5154],{},"pdf.Image(path, ...)"," para cargar logos. ¿Tengo que embeber?","\nNo tienes que. ",[31,5158,5159],{},"c.Image(imageBytes, ...)"," toma bytes — usa ",[31,5162,5163],{},"os.ReadFile"," si quieres carga en runtime. Pero ",[31,5166,5167],{},"//go:embed"," es el mejor por defecto.",[19,5170,5171,5178,34,5181,34,5184,5187,5188,629],{},[22,5172,5173,5174,5177],{},"¿Y ",[31,5175,5176],{},"gopdf.PageSizeA4"," y otras constantes de tamaño?",[31,5179,5180],{},"document.A4",[31,5182,5183],{},"document.Letter",[31,5185,5186],{},"document.Legal"," cubren el mismo conjunto. Para tamaños custom: ",[31,5189,5190],{},"document.PageSize(document.Mm(210), document.Mm(297))",[19,5192,5193,5200,5202,5203,629],{},[22,5194,5195,5196,5199],{},"Mi generador usa ",[31,5197,5198],{},"pdf.Rotate"," para sellos en diagonal. ¿Hay equivalente?",[31,5201,5092],{}," acepta opción de rotación; el patrón típico de \"marca de agua diagonal\" es una llamada ",[31,5204,5205],{},"page.Absolute",[19,5207,5208,5211,5212,1567,5214,5216,5217,1567,5220,5222],{},[22,5209,5210],{},"¿Hay una herramienta que reescriba mi código automáticamente?","\nAún no. El mapeo de partes simples (",[31,5213,33],{},[31,5215,37],{}," → ",[31,5218,5219],{},"r.Col",[31,5221,4005],{},") es mecánico, pero la reescritura de tablas es estructural — borras el bookkeeping en lugar de traducirlo. La migración manual de un generador típico lleva unas horas por tipo de documento.",[14,5224,5226],{"id":5225},"probar-gpdf","Probar gpdf",[19,5228,5229],{},"gpdf es una biblioteca Go para generar PDFs. Licencia MIT, cero dependencias externas, soporte CJK nativo, layout en grilla de 12 columnas.",[522,5231,5235],{"className":5232,"code":5233,"language":5234,"meta":527,"style":527},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","go get github.com/gpdf-dev/gpdf\n","bash",[31,5236,5237],{"__ignoreMap":527},[531,5238,5239,5241,5244],{"class":533,"line":534},[531,5240,526],{"class":541},[531,5242,5243],{"class":723}," get",[531,5245,5246],{"class":723}," github.com/gpdf-dev/gpdf\n",[19,5248,5249,5256,5257],{},[5250,5251,5255],"a",{"href":5252,"rel":5253},"https://github.com/gpdf-dev/gpdf",[5254],"nofollow","⭐ Star en GitHub"," · ",[5250,5258,5261],{"href":5259,"rel":5260},"https://gpdf.dev/es/docs/quickstart",[5254],"Lee la documentación",[14,5263,5265],{"id":5264},"lecturas-siguientes","Lecturas siguientes",[5055,5267,5268,5274,5280,5286,5292],{},[5058,5269,5270],{},[5250,5271,5273],{"href":5272},"/es/blog/12-column-grid","La grilla de 12 columnas: pensamiento Bootstrap para layout PDF",[5058,5275,5276],{},[5250,5277,5279],{"href":5278},"/es/blog/bootstrap-grid-thinking-for-pdf","Pensamiento de grilla Bootstrap para PDF",[5058,5281,5282],{},[5250,5283,5285],{"href":5284},"/es/blog/gofpdf-migration","gofpdf está archivado. Cómo migrar a gpdf.",[5058,5287,5288],{},[5250,5289,5291],{"href":5290},"/es/blog/unidoc-migration","unipdf es AGPL o de pago. Cómo migrar a gpdf.",[5058,5293,5294],{},[5250,5295,5297],{"href":5296},"/es/blog/invoice-pdf-go-under-50-lines","Generar una factura PDF en Go en menos de 50 líneas",[5299,5300,5301],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}",{"title":527,"searchDepth":545,"depth":545,"links":5303},[5304,5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315,5316,5317,5318],{"id":16,"depth":545,"text":17},{"id":67,"depth":545,"text":68},{"id":89,"depth":545,"text":90},{"id":131,"depth":545,"text":132},{"id":511,"depth":545,"text":512},{"id":1448,"depth":545,"text":1449},{"id":2231,"depth":545,"text":2232},{"id":3321,"depth":545,"text":3322},{"id":4012,"depth":545,"text":4013},{"id":4664,"depth":545,"text":4665},{"id":4934,"depth":545,"text":4935},{"id":5049,"depth":545,"text":5050},{"id":5119,"depth":545,"text":5120},{"id":5225,"depth":545,"text":5226},{"id":5264,"depth":545,"text":5265},"2026-05-06","signintech/gopdf funciona, pero cada celda, línea y encabezado es un cálculo (x, y). Esta guía mapea la API de gopdf a gpdf — el mismo Go, sin coordenadas.",false,"md",{"name":5324,"totalTime":5325,"tools":5326,"steps":5328},"Migrar un proyecto Go de signintech/gopdf a gpdf","PT40M",[5327],"Go 1.22+",[5329,5332,5335,5338,5341,5344,5347],{"name":5330,"text":5331},"Reemplazar la ruta de import","Cambiar github.com/signintech/gopdf por github.com/gpdf-dev/gpdf, github.com/gpdf-dev/gpdf/document y github.com/gpdf-dev/gpdf/template. La struct gopdf.GoPdf{} con cursor mutable compartido desaparece — no hay tipo equivalente en gpdf.",{"name":5333,"text":5334},"Reemplazar pdf.Start y pdf.AddPage por gpdf.NewDocument","Construir el documento con gpdf.NewDocument(WithPageSize(document.A4), WithMargins(...)). doc.AddPage() devuelve un PageBuilder, no un cursor. Deja de rastrear la posición y a mano.",{"name":5336,"text":5337},"Eliminar todas las llamadas a SetX, SetY y SetXY","Borrar todas las llamadas de cursor. Envolver el contenido en page.AutoRow(func(r *RowBuilder)) y r.Col(span, func(c *ColBuilder)). La grilla de 12 columnas maneja la disposición horizontal; AutoRow apila vertical sin matemática manual de y.",{"name":5339,"text":5340},"Reemplazar Cell y MultiCell por c.Text","Dentro de una columna, llamar c.Text(string, options...) en lugar de calcular un Rect y llamar Cell o MultiCell. El ajuste de línea es automático — la columna conoce su propio ancho.",{"name":5342,"text":5343},"Reescribir bucles manuales de tabla con c.Table","Reemplazar los bucles SetXY/Cell que dibujan cada fila de encabezado y cuerpo por c.Table(headers, rows, template.ColumnWidths(...)). Bordes, saltos de página y repetición de encabezado son manejados por el motor de layout.",{"name":5345,"text":5346},"Cambiar el registro de fuentes a bytes","Reemplazar pdf.AddTTFFont(name, path) por gpdf.WithFont(name, ttfBytes) en la construcción. Embeber el TTF vía //go:embed para que el binario deje de necesitar una ruta de fuente en runtime.",{"name":5348,"text":5349},"Reemplazar WritePdf por doc.Generate más os.WriteFile","Cambiar pdf.WritePdf(path) por data, _ := doc.Generate() y luego os.WriteFile(path, data, 0o644). Usar doc.Render(w) cuando se quiera transmitir directamente a un http.ResponseWriter o S3 PutObject.",null,{},"/es/blog/signintech-gopdf-migration",{"title":5,"description":5320},"es/blog/021.signintech-gopdf-migration",[5356,5357,5358],"migration","comparison","tutorial","IwVWYmFZ5tZtGOxpdI8ohsIlFLXTKkjXZe3sZnKnvTM",1779199041836]