[{"data":1,"prerenderedAt":1946},["ShallowReactive",2],{"blog-ko-japanese-pdf-in-go":3},{"id":4,"title":5,"author":6,"body":9,"date":1907,"description":1908,"draft":1909,"extension":1910,"howTo":1911,"image":1936,"meta":1937,"navigation":349,"path":1938,"seo":1939,"stem":1940,"tags":1941,"updated":1936,"__hash__":1945},"blogKo/ko/blog/007.japanese-pdf-in-go.md","Go로 일본어 PDF 만들기 — 2026 결정판 가이드",{"name":7,"url":8},"gpdf team","https://gpdf.dev",{"type":10,"value":11,"toc":1893},"minimark",[12,17,43,47,50,57,68,71,75,86,128,143,153,157,160,289,292,298,308,312,322,1296,1299,1355,1364,1368,1377,1380,1387,1436,1450,1453,1477,1493,1497,1500,1508,1511,1526,1536,1618,1624,1627,1630,1640,1650,1674,1688,1691,1695,1702,1712,1721,1735,1742,1746,1772,1778,1788,1802,1812,1821,1825,1828,1843,1857,1861,1889],[13,14,16],"h2",{"id":15},"tldr","TL;DR",[18,19,20,21,25,26,29,30,33,34,38,39,42],"p",{},"Go PDF에 ",[22,23,24],"code",{},"こんにちは","라 썼는데 두부 □□□□□ 다섯 개가 나왔다면, 해법은 재작성이 아니라 설정 2줄이다. TTF를 읽고 ",[22,27,28],{},"gpdf.WithFont","를 ",[22,31,32],{},"NewDocument","에 넘긴 뒤 일본어를 쓴다. ",[35,36,37],"strong",{},"gpdf는 글리프 테이블을 자동으로 서브셋한다"," — 출력에는 실제로 쓴 문자의 글리프만 실린다. 5 MB 풀 폰트가 아닌 약 30 KB. 이 글은 그 전체 지도다: Go에서 일본어 PDF가 왜 묘하게 어려웠는지, 2026년의 현실적 선택지 네 개, 동작하는 예제, 폰트 서브셋의 내부, 혼용 조판의 실무, 그리고 ",[35,40,41],{},"아직 풀리지 않은 부분",".",[13,44,46],{"id":45},"이-가이드가-존재하는-이유","이 가이드가 존재하는 이유",[18,48,49],{},"Go에서 일본어 PDF를 뱉는 것은 본래 5분짜리 작업이다. 많은 팀에서 하루 반이 걸린다.",[18,51,52,53,56],{},"익숙한 전개: 누군가 ",[22,54,55],{},"AddUTF8Font","를 끼워넣는다 → PDF에 빈 사각형이 줄지어 나온다 — 그 유명한 豆腐 — 시니어 한 명이 오후 내내 폰트 경로인지, 서브셋 플래그인지, CMap인지, UTF-8 스위치인지, PDF 리더 문제인지를 좁힌다. 저녁이면 Slack에 \"왜 漢字가 아직 깨졌는가\"라는 스레드가 서고, 다음 날 누구나 후회할 헬퍼 세 개가 추가된 PR이 올라온다.",[18,58,59,60,63,64,67],{},"근본 원인은 그중 어느 것도 아니다. ",[35,61,62],{},"Go에서 가장 오래 살아남은 PDF 라이브러리가 2002년의 PHP와 Latin-1을 전제로 설계","된 것과, 그 이후 쓰인 일본어 튜토리얼 대부분이 그 유산과 싸워왔다는 것. 이 글은 2026판이다 — 백지에서 시작할 때 실제로 동작하는 방법과, ",[35,65,66],{},"여전히 어려운 지점","을 정직하게.",[18,69,70],{},"본문 코드는 gpdf v1.x (2026-04 기준)에서 동작 확인. 벤치 수치는 Apple M1 + Go 1.25.",[13,72,74],{"id":73},"두부-문제를-90초에","두부 문제를 90초에",[18,76,77,78,81,82,85],{},"PDF는 Unicode를 모른다. PDF가 아는 것은 ",[35,79,80],{},"글리프 ID"," — 임베디드 글리프 테이블의 정수 인덱스. ",[22,83,84],{},"\"こんにちは\"","를 PDF에 쓰려면 누군가 다음을 모두 해야 한다:",[87,88,89,100,106,112],"ol",{},[90,91,92,95,96,99],"li",{},[35,93,94],{},"TTF 파싱"," — ",[22,97,98],{},"cmap"," 서브테이블에서 각 코드포인트에 해당하는 글리프 ID를 찾는다.",[90,101,102,105],{},[35,103,104],{},"ToUnicode CMap 작성"," — 사용자가 복사·검색할 때 글리프를 텍스트로 되돌릴 수 있게.",[90,107,108,111],{},[35,109,110],{},"서브셋화"," — Noto Sans JP의 2만 글리프를 전부 싣지 않도록.",[90,113,114,95,117,120,121,120,124,127],{},[35,115,116],{},"임베딩",[22,118,119],{},"name","·",[22,122,123],{},"OS/2",[22,125,126],{},"head"," 테이블과 인코딩 오브젝트를 올바르게 엮어서.",[18,129,130,131,134,135,138,139,142],{},"이 중 어느 것이라도 빠지거나 틀리면 리더는 코드포인트에 해당하는 글리프를 못 찾고 두부를 그린다. 아카이브된 ",[22,132,133],{},"jung-kurt/gofpdf","와 ",[22,136,137],{},"go-pdf/fpdf"," 계열은 이 모든 것을 ",[35,140,141],{},"단일 바이트 폰트 전제의 내부 모델에 덧댔다"," — 2002년의 FPDF는 Latin-1만 알았다. 설정이 부서지기 쉬운 이유, 출력이 서브셋이 아닌 풀 폰트를 자주 임베드하는 이유, OS·리더에 따라 부서지는 양상이 다른 이유가 여기에 있다.",[18,144,145,146,149,150,152],{},"gpdf는 CJK를 ",[35,147,148],{},"일급 사용례","로 다룬다. TTF 서브셋터가 코어 패키지에 포함된다. ToUnicode CMap은 자동으로 쓰인다. 단일 바이트 폰트 유산이 없으니 ",[22,151,55],{}," 춤도 없다.",[13,154,156],{"id":155},"_2026년의-현실적-선택지-네-개","2026년의 현실적 선택지 네 개",[18,158,159],{},"코드 전에 정직한 판 — \"일본어 지원\"은 \"올바른 TTF가 주어졌을 때 크래시도 두부도 없이 임의의 일본어를 렌더할 수 있다\"의 의미로 쓴다.",[161,162,163,188],"table",{},[164,165,166],"thead",{},[167,168,169,173,176,179,182,185],"tr",{},[170,171,172],"th",{},"선택지",[170,174,175],{},"라이선스",[170,177,178],{},"의존",[170,180,181],{},"CJK 경로",[170,183,184],{},"300자 문서 크기",[170,186,187],{},"비고",[189,190,191,216,239,264],"tbody",{},[167,192,193,199,202,205,210,213],{},[194,195,196,198],"td",{},[22,197,137],{}," (2025 아카이브)",[194,200,201],{},"MIT",[194,203,204],{},"표준 라이브러리",[194,206,207,209],{},[22,208,55],{}," 덧댐",[194,211,212],{},"약 5 MB (풀)",[194,214,215],{},"Latin-1 코어 위에 덧댐. 서브셋은 옵트인이며 불완전.",[167,217,218,223,225,227,233,236],{},[194,219,220],{},[22,221,222],{},"signintech/gopdf",[194,224,201],{},[194,226,204],{},[194,228,229,232],{},[22,230,231],{},"AddTTFFont"," + 수동",[194,234,235],{},"약 3 MB",[194,237,238],{},"저수준. 좌표를 직접 쓴다. 서브셋 기능은 있지만 수동 구동.",[167,240,241,247,250,255,258,261],{},[194,242,243,246],{},[22,244,245],{},"chromedp"," + Chromium",[194,248,249],{},"MIT + Chrome",[194,251,252],{},[35,253,254],{},"Chromium 바이너리",[194,256,257],{},"브라우저 네이티브",[194,259,260],{},"가변",[194,262,263],{},"HTML/CSS. 컨테이너에 폰트 설치 필요. 이미지 500 MB+.",[167,265,266,271,273,278,281,286],{},[194,267,268],{},[22,269,270],{},"gpdf",[194,272,201],{},[194,274,275],{},[35,276,277],{},"표준만",[194,279,280],{},"네이티브, 자동 서브셋",[194,282,283],{},[35,284,285],{},"약 30 KB",[194,287,288],{},"순수 Go. Builder API. ToUnicode CMap 자동 기록.",[18,290,291],{},"두 가지 강조:",[18,293,294,297],{},[35,295,296],{},"\"풀 임베드\"와 \"자동 서브셋\"의 160배 차이는 오차가 아니다."," 10줄짜리 EC 일본어 청구서 PDF가 사용하는 고유 글리프는 많아야 120개쯤. 매번 풀 Noto Sans JP (5.1 MB)를 임베드하면 연말까지 같은 5 MB 글리프 데이터가 오브젝트 스토리지에 1000만 번 복사된다. 서브셋 임베드는 사용한 글리프만 싣는다.",[18,299,300,303,304,307],{},[35,301,302],{},"\"chromedp 된다\"는 사실이고, 가장 비싼 답이다."," 스크린샷 용도로 헤드리스 Chrome 함대를 이미 운용 중인 팀이라면 PDF도 거기 얹는 게 괜찮다. 그게 아니라 ",[35,305,306],{},"오직 일본어 출력을 위해"," Chromium을 세우는 것은, 40줄의 Go로 풀리는 문제에 과한 인프라다.",[13,309,311],{"id":310},"가장-짧은-동작-경로","가장 짧은 동작 경로",[18,313,314,315,318,319,42],{},"먼저 이걸 돌린다. 완전형 — 복사해서 ",[22,316,317],{},"main.go","로 저장하고 TTF 두 개를 옆에 두고 ",[22,320,321],{},"go run main.go",[323,324,329],"pre",{"className":325,"code":326,"language":327,"meta":328,"style":328},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","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    regular, err := os.ReadFile(\"NotoSansJP-Regular.ttf\")\n    if err != nil {\n        log.Fatal(err)\n    }\n    bold, err := os.ReadFile(\"NotoSansJP-Bold.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(\"NotoSansJP\", regular),\n        gpdf.WithFont(\"NotoSansJP-Bold\", bold),\n        gpdf.WithDefaultFont(\"NotoSansJP\", 11),\n    )\n\n    page := doc.AddPage()\n    page.AutoRow(func(r *template.RowBuilder) {\n        r.Col(12, func(c *template.ColBuilder) {\n            c.Text(\"請求書\", template.FontFamily(\"NotoSansJP-Bold\"), template.FontSize(22))\n            c.Text(\"2026 年 4 月 16 日\")\n        })\n    })\n    page.AutoRow(func(r *template.RowBuilder) {\n        r.Col(7, func(c *template.ColBuilder) {\n            c.Text(\"株式会社 ABC 御中\", template.FontSize(13))\n            c.Text(\"〒 100-0001 東京都千代田区千代田 1-1\")\n        })\n        r.Col(5, func(c *template.ColBuilder) {\n            c.Text(\"合計 ¥ 128,000\", template.FontFamily(\"NotoSansJP-Bold\"), template.AlignRight())\n            c.Text(\"支払期限: 2026-05-31\", template.AlignRight())\n        })\n    })\n\n    data, err := doc.Generate()\n    if err != nil {\n        log.Fatal(err)\n    }\n    if err := os.WriteFile(\"invoice-ja.pdf\", data, 0o644); err != nil {\n        log.Fatal(err)\n    }\n}\n","go","",[22,330,331,344,351,361,373,383,388,398,408,418,424,429,445,483,499,517,523,552,565,580,585,590,608,632,669,695,720,745,751,756,775,809,846,902,922,928,934,959,991,1024,1044,1049,1081,1127,1155,1160,1165,1170,1191,1204,1219,1224,1270,1285,1290],{"__ignoreMap":328},[332,333,336,340],"span",{"class":334,"line":335},"line",1,[332,337,339],{"class":338},"sMK4o","package",[332,341,343],{"class":342},"sBMFI"," main\n",[332,345,347],{"class":334,"line":346},2,[332,348,350],{"emptyLinePlaceholder":349},true,"\n",[332,352,354,358],{"class":334,"line":353},3,[332,355,357],{"class":356},"s7zQu","import",[332,359,360],{"class":338}," (\n",[332,362,364,367,370],{"class":334,"line":363},4,[332,365,366],{"class":338},"    \"",[332,368,369],{"class":342},"log",[332,371,372],{"class":338},"\"\n",[332,374,376,378,381],{"class":334,"line":375},5,[332,377,366],{"class":338},[332,379,380],{"class":342},"os",[332,382,372],{"class":338},[332,384,386],{"class":334,"line":385},6,[332,387,350],{"emptyLinePlaceholder":349},[332,389,391,393,396],{"class":334,"line":390},7,[332,392,366],{"class":338},[332,394,395],{"class":342},"github.com/gpdf-dev/gpdf",[332,397,372],{"class":338},[332,399,401,403,406],{"class":334,"line":400},8,[332,402,366],{"class":338},[332,404,405],{"class":342},"github.com/gpdf-dev/gpdf/document",[332,407,372],{"class":338},[332,409,411,413,416],{"class":334,"line":410},9,[332,412,366],{"class":338},[332,414,415],{"class":342},"github.com/gpdf-dev/gpdf/template",[332,417,372],{"class":338},[332,419,421],{"class":334,"line":420},10,[332,422,423],{"class":338},")\n",[332,425,427],{"class":334,"line":426},11,[332,428,350],{"emptyLinePlaceholder":349},[332,430,432,435,439,442],{"class":334,"line":431},12,[332,433,434],{"class":338},"func",[332,436,438],{"class":437},"s2Zo4"," main",[332,440,441],{"class":338},"()",[332,443,444],{"class":338}," {\n",[332,446,448,452,455,458,461,464,466,469,472,475,479,481],{"class":334,"line":447},13,[332,449,451],{"class":450},"sTEyZ","    regular",[332,453,454],{"class":338},",",[332,456,457],{"class":450}," err ",[332,459,460],{"class":338},":=",[332,462,463],{"class":450}," os",[332,465,42],{"class":338},[332,467,468],{"class":437},"ReadFile",[332,470,471],{"class":338},"(",[332,473,474],{"class":338},"\"",[332,476,478],{"class":477},"sfazB","NotoSansJP-Regular.ttf",[332,480,474],{"class":338},[332,482,423],{"class":338},[332,484,486,489,491,494,497],{"class":334,"line":485},14,[332,487,488],{"class":356},"    if",[332,490,457],{"class":450},[332,492,493],{"class":338},"!=",[332,495,496],{"class":338}," nil",[332,498,444],{"class":338},[332,500,502,505,507,510,512,515],{"class":334,"line":501},15,[332,503,504],{"class":450},"        log",[332,506,42],{"class":338},[332,508,509],{"class":437},"Fatal",[332,511,471],{"class":338},[332,513,514],{"class":450},"err",[332,516,423],{"class":338},[332,518,520],{"class":334,"line":519},16,[332,521,522],{"class":338},"    }\n",[332,524,526,529,531,533,535,537,539,541,543,545,548,550],{"class":334,"line":525},17,[332,527,528],{"class":450},"    bold",[332,530,454],{"class":338},[332,532,457],{"class":450},[332,534,460],{"class":338},[332,536,463],{"class":450},[332,538,42],{"class":338},[332,540,468],{"class":437},[332,542,471],{"class":338},[332,544,474],{"class":338},[332,546,547],{"class":477},"NotoSansJP-Bold.ttf",[332,549,474],{"class":338},[332,551,423],{"class":338},[332,553,555,557,559,561,563],{"class":334,"line":554},18,[332,556,488],{"class":356},[332,558,457],{"class":450},[332,560,493],{"class":338},[332,562,496],{"class":338},[332,564,444],{"class":338},[332,566,568,570,572,574,576,578],{"class":334,"line":567},19,[332,569,504],{"class":450},[332,571,42],{"class":338},[332,573,509],{"class":437},[332,575,471],{"class":338},[332,577,514],{"class":450},[332,579,423],{"class":338},[332,581,583],{"class":334,"line":582},20,[332,584,522],{"class":338},[332,586,588],{"class":334,"line":587},21,[332,589,350],{"emptyLinePlaceholder":349},[332,591,593,596,598,601,603,605],{"class":334,"line":592},22,[332,594,595],{"class":450},"    doc ",[332,597,460],{"class":338},[332,599,600],{"class":450}," gpdf",[332,602,42],{"class":338},[332,604,32],{"class":437},[332,606,607],{"class":338},"(\n",[332,609,611,614,616,619,621,624,626,629],{"class":334,"line":610},23,[332,612,613],{"class":450},"        gpdf",[332,615,42],{"class":338},[332,617,618],{"class":437},"WithPageSize",[332,620,471],{"class":338},[332,622,623],{"class":450},"document",[332,625,42],{"class":338},[332,627,628],{"class":450},"A4",[332,630,631],{"class":338},"),\n",[332,633,635,637,639,642,644,646,648,651,653,655,657,660,662,666],{"class":334,"line":634},24,[332,636,613],{"class":450},[332,638,42],{"class":338},[332,640,641],{"class":437},"WithMargins",[332,643,471],{"class":338},[332,645,623],{"class":450},[332,647,42],{"class":338},[332,649,650],{"class":437},"UniformEdges",[332,652,471],{"class":338},[332,654,623],{"class":450},[332,656,42],{"class":338},[332,658,659],{"class":437},"Mm",[332,661,471],{"class":338},[332,663,665],{"class":664},"sbssI","20",[332,667,668],{"class":338},"))),\n",[332,670,672,674,676,679,681,683,686,688,690,693],{"class":334,"line":671},25,[332,673,613],{"class":450},[332,675,42],{"class":338},[332,677,678],{"class":437},"WithFont",[332,680,471],{"class":338},[332,682,474],{"class":338},[332,684,685],{"class":477},"NotoSansJP",[332,687,474],{"class":338},[332,689,454],{"class":338},[332,691,692],{"class":450}," regular",[332,694,631],{"class":338},[332,696,698,700,702,704,706,708,711,713,715,718],{"class":334,"line":697},26,[332,699,613],{"class":450},[332,701,42],{"class":338},[332,703,678],{"class":437},[332,705,471],{"class":338},[332,707,474],{"class":338},[332,709,710],{"class":477},"NotoSansJP-Bold",[332,712,474],{"class":338},[332,714,454],{"class":338},[332,716,717],{"class":450}," bold",[332,719,631],{"class":338},[332,721,723,725,727,730,732,734,736,738,740,743],{"class":334,"line":722},27,[332,724,613],{"class":450},[332,726,42],{"class":338},[332,728,729],{"class":437},"WithDefaultFont",[332,731,471],{"class":338},[332,733,474],{"class":338},[332,735,685],{"class":477},[332,737,474],{"class":338},[332,739,454],{"class":338},[332,741,742],{"class":664}," 11",[332,744,631],{"class":338},[332,746,748],{"class":334,"line":747},28,[332,749,750],{"class":338},"    )\n",[332,752,754],{"class":334,"line":753},29,[332,755,350],{"emptyLinePlaceholder":349},[332,757,759,762,764,767,769,772],{"class":334,"line":758},30,[332,760,761],{"class":450},"    page ",[332,763,460],{"class":338},[332,765,766],{"class":450}," doc",[332,768,42],{"class":338},[332,770,771],{"class":437},"AddPage",[332,773,774],{"class":338},"()\n",[332,776,778,781,783,786,789,793,796,799,801,804,807],{"class":334,"line":777},31,[332,779,780],{"class":450},"    page",[332,782,42],{"class":338},[332,784,785],{"class":437},"AutoRow",[332,787,788],{"class":338},"(func(",[332,790,792],{"class":791},"sHdIc","r",[332,794,795],{"class":338}," *",[332,797,798],{"class":342},"template",[332,800,42],{"class":338},[332,802,803],{"class":342},"RowBuilder",[332,805,806],{"class":338},")",[332,808,444],{"class":338},[332,810,812,815,817,820,822,825,827,830,833,835,837,839,842,844],{"class":334,"line":811},32,[332,813,814],{"class":450},"        r",[332,816,42],{"class":338},[332,818,819],{"class":437},"Col",[332,821,471],{"class":338},[332,823,824],{"class":664},"12",[332,826,454],{"class":338},[332,828,829],{"class":338}," func(",[332,831,832],{"class":791},"c",[332,834,795],{"class":338},[332,836,798],{"class":342},[332,838,42],{"class":338},[332,840,841],{"class":342},"ColBuilder",[332,843,806],{"class":338},[332,845,444],{"class":338},[332,847,849,852,854,857,859,861,864,866,868,871,873,876,878,880,882,884,887,889,891,894,896,899],{"class":334,"line":848},33,[332,850,851],{"class":450},"            c",[332,853,42],{"class":338},[332,855,856],{"class":437},"Text",[332,858,471],{"class":338},[332,860,474],{"class":338},[332,862,863],{"class":477},"請求書",[332,865,474],{"class":338},[332,867,454],{"class":338},[332,869,870],{"class":450}," template",[332,872,42],{"class":338},[332,874,875],{"class":437},"FontFamily",[332,877,471],{"class":338},[332,879,474],{"class":338},[332,881,710],{"class":477},[332,883,474],{"class":338},[332,885,886],{"class":338},"),",[332,888,870],{"class":450},[332,890,42],{"class":338},[332,892,893],{"class":437},"FontSize",[332,895,471],{"class":338},[332,897,898],{"class":664},"22",[332,900,901],{"class":338},"))\n",[332,903,905,907,909,911,913,915,918,920],{"class":334,"line":904},34,[332,906,851],{"class":450},[332,908,42],{"class":338},[332,910,856],{"class":437},[332,912,471],{"class":338},[332,914,474],{"class":338},[332,916,917],{"class":477},"2026 年 4 月 16 日",[332,919,474],{"class":338},[332,921,423],{"class":338},[332,923,925],{"class":334,"line":924},35,[332,926,927],{"class":338},"        })\n",[332,929,931],{"class":334,"line":930},36,[332,932,933],{"class":338},"    })\n",[332,935,937,939,941,943,945,947,949,951,953,955,957],{"class":334,"line":936},37,[332,938,780],{"class":450},[332,940,42],{"class":338},[332,942,785],{"class":437},[332,944,788],{"class":338},[332,946,792],{"class":791},[332,948,795],{"class":338},[332,950,798],{"class":342},[332,952,42],{"class":338},[332,954,803],{"class":342},[332,956,806],{"class":338},[332,958,444],{"class":338},[332,960,962,964,966,968,970,973,975,977,979,981,983,985,987,989],{"class":334,"line":961},38,[332,963,814],{"class":450},[332,965,42],{"class":338},[332,967,819],{"class":437},[332,969,471],{"class":338},[332,971,972],{"class":664},"7",[332,974,454],{"class":338},[332,976,829],{"class":338},[332,978,832],{"class":791},[332,980,795],{"class":338},[332,982,798],{"class":342},[332,984,42],{"class":338},[332,986,841],{"class":342},[332,988,806],{"class":338},[332,990,444],{"class":338},[332,992,994,996,998,1000,1002,1004,1007,1009,1011,1013,1015,1017,1019,1022],{"class":334,"line":993},39,[332,995,851],{"class":450},[332,997,42],{"class":338},[332,999,856],{"class":437},[332,1001,471],{"class":338},[332,1003,474],{"class":338},[332,1005,1006],{"class":477},"株式会社 ABC 御中",[332,1008,474],{"class":338},[332,1010,454],{"class":338},[332,1012,870],{"class":450},[332,1014,42],{"class":338},[332,1016,893],{"class":437},[332,1018,471],{"class":338},[332,1020,1021],{"class":664},"13",[332,1023,901],{"class":338},[332,1025,1027,1029,1031,1033,1035,1037,1040,1042],{"class":334,"line":1026},40,[332,1028,851],{"class":450},[332,1030,42],{"class":338},[332,1032,856],{"class":437},[332,1034,471],{"class":338},[332,1036,474],{"class":338},[332,1038,1039],{"class":477},"〒 100-0001 東京都千代田区千代田 1-1",[332,1041,474],{"class":338},[332,1043,423],{"class":338},[332,1045,1047],{"class":334,"line":1046},41,[332,1048,927],{"class":338},[332,1050,1052,1054,1056,1058,1060,1063,1065,1067,1069,1071,1073,1075,1077,1079],{"class":334,"line":1051},42,[332,1053,814],{"class":450},[332,1055,42],{"class":338},[332,1057,819],{"class":437},[332,1059,471],{"class":338},[332,1061,1062],{"class":664},"5",[332,1064,454],{"class":338},[332,1066,829],{"class":338},[332,1068,832],{"class":791},[332,1070,795],{"class":338},[332,1072,798],{"class":342},[332,1074,42],{"class":338},[332,1076,841],{"class":342},[332,1078,806],{"class":338},[332,1080,444],{"class":338},[332,1082,1084,1086,1088,1090,1092,1094,1097,1099,1101,1103,1105,1107,1109,1111,1113,1115,1117,1119,1121,1124],{"class":334,"line":1083},43,[332,1085,851],{"class":450},[332,1087,42],{"class":338},[332,1089,856],{"class":437},[332,1091,471],{"class":338},[332,1093,474],{"class":338},[332,1095,1096],{"class":477},"合計 ¥ 128,000",[332,1098,474],{"class":338},[332,1100,454],{"class":338},[332,1102,870],{"class":450},[332,1104,42],{"class":338},[332,1106,875],{"class":437},[332,1108,471],{"class":338},[332,1110,474],{"class":338},[332,1112,710],{"class":477},[332,1114,474],{"class":338},[332,1116,886],{"class":338},[332,1118,870],{"class":450},[332,1120,42],{"class":338},[332,1122,1123],{"class":437},"AlignRight",[332,1125,1126],{"class":338},"())\n",[332,1128,1130,1132,1134,1136,1138,1140,1143,1145,1147,1149,1151,1153],{"class":334,"line":1129},44,[332,1131,851],{"class":450},[332,1133,42],{"class":338},[332,1135,856],{"class":437},[332,1137,471],{"class":338},[332,1139,474],{"class":338},[332,1141,1142],{"class":477},"支払期限: 2026-05-31",[332,1144,474],{"class":338},[332,1146,454],{"class":338},[332,1148,870],{"class":450},[332,1150,42],{"class":338},[332,1152,1123],{"class":437},[332,1154,1126],{"class":338},[332,1156,1158],{"class":334,"line":1157},45,[332,1159,927],{"class":338},[332,1161,1163],{"class":334,"line":1162},46,[332,1164,933],{"class":338},[332,1166,1168],{"class":334,"line":1167},47,[332,1169,350],{"emptyLinePlaceholder":349},[332,1171,1173,1176,1178,1180,1182,1184,1186,1189],{"class":334,"line":1172},48,[332,1174,1175],{"class":450},"    data",[332,1177,454],{"class":338},[332,1179,457],{"class":450},[332,1181,460],{"class":338},[332,1183,766],{"class":450},[332,1185,42],{"class":338},[332,1187,1188],{"class":437},"Generate",[332,1190,774],{"class":338},[332,1192,1194,1196,1198,1200,1202],{"class":334,"line":1193},49,[332,1195,488],{"class":356},[332,1197,457],{"class":450},[332,1199,493],{"class":338},[332,1201,496],{"class":338},[332,1203,444],{"class":338},[332,1205,1207,1209,1211,1213,1215,1217],{"class":334,"line":1206},50,[332,1208,504],{"class":450},[332,1210,42],{"class":338},[332,1212,509],{"class":437},[332,1214,471],{"class":338},[332,1216,514],{"class":450},[332,1218,423],{"class":338},[332,1220,1222],{"class":334,"line":1221},51,[332,1223,522],{"class":338},[332,1225,1227,1229,1231,1233,1235,1237,1240,1242,1244,1247,1249,1251,1254,1256,1259,1262,1264,1266,1268],{"class":334,"line":1226},52,[332,1228,488],{"class":356},[332,1230,457],{"class":450},[332,1232,460],{"class":338},[332,1234,463],{"class":450},[332,1236,42],{"class":338},[332,1238,1239],{"class":437},"WriteFile",[332,1241,471],{"class":338},[332,1243,474],{"class":338},[332,1245,1246],{"class":477},"invoice-ja.pdf",[332,1248,474],{"class":338},[332,1250,454],{"class":338},[332,1252,1253],{"class":450}," data",[332,1255,454],{"class":338},[332,1257,1258],{"class":664}," 0o644",[332,1260,1261],{"class":338},");",[332,1263,457],{"class":450},[332,1265,493],{"class":338},[332,1267,496],{"class":338},[332,1269,444],{"class":338},[332,1271,1273,1275,1277,1279,1281,1283],{"class":334,"line":1272},53,[332,1274,504],{"class":450},[332,1276,42],{"class":338},[332,1278,509],{"class":437},[332,1280,471],{"class":338},[332,1282,514],{"class":450},[332,1284,423],{"class":338},[332,1286,1288],{"class":334,"line":1287},54,[332,1289,522],{"class":338},[332,1291,1293],{"class":334,"line":1292},55,[332,1294,1295],{"class":338},"}\n",[18,1297,1298],{},"눈여겨볼 점:",[1300,1301,1302,1320,1329,1346],"ul",{},[90,1303,1304,1312,1313,1315,1316,1319],{},[35,1305,1306,1308,1309,1311],{},[22,1307,55],{},"도, UTF-8 플래그도, ",[22,1310,856],{},"의 폰트 경로 인자도 없다",". ",[22,1314,28],{},"로 family를 등록하고 ",[22,1317,1318],{},"c.Text","는 Unicode를 쓸 뿐. 배선은 전부 내부.",[90,1321,1322,1325,1326,1328],{},[35,1323,1324],{},"굵기는 별도 family이지 플래그가 아니다",". 이것이 TTF의 배포 방식(Noto Sans JP Regular와 Bold는 ",[22,1327,119],{}," 테이블이 다른 별도 파일)과 부합한다. Gothic/Mincho, Source Han Sans JP Normal/Heavy도 같은 패턴.",[90,1330,1331,1312,1334,134,1337,1340,1341,42],{},[35,1332,1333],{},"레이아웃은 그리드, 커서가 아니다",[22,1335,1336],{},"r.Col(7, ...)",[22,1338,1339],{},"r.Col(5, ...)","는 합 12. 너비는 선언적이며 x 좌표는 계산하지 않는다. 자세한 건 ",[1342,1343,1345],"a",{"href":1344},"/ko/blog/12-column-grid","gpdf의 12칼럼 그리드 동작 방식",[90,1347,1348,1354],{},[35,1349,1350,1353],{},[22,1351,1352],{},"AlignRight()","는 로케일 독립",". 일본어 \"¥ 128,000\"도 \"$1,280.00\"와 같은 방식으로 우측 정렬. 텍스트 내용에 레이아웃 코드가 반응하지 않는다.",[18,1356,1357,1358,1360,1361,1363],{},"생성된 ",[22,1359,1246],{},"를 아무 리더로 연다. \"株式会社 ABC 御中\"을 선택해 에디터에 붙인다. 깨지지 않고 ",[22,1362,1006],{},"이 나온다. 이것이 ToUnicode CMap의 일이며 gpdf가 기본으로 쓴다.",[13,1365,1367],{"id":1366},"폰트-서브셋화-숨어-있는-크기-폭탄","폰트 서브셋화 — 숨어 있는 크기 폭탄",[18,1369,1370,1371,95,1374,42],{},"튜토리얼이 건너뛰기 쉬운 CJK-in-PDF의 ",[35,1372,1373],{},"가장 중요한 성질",[35,1375,1376],{},"서브셋 임베드",[18,1378,1379],{},"TTF는 글리프 아웃라인과 메타데이터 테이블의 모음이다. Noto Sans JP Regular는 약 17,500 글리프·5.1 MB. 일반 청구서가 사용하는 고유 일본어 문자는 60〜200. 문서마다 풀 임베드는 자릿수 단위의 낭비다.",[18,1381,1382,1383,1386],{},"서브셋 임베드는 ",[35,1384,1385],{},"사용한 글리프만 남긴다",". gpdf는 이를 자동으로 한다. 위 예제로 확인:",[323,1388,1392],{"className":1389,"code":1390,"language":1391,"meta":328,"style":328},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","$ ls -l invoice-ja.pdf\n-rw-r--r--  1 dev  staff  34892 Apr 16 10:12 invoice-ja.pdf\n","bash",[22,1393,1394,1408],{"__ignoreMap":328},[332,1395,1396,1399,1402,1405],{"class":334,"line":335},[332,1397,1398],{"class":342},"$",[332,1400,1401],{"class":477}," ls",[332,1403,1404],{"class":477}," -l",[332,1406,1407],{"class":477}," invoice-ja.pdf\n",[332,1409,1410,1413,1416,1419,1422,1425,1428,1431,1434],{"class":334,"line":346},[332,1411,1412],{"class":342},"-rw-r--r--",[332,1414,1415],{"class":664},"  1",[332,1417,1418],{"class":477}," dev",[332,1420,1421],{"class":477},"  staff",[332,1423,1424],{"class":664},"  34892",[332,1426,1427],{"class":477}," Apr",[332,1429,1430],{"class":664}," 16",[332,1432,1433],{"class":477}," 10:12",[332,1435,1407],{"class":477},[18,1437,1438,1439,1441,1442,1445,1446,1449],{},"34 KB. 비교: 같은 문서를 ",[22,1440,137],{}," + ",[22,1443,1444],{},"AddUTF8Font(\"NotoSansJP\", \"NotoSansJP-Regular.ttf\", true)"," (세 번째 인자는 UTF-8 플래그) 로 생성하면 ",[35,1447,1448],{},"4.9 MB",". 입력도 출력 텍스트도 같은데 파일은 143배 크다. 원인은 fpdf 경로가 emit 시점에 서브셋하지 않고 폰트 테이블 전체를 임베드하기 때문.",[18,1451,1452],{},"운영 영향:",[1300,1454,1455,1465,1471],{},[90,1456,1457,1460,1461,1464],{},[35,1458,1459],{},"초당 10건 청구서 생성"," (일반적인 SaaS 규모) 에서 서브셋 차이는 ",[35,1462,1463],{},"0.3 MB/s vs 43 MB/s","의 대역폭 차이. 로드밸런서가 여기에 의견이 있다.",[90,1466,1467,1470],{},[35,1468,1469],{},"콜드 스토리지 비용은 PDF 크기에 선형",". 아카이브 500만 건 × 5 MB = 25 TB. × 30 KB = 150 GB. 오브젝트 스토리지 요금은 월간 네 자리 대 두 자리의 차이.",[90,1472,1473,1476],{},[35,1474,1475],{},"이메일 첨부","는 제공사별 10〜25 MB 상한. 5 MB 일본어 청구서 + 다른 첨부 + MIME 인코딩이면 상한에 쉽게 닿는다.",[18,1478,1479,1480,120,1483,120,1486,120,1489,1492],{},"gpdf는 렌더 시점에 서브셋한다. 켜는 플래그는 없다. 어떤 글리프가 출력에 들어갔는지는 로컬 검증 도구로 볼 수 있지만 요점은: ",[22,1481,1482],{},"株",[22,1484,1485],{},"式",[22,1487,1488],{},"会",[22,1490,1491],{},"社","를 썼다면 그 네 글리프가 출력에 실리고 나머지 17,496은 실리지 않는다.",[13,1494,1496],{"id":1495},"혼용-조판-같은-줄의-漢字-かな-ascii","혼용 조판 — 같은 줄의 漢字 + かな + ASCII",[18,1498,1499],{},"일본어 텍스트가 단독으로 나오는 일은 드물다. 실무의 한 줄은 이렇다:",[323,1501,1506],{"className":1502,"code":1504,"language":1505},[1503],"language-text","API の P95 レイテンシは 50 ms 未満です。\n","text",[22,1507,1504],{"__ignoreMap":328},[18,1509,1510],{},"다섯 스크립트 공존: 로마자 (ASCII Latin), 가타카나, 히라가나, 한자 (Han), 숫자. 소박한 구현은 ASCII 부분에 잘못된 폰트를 얹어, 비례 일본어 옆에 고정폭 \"API\"가 나란히 서서 시각이 깨진다.",[18,1512,1513,1514,1517,1518,1521,1522,1525],{},"gpdf의 기본 동작은 ",[35,1515,1516],{},"등록된 family로 모든 코드포인트를 그린다",". Noto Sans JP가 기본이면 ",[22,1519,1520],{},"API","도 ",[22,1523,1524],{},"50 ms","도 Noto Sans JP의 라틴 글리프로 그려진다 — Noto는 이를 제공한다 (대부분의 일본어 슈퍼패밀리가 그렇다). 결과는 단일 서체처럼 보이고 실제로 단일 서체다.",[18,1527,1528,1529,1532,1533,1535],{},"family를 ",[35,1530,1531],{},"의도적으로 섞고 싶다면"," (ASCII는 condensed sans, 일본어는 Noto Sans JP) 둘 다 등록하고 ",[22,1534,1318],{}," 단위로 덮어쓴다:",[323,1537,1539],{"className":325,"code":1538,"language":327,"meta":328,"style":328},"c.Text(\"API の P95 レイテンシは 50 ms 未満です。\",\n    template.FontFamily(\"NotoSansJP\"))\nc.Text(\"API latency (P95) is under 50 ms.\",\n    template.FontFamily(\"InterVariable\"))\n",[22,1540,1541,1561,1580,1599],{"__ignoreMap":328},[332,1542,1543,1545,1547,1549,1551,1553,1556,1558],{"class":334,"line":335},[332,1544,832],{"class":450},[332,1546,42],{"class":338},[332,1548,856],{"class":437},[332,1550,471],{"class":338},[332,1552,474],{"class":338},[332,1554,1555],{"class":477},"API の P95 レイテンシは 50 ms 未満です。",[332,1557,474],{"class":338},[332,1559,1560],{"class":338},",\n",[332,1562,1563,1566,1568,1570,1572,1574,1576,1578],{"class":334,"line":346},[332,1564,1565],{"class":450},"    template",[332,1567,42],{"class":338},[332,1569,875],{"class":437},[332,1571,471],{"class":338},[332,1573,474],{"class":338},[332,1575,685],{"class":477},[332,1577,474],{"class":338},[332,1579,901],{"class":338},[332,1581,1582,1584,1586,1588,1590,1592,1595,1597],{"class":334,"line":353},[332,1583,832],{"class":450},[332,1585,42],{"class":338},[332,1587,856],{"class":437},[332,1589,471],{"class":338},[332,1591,474],{"class":338},[332,1593,1594],{"class":477},"API latency (P95) is under 50 ms.",[332,1596,474],{"class":338},[332,1598,1560],{"class":338},[332,1600,1601,1603,1605,1607,1609,1611,1614,1616],{"class":334,"line":363},[332,1602,1565],{"class":450},[332,1604,42],{"class":338},[332,1606,875],{"class":437},[332,1608,471],{"class":338},[332,1610,474],{"class":338},[332,1612,1613],{"class":477},"InterVariable",[332,1615,474],{"class":338},[332,1617,901],{"class":338},[18,1619,1620,1621,1623],{},"두 번의 ",[22,1622,1318],{},", 두 family, 스크립트 감지 로직은 코드에 없다. 한 줄 안에서 섞고 싶다면 (같은 문장 내 ASCII는 Inter, 일본어는 Noto) gpdf v1.2에서 지원 예정이며, 현재 우회는 스크립트 경계에서 수동 분할 후 가로 열로 배치하는 방식.",[13,1625,66],{"id":1626},"여전히-어려운-지점",[18,1628,1629],{},"Go의 일본어 PDF 이야기는 95% 풀려 있다. 남은 5%를 정직하게.",[18,1631,1632,1635,1636,1639],{},[35,1633,1634],{},"세로쓰기 (縦書き)는 아직 미지원."," gpdf v1.x는 가로만. 전통적인 일본어 조판 — 우→좌 열, 각 열은 위→아래, 적절한 글리프 회전과 문장부호 재배치 — 는 렌더 미세조정이 아니라 레이아웃 엔진의 깊은 변경이다. 설계안이 달린 오픈 이슈가 있고, 도착할 때 도착한다. 지금 꼭 세로가 필요하다면 (도서·정식 서한), 다른 도구 (Word, InDesign, pandoc + LuaLaTeX 파이프라인) 로 세로 PDF를 만들고 ",[22,1637,1638],{},"gpdf.Merge","로 병합하는 것이 현실해.",[18,1641,1642,1645,1646,1649],{},[35,1643,1644],{},"루비 (振り仮名)는 우회만 가능."," ",[22,1647,1648],{},"c.Ruby(\"漢字\", \"かんじ\")"," 같은 프리미티브는 없다. 어린이 콘텐츠나 언어 교재에서 필요하다면, 위 줄은 작은 가나, 아래 줄은 일반 크기 한자 정렬 — 두 행 구조로. 동작은 하지만 수동이고 가나 경계의 미세 자간 관리가 필요하다.",[18,1651,1652,1655,1656,120,1659,120,1662,1665,1666,1668,1669,1673],{},[35,1653,1654],{},"여러 CJK 폰트 간 자동 폴백은 없다."," 사용자 입력이 JP 한자와 CN 전용 자형 (",[22,1657,1658],{},"直",[22,1660,1661],{},"骨",[22,1663,1664],{},"角","은 JP/CN에서 미세하게 다르다) 을 섞는다면, 수동으로 쪼개 두 family를 쓰게 된다. 같은 ",[22,1667,1318],{}," 호출 내에서 family를 건너뛰는 자동 폴백은 아직. 실무에서 여기가 직접 박히는 문서는 많지 않지만, 필요하면 ",[1342,1670,1672],{"href":1671},"/ko/blog/","JP/CN/KR/EN 혼합 PDF"," (B-070 예정) 참고.",[18,1675,1676,1679,1680,1683,1684,1687],{},[35,1677,1678],{},"엄격 PDF/A-2b + 일본어."," gpdf는 ",[22,1681,1682],{},"gpdf.WithPDFA","로 PDF/A를 낼 수 있지만, 임베디드 글리프 메타데이터, CJK 런의 ",[22,1685,1686],{},"ActualText",", 태그된 구조 트리 등 엄격 요건은 CJK 케이스에서 아직 다듬는 중이다. 장기 보존 (일본의 전자장부보존법, 한국의 전자세금계산서 보관 등) 이라면 커밋 전에 veraPDF (무료) 등 서드파티로 검증하라.",[18,1689,1690],{},"어느 것도 일반 용도 (청구서·보고서·명세서·영수증·증명서) 의 블로커는 아니다. 적어두는 것은 누군가는 그중 하나에 프로덕션에서 부딪힐 것이기 때문이다 — \"로드맵에 있음\"보다 \"여기가 우회로\"가 유용하다.",[13,1692,1694],{"id":1693},"컴플라이언스-관점","컴플라이언스 관점",[18,1696,1697,1698,1701],{},"자주 언급되지 않는 맥락 하나: ",[35,1699,1700],{},"2026년의 일본어 PDF 생성은 단순한 조판 문제가 아니다",". 두 규제 축이 이를 컴플라이언스 대화로 밀어넣는다.",[18,1703,1704,1707,1708,1711],{},[35,1705,1706],{},"적격청구서 (適格請求書 인보이스) 제도","는 청구서에 특정 필드 (등록 사업자 번호, 적용 세율, 세액 내역) 와 변조 방지 보관을 요구한다. PDF가 사실상의 기본 포맷이고, \"변조 방지\"는 ",[35,1709,1710],{},"PDF 전자서명"," — 엄격 모드에서는 PAdES-B-LT — 에 매핑된다.",[18,1713,1714,1717,1718,42],{},[35,1715,1716],{},"전자장부보존법"," (2024 개정) 은 전자로 수령한 청구서의 보관 의무를 확장했다. 아카이브 PDF는 일정 무결성 요건을 만족해야 한다. 사실상 목표 포맷은 ",[35,1719,1720],{},"PDF/A-2b 또는 PDF/A-3b",[18,1722,1723,1724,1727,1728,1731,1732,1734],{},"둘 다 ",[35,1725,1726],{},"PDF 네이티브 기능"," — 서명, 장기 검증, PDF/A 임베디드 메타데이터 — 에 기댄다. 헤드리스 브라우저 경유 HTML→PDF는 어느 쪽도 깔끔히 만족하지 못한다. Chromium PDF 출력은 PDF/A가 아니고 단일 단계로 전자서명을 임베드하지도 못한다. 네이티브 Go 스택 (gpdf + ",[22,1729,1730],{},"gpdf/signature","의 PAdES + ",[22,1733,1682],{},") 은 이 체인을 프로세스 이탈 없이 한 파이프라인으로 통과한다.",[18,1736,1737,1738,1741],{},"본문에서는 ",[35,1739,1740],{},"예고","에 그친다 — 서명과 PDF/A는 각자 히어로 한 편 분량이다 (백로그 B-067, B-068). 다만 오늘 일본어 PDF 스택을 고르는데 컴플라이언스가 눈에 들어온다면, 네이티브로 서명과 PDF/A를 낼 수 있는 스택을 고르라. \"지금 동작\"에서 \"감사 통과\"로의 이주세는 실재하며 뒤로 미룰수록 비싸다.",[13,1743,1745],{"id":1744},"faq","FAQ",[18,1747,1748,1751,1752,1755,1756,1759,1760,1763,1764,1767,1768,1771],{},[35,1749,1750],{},"서버나 컨테이너에 폰트를 설치해야 하나?","\n아니. gpdf는 TTF 바이트를 읽는다 — 시스템 폰트 캐시를 보지 않는다. ",[22,1753,1754],{},"os.ReadFile(\"NotoSansJP-Regular.ttf\")","나 ",[22,1757,1758],{},"//go:embed NotoSansJP-Regular.ttf","는 macOS / Linux / Windows, distroless 컨테이너, AWS Lambda에서 동일하게 동작한다. ",[22,1761,1762],{},"fontconfig"," 불필요, ",[22,1765,1766],{},"fc-cache -fv"," 불필요. gpdf가 ",[22,1769,1770],{},"FROM scratch"," 이미지에서 돌아가는 이유 중 하나.",[18,1773,1774,1777],{},[35,1775,1776],{},"Noto Sans JP와 Source Han Sans JP 중 어느 쪽?","\n같은 폰트, 두 이름. Adobe가 Source Han Sans JP로 발행한 것을 Google이 Noto Sans JP로 재포장한다. 글리프 커버리지 동일. 둘 다 SIL Open Font License — 법무 리뷰가 수월한 쪽을 고르면 된다. gpdf 예제가 Noto Sans JP를 기본으로 쓰는 것은 파일명이 기억하기 쉬워서.",[18,1779,1780,1783,1784,1787],{},[35,1781,1782],{},"游ゴシック (Yu Gothic) 이나 히라기노는?","\nOS 번들 상용 폰트. 배포 대상이 라이선스를 가졌다면 사용 가능 (Windows Server는 Yu Gothic 번들, macOS는 히라기노 번들) 이지만, TTF 파일의 확보와 컨테이너 빌드에서의 재배포 조건은 각자 확인 필요. 개방형 배포에는 ",[35,1785,1786],{},"Noto Sans JP 또는 IPAex Gothic"," (양쪽 모두 자유 재배포 가능) 권장.",[18,1789,1790,1797,1798,1801],{},[35,1791,1792,1793,1796],{},"PDF는 나오는데 ",[22,1794,1795],{},"Ctrl+F"," 검색이 안 된다","\n거의 확실히 ToUnicode CMap 이슈. gpdf는 기본으로 쓴다. gpdf에서 이 현상이라면 리더 이름을 붙여 이슈를 열어달라. gofpdf라면 UTF-8 플래그 활성화 ",[35,1799,1800],{},"+"," 리더가 CID 폰트를 지원하는지 확인 (구 버전 macOS Preview.app에 알려진 문제 있음). 대조군으로 Adobe Reader 또는 Chrome 사용.",[18,1803,1804,1807,1808,1811],{},[35,1805,1806],{},"폰트에 없는 JIS X 0213 문자는?","\n그릴 글리프가 없으니 나오지 않는다. 실용 답은 \"JIS X 0213을 커버하는 폰트 사용\". Noto Sans JP는 BMP 전역 + JIS X 0213 1수준을 커버한다. 희귀 이체자는 Hanazono Mincho (화원명조) 같은 말단 폴백. 어떤 폰트에도 없는 코드포인트는 gpdf가 Unicode 치환 문자 (U+FFFD) 를 낸다 — 무음의 두부가 아니라 ",[22,1809,1810],{},"�","가 보이므로 조사의 단서가 된다.",[18,1813,1814,1817,1818,1820],{},[35,1815,1816],{},"CJK는 ASCII보다 느린가?","\n살짝. gpdf의 \"complex CJK invoice\" 벤치는 Apple M1에서 133 µs, ASCII 4×10 테이블이 108 µs. 약 23% 오버헤드로 대부분 글리프 룩업과 서브셋 비용이다. 참고: 같은 CJK 벤치에서 ",[22,1819,137],{},"는 254 µs, Maroto v2는 10.4 ms. 일본어 렌더가 서비스 병목이 되는 일은 거의 없다.",[13,1822,1824],{"id":1823},"gpdf-사용해-보기","gpdf 사용해 보기",[18,1826,1827],{},"gpdf는 Go용 PDF 생성 라이브러리. MIT, 외부 의존 없음, 네이티브 CJK.",[323,1829,1831],{"className":1389,"code":1830,"language":1391,"meta":328,"style":328},"go get github.com/gpdf-dev/gpdf\n",[22,1832,1833],{"__ignoreMap":328},[332,1834,1835,1837,1840],{"class":334,"line":335},[332,1836,327],{"class":342},[332,1838,1839],{"class":477}," get",[332,1841,1842],{"class":477}," github.com/gpdf-dev/gpdf\n",[18,1844,1845,1851,1852],{},[1342,1846,1850],{"href":1847,"rel":1848},"https://github.com/gpdf-dev/gpdf",[1849],"nofollow","⭐ Star on GitHub"," · ",[1342,1853,1856],{"href":1854,"rel":1855},"https://gpdf.dev/ko/docs/quickstart",[1849],"문서 읽기",[13,1858,1860],{"id":1859},"이어-읽을-글","이어 읽을 글",[1300,1862,1863,1870,1877,1882],{},[90,1864,1865,1869],{},[1342,1866,1868],{"href":1867},"/ko/blog/embed-japanese-font","gpdf에 일본어 폰트를 임베드하려면?"," — 배경 없는 3행 레시피",[90,1871,1872,1876],{},[1342,1873,1875],{"href":1874},"/ko/blog/noto-sans-jp-with-gpdf","gpdf에서 Noto Sans JP 쓰기"," — Regular / Bold / Medium 웨이트 설정",[90,1878,1879,1881],{},[1342,1880,1345],{"href":1344}," — 커서 계산을 대체하는 레이아웃 관용구",[90,1883,1884,1888],{},[1342,1885,1887],{"href":1886},"/ko/blog/go-pdf-fpdf-archived","go-pdf/fpdf도 아카이브. 2026년의 Go PDF 스택"," — 2026 판도 전체",[1890,1891,1892],"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 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 .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":328,"searchDepth":346,"depth":346,"links":1894},[1895,1896,1897,1898,1899,1900,1901,1902,1903,1904,1905,1906],{"id":15,"depth":346,"text":16},{"id":45,"depth":346,"text":46},{"id":73,"depth":346,"text":74},{"id":155,"depth":346,"text":156},{"id":310,"depth":346,"text":311},{"id":1366,"depth":346,"text":1367},{"id":1495,"depth":346,"text":1496},{"id":1626,"depth":346,"text":66},{"id":1693,"depth":346,"text":1694},{"id":1744,"depth":346,"text":1745},{"id":1823,"depth":346,"text":1824},{"id":1859,"depth":346,"text":1860},"2026-04-16","Go에서 일본어 PDF를 생성하는 완전한 순서. CGO 없이, Chromium 없이, 두부 글자 없이. 폰트·서브셋·혼용 조판까지.",false,"md",{"name":1912,"totalTime":1913,"tools":1914,"steps":1917},"Go에서 TrueType 서브셋 임베딩된 일본어 PDF 생성하기","PT20M",[1915,1916],"Go 1.22+","NotoSansJP-Regular.ttf 및 NotoSansJP-Bold.ttf (또는 임의의 일본어 지원 TTF 쌍)",[1918,1921,1924,1927,1930,1933],{"name":1919,"text":1920},"gpdf 설치 및 폰트 준비","go get github.com/gpdf-dev/gpdf를 실행. Google Fonts에서 Noto Sans JP Regular와 Bold를 내려받아 main.go 옆에 둔다. CGO도, OS 폰트 설정도 필요 없다.",{"name":1922,"text":1923},"기동 시 TTF 바이트를 읽어들이기","os.ReadFile로 두 TTF 파일을 []byte로 읽는다. 바이너리에 묻고 싶다면 //go:embed도 가능.",{"name":1925,"text":1926},"문서 구성 시 폰트 등록","gpdf.WithFont(\"NotoSansJP\", regular)과 gpdf.WithFont(\"NotoSansJP-Bold\", bold)을 gpdf.NewDocument에 넘긴다. family 이름은 임의 식별자 — 이후 참조할 핸들에 불과하다.",{"name":1928,"text":1929},"일본어 폰트를 기본으로 설정","gpdf.WithDefaultFont(\"NotoSansJP\", 11)을 추가. 이후의 c.Text는 FontFamily 옵션 없이 일본어 폰트를 사용한다.",{"name":1931,"text":1932},"c.Text로 문서 트리를 조립","page.AutoRow 블록 안에서 r.Col(span, fn)을 호출하고 c.Text(\"こんにちは、世界。\")를 쓴다. 굵기와 크기는 메서드가 아니라 template 옵션이다.",{"name":1934,"text":1935},"생성하고 동작 확인","doc.Generate()로 []byte를 받아 os.WriteFile로 저장. PDF를 열어 텍스트를 선택해 에디터에 붙여넣으면 — ToUnicode CMap 덕분에 복사·붙여넣기가 정확히 동작한다.",null,{},"/ko/blog/japanese-pdf-in-go",{"title":5,"description":1908},"ko/blog/007.japanese-pdf-in-go",[1942,1943,1944],"tutorial","cjk","troubleshooting","uW2Khc9HlItLbXpkwE4500UyNrvr0zIo6xJx8VjxID0",1776529266870]