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