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