[{"data":1,"prerenderedAt":1942},["ShallowReactive",2],{"blog-ja-japanese-pdf-in-go":3},{"id":4,"title":5,"author":6,"body":9,"date":1903,"description":1904,"draft":1905,"extension":1906,"howTo":1907,"image":1932,"meta":1933,"navigation":348,"path":1934,"seo":1935,"stem":1936,"tags":1937,"updated":1932,"__hash__":1941},"blogJa/ja/blog/007.japanese-pdf-in-go.md","Go で日本語 PDF を作る決定版ガイド (2026)",{"name":7,"url":8},"gpdf team","https://gpdf.dev",{"type":10,"value":11,"toc":1889},"minimark",[12,17,43,46,49,56,67,70,74,85,128,143,153,157,160,289,292,298,308,311,321,1296,1299,1354,1363,1367,1376,1379,1386,1435,1449,1452,1476,1493,1497,1500,1508,1511,1526,1536,1618,1624,1626,1629,1639,1648,1672,1686,1689,1693,1700,1710,1719,1733,1740,1744,1769,1775,1785,1799,1809,1818,1822,1825,1840,1854,1857,1885],[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",{},"こんにちは"," と書いたら豆腐 □□□□□ が 5 つ並んだ、という症状の直し方はリライトではなくセットアップ 2 行。TTF を読んで ",[22,27,28],{},"gpdf.WithFont"," を ",[22,31,32],{},"NewDocument"," に渡し、あとは日本語を書く。",[35,36,37],"strong",{},"gpdf はグリフテーブルを自動的にサブセット化する","ので、出力には実際に使った文字のグリフだけが載る — 5 MB のフルフォントではなく 30 KB 前後。この記事はその全景図: なぜ Go で日本語 PDF は妙に難しかったのか、2026 年の現実的な選択肢 4 つ、動くコード、フォントサブセット化の内部、混植の実務、そして",[35,40,41],{},"まだ解けていない部分","。",[13,44,45],{"id":45},"なぜこの記事を書くのか",[18,47,48],{},"Go で日本語 PDF を吐くのは本来 5 分の仕事だ。多くのチームではそれが 1 日半かかっている。",[18,50,51,52,55],{},"よくあるのはこういう流れ: ",[22,53,54],{},"AddUTF8Font"," を呼び出してみる → 出力 PDF には空の四角 (豆腐) が並ぶ → シニアエンジニアが半日使って、フォントパスなのかサブセットフラグなのか CMap なのか UTF-8 フラグなのか PDF ビューアなのかを絞り込む。夕方には Slack に「なぜ漢字がまだ壊れてるのか」というスレッドが立ち、翌日には誰もが後悔するヘルパー関数が 3 つ追加された PR が出ている。",[18,57,58,59,62,63,66],{},"根本原因はそのどれでもない。",[35,60,61],{},"Go で一番長く生きている PDF ライブラリが、2002 年の PHP と Latin-1 前提で設計された","ことと、それ以降に書かれた日本語チュートリアルのほぼ全てがその負債と戦ってきたこと。この記事は 2026 年版、ゼロからやる場合に本当に動くやり方と、",[35,64,65],{},"今なお難しい部分","を正直に書く。",[18,68,69],{},"本記事のコードは gpdf v1.x (2026-04 時点) で動作確認済み。ベンチ数値は Apple M1 + Go 1.25。",[13,71,73],{"id":72},"豆腐文字問題を-90-秒で","豆腐文字問題を 90 秒で",[18,75,76,77,80,81,84],{},"PDF は Unicode を知らない。PDF が知っているのは ",[35,78,79],{},"グリフ ID"," — フォントに埋め込まれたグリフテーブルへの整数インデックス。",[22,82,83],{},"\"こんにちは\""," を PDF に書くには、誰かが以下を全部やる必要がある:",[86,87,88,99,105,111],"ol",{},[89,90,91,94,95,98],"li",{},[35,92,93],{},"TTF を解析"," して、各コードポイントに対応するグリフ ID を ",[22,96,97],{},"cmap"," サブテーブルから引く。",[89,100,101,104],{},[35,102,103],{},"ToUnicode CMap を書き出す"," — ユーザーがコピー・検索したときに、グリフからテキストへ戻せるように。",[89,106,107,110],{},[35,108,109],{},"サブセット化","。Noto Sans JP の 2 万グリフを全部埋め込まない。",[89,112,113,116,117,120,121,120,124,127],{},[35,114,115],{},"埋め込み"," — ",[22,118,119],{},"name"," / ",[22,122,123],{},"OS/2",[22,125,126],{},"head"," テーブルとエンコーディングオブジェクトを正しく接続した形で。",[18,129,130,131,134,135,138,139,142],{},"このどれかが抜けるか間違うと、PDF ビューアはコードポイントに対応するグリフを見つけられず豆腐を描く。アーカイブ済みの ",[22,132,133],{},"jung-kurt/gofpdf"," と ",[22,136,137],{},"go-pdf/fpdf"," 系統は、これら全てを ",[35,140,141],{},"単一バイトフォント前提の内部モデル"," に後付けしてきた — 2002 年のオリジナル FPDF は Latin-1 しか知らなかったからだ。セットアップが脆いのも、出力がサブセットではなくフルフォントを埋め込みがちなのも、OS や PDF ビューアによって壊れ方が変わるのもそのせい。",[18,144,145,146,149,150,152],{},"gpdf は CJK を",[35,147,148],{},"ファーストクラスの用例","として扱う。TTF サブセッタはコアパッケージに同梱。ToUnicode CMap は自動で書かれる。単一バイトフォントの過去互換層がないので、",[22,151,54],{}," ダンスもない。",[13,154,156],{"id":155},"_2026-年の現実的な選択肢-4-つ","2026 年の現実的な選択肢 4 つ",[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 字 PDF のサイズ",[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 archived)",[194,200,201],{},"MIT",[194,203,204],{},"stdlib",[194,206,207,209],{},[22,208,54],{}," 後付け",[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],{},"stdlib のみ",[194,279,280],{},"ネイティブ、自動サブセット",[194,282,283],{},[35,284,285],{},"約 30 KB",[194,287,288],{},"純 Go。ビルダー API。ToUnicode CMap を自動出力。",[18,290,291],{},"2 点強調したい。",[18,293,294,297],{},[35,295,296],{},"「フル埋込」と「自動サブセット」の 160 倍の差は誤差ではない。"," 10 明細の EC 請求書 PDF で使う日本語グリフは、ユニークで多くても 120 字程度。毎回の請求書にフル Noto Sans JP (5.1 MB) を埋め込むなら、年末までに同じ 5 MB のグリフデータがオブジェクトストレージに 1,000 万回コピーされる。サブセット埋込なら、使ったグリフだけが乗る。",[18,299,300,303,304,307],{},[35,301,302],{},"「chromedp で動く」は事実だが、最も高価な答え","。すでにスクリーンショット用にヘッドレス Chrome の艦隊を運用しているチームなら、それに PDF を相乗りさせるのはアリ。そうでないチームが ",[35,305,306],{},"日本語を印字するためだけに"," Chromium を立てるのは、40 行の Go で解ける問題に対して過剰なインフラだ。",[13,309,310],{"id":310},"動く最短経路",[18,312,313,314,317,318,42],{},"まずこれを試す。完全形 — コピーして ",[22,315,316],{},"main.go"," で保存、TTF 2 本を隣に置いて ",[22,319,320],{},"go run main.go",[322,323,328],"pre",{"className":324,"code":325,"language":326,"meta":327,"style":327},"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,329,330,343,350,360,372,382,387,397,407,417,423,428,444,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":327},[331,332,335,339],"span",{"class":333,"line":334},"line",1,[331,336,338],{"class":337},"sMK4o","package",[331,340,342],{"class":341},"sBMFI"," main\n",[331,344,346],{"class":333,"line":345},2,[331,347,349],{"emptyLinePlaceholder":348},true,"\n",[331,351,353,357],{"class":333,"line":352},3,[331,354,356],{"class":355},"s7zQu","import",[331,358,359],{"class":337}," (\n",[331,361,363,366,369],{"class":333,"line":362},4,[331,364,365],{"class":337},"    \"",[331,367,368],{"class":341},"log",[331,370,371],{"class":337},"\"\n",[331,373,375,377,380],{"class":333,"line":374},5,[331,376,365],{"class":337},[331,378,379],{"class":341},"os",[331,381,371],{"class":337},[331,383,385],{"class":333,"line":384},6,[331,386,349],{"emptyLinePlaceholder":348},[331,388,390,392,395],{"class":333,"line":389},7,[331,391,365],{"class":337},[331,393,394],{"class":341},"github.com/gpdf-dev/gpdf",[331,396,371],{"class":337},[331,398,400,402,405],{"class":333,"line":399},8,[331,401,365],{"class":337},[331,403,404],{"class":341},"github.com/gpdf-dev/gpdf/document",[331,406,371],{"class":337},[331,408,410,412,415],{"class":333,"line":409},9,[331,411,365],{"class":337},[331,413,414],{"class":341},"github.com/gpdf-dev/gpdf/template",[331,416,371],{"class":337},[331,418,420],{"class":333,"line":419},10,[331,421,422],{"class":337},")\n",[331,424,426],{"class":333,"line":425},11,[331,427,349],{"emptyLinePlaceholder":348},[331,429,431,434,438,441],{"class":333,"line":430},12,[331,432,433],{"class":337},"func",[331,435,437],{"class":436},"s2Zo4"," main",[331,439,440],{"class":337},"()",[331,442,443],{"class":337}," {\n",[331,445,447,451,454,457,460,463,466,469,472,475,479,481],{"class":333,"line":446},13,[331,448,450],{"class":449},"sTEyZ","    regular",[331,452,453],{"class":337},",",[331,455,456],{"class":449}," err ",[331,458,459],{"class":337},":=",[331,461,462],{"class":449}," os",[331,464,465],{"class":337},".",[331,467,468],{"class":436},"ReadFile",[331,470,471],{"class":337},"(",[331,473,474],{"class":337},"\"",[331,476,478],{"class":477},"sfazB","NotoSansJP-Regular.ttf",[331,480,474],{"class":337},[331,482,422],{"class":337},[331,484,486,489,491,494,497],{"class":333,"line":485},14,[331,487,488],{"class":355},"    if",[331,490,456],{"class":449},[331,492,493],{"class":337},"!=",[331,495,496],{"class":337}," nil",[331,498,443],{"class":337},[331,500,502,505,507,510,512,515],{"class":333,"line":501},15,[331,503,504],{"class":449},"        log",[331,506,465],{"class":337},[331,508,509],{"class":436},"Fatal",[331,511,471],{"class":337},[331,513,514],{"class":449},"err",[331,516,422],{"class":337},[331,518,520],{"class":333,"line":519},16,[331,521,522],{"class":337},"    }\n",[331,524,526,529,531,533,535,537,539,541,543,545,548,550],{"class":333,"line":525},17,[331,527,528],{"class":449},"    bold",[331,530,453],{"class":337},[331,532,456],{"class":449},[331,534,459],{"class":337},[331,536,462],{"class":449},[331,538,465],{"class":337},[331,540,468],{"class":436},[331,542,471],{"class":337},[331,544,474],{"class":337},[331,546,547],{"class":477},"NotoSansJP-Bold.ttf",[331,549,474],{"class":337},[331,551,422],{"class":337},[331,553,555,557,559,561,563],{"class":333,"line":554},18,[331,556,488],{"class":355},[331,558,456],{"class":449},[331,560,493],{"class":337},[331,562,496],{"class":337},[331,564,443],{"class":337},[331,566,568,570,572,574,576,578],{"class":333,"line":567},19,[331,569,504],{"class":449},[331,571,465],{"class":337},[331,573,509],{"class":436},[331,575,471],{"class":337},[331,577,514],{"class":449},[331,579,422],{"class":337},[331,581,583],{"class":333,"line":582},20,[331,584,522],{"class":337},[331,586,588],{"class":333,"line":587},21,[331,589,349],{"emptyLinePlaceholder":348},[331,591,593,596,598,601,603,605],{"class":333,"line":592},22,[331,594,595],{"class":449},"    doc ",[331,597,459],{"class":337},[331,599,600],{"class":449}," gpdf",[331,602,465],{"class":337},[331,604,32],{"class":436},[331,606,607],{"class":337},"(\n",[331,609,611,614,616,619,621,624,626,629],{"class":333,"line":610},23,[331,612,613],{"class":449},"        gpdf",[331,615,465],{"class":337},[331,617,618],{"class":436},"WithPageSize",[331,620,471],{"class":337},[331,622,623],{"class":449},"document",[331,625,465],{"class":337},[331,627,628],{"class":449},"A4",[331,630,631],{"class":337},"),\n",[331,633,635,637,639,642,644,646,648,651,653,655,657,660,662,666],{"class":333,"line":634},24,[331,636,613],{"class":449},[331,638,465],{"class":337},[331,640,641],{"class":436},"WithMargins",[331,643,471],{"class":337},[331,645,623],{"class":449},[331,647,465],{"class":337},[331,649,650],{"class":436},"UniformEdges",[331,652,471],{"class":337},[331,654,623],{"class":449},[331,656,465],{"class":337},[331,658,659],{"class":436},"Mm",[331,661,471],{"class":337},[331,663,665],{"class":664},"sbssI","20",[331,667,668],{"class":337},"))),\n",[331,670,672,674,676,679,681,683,686,688,690,693],{"class":333,"line":671},25,[331,673,613],{"class":449},[331,675,465],{"class":337},[331,677,678],{"class":436},"WithFont",[331,680,471],{"class":337},[331,682,474],{"class":337},[331,684,685],{"class":477},"NotoSansJP",[331,687,474],{"class":337},[331,689,453],{"class":337},[331,691,692],{"class":449}," regular",[331,694,631],{"class":337},[331,696,698,700,702,704,706,708,711,713,715,718],{"class":333,"line":697},26,[331,699,613],{"class":449},[331,701,465],{"class":337},[331,703,678],{"class":436},[331,705,471],{"class":337},[331,707,474],{"class":337},[331,709,710],{"class":477},"NotoSansJP-Bold",[331,712,474],{"class":337},[331,714,453],{"class":337},[331,716,717],{"class":449}," bold",[331,719,631],{"class":337},[331,721,723,725,727,730,732,734,736,738,740,743],{"class":333,"line":722},27,[331,724,613],{"class":449},[331,726,465],{"class":337},[331,728,729],{"class":436},"WithDefaultFont",[331,731,471],{"class":337},[331,733,474],{"class":337},[331,735,685],{"class":477},[331,737,474],{"class":337},[331,739,453],{"class":337},[331,741,742],{"class":664}," 11",[331,744,631],{"class":337},[331,746,748],{"class":333,"line":747},28,[331,749,750],{"class":337},"    )\n",[331,752,754],{"class":333,"line":753},29,[331,755,349],{"emptyLinePlaceholder":348},[331,757,759,762,764,767,769,772],{"class":333,"line":758},30,[331,760,761],{"class":449},"    page ",[331,763,459],{"class":337},[331,765,766],{"class":449}," doc",[331,768,465],{"class":337},[331,770,771],{"class":436},"AddPage",[331,773,774],{"class":337},"()\n",[331,776,778,781,783,786,789,793,796,799,801,804,807],{"class":333,"line":777},31,[331,779,780],{"class":449},"    page",[331,782,465],{"class":337},[331,784,785],{"class":436},"AutoRow",[331,787,788],{"class":337},"(func(",[331,790,792],{"class":791},"sHdIc","r",[331,794,795],{"class":337}," *",[331,797,798],{"class":341},"template",[331,800,465],{"class":337},[331,802,803],{"class":341},"RowBuilder",[331,805,806],{"class":337},")",[331,808,443],{"class":337},[331,810,812,815,817,820,822,825,827,830,833,835,837,839,842,844],{"class":333,"line":811},32,[331,813,814],{"class":449},"        r",[331,816,465],{"class":337},[331,818,819],{"class":436},"Col",[331,821,471],{"class":337},[331,823,824],{"class":664},"12",[331,826,453],{"class":337},[331,828,829],{"class":337}," func(",[331,831,832],{"class":791},"c",[331,834,795],{"class":337},[331,836,798],{"class":341},[331,838,465],{"class":337},[331,840,841],{"class":341},"ColBuilder",[331,843,806],{"class":337},[331,845,443],{"class":337},[331,847,849,852,854,857,859,861,864,866,868,871,873,876,878,880,882,884,887,889,891,894,896,899],{"class":333,"line":848},33,[331,850,851],{"class":449},"            c",[331,853,465],{"class":337},[331,855,856],{"class":436},"Text",[331,858,471],{"class":337},[331,860,474],{"class":337},[331,862,863],{"class":477},"請求書",[331,865,474],{"class":337},[331,867,453],{"class":337},[331,869,870],{"class":449}," template",[331,872,465],{"class":337},[331,874,875],{"class":436},"FontFamily",[331,877,471],{"class":337},[331,879,474],{"class":337},[331,881,710],{"class":477},[331,883,474],{"class":337},[331,885,886],{"class":337},"),",[331,888,870],{"class":449},[331,890,465],{"class":337},[331,892,893],{"class":436},"FontSize",[331,895,471],{"class":337},[331,897,898],{"class":664},"22",[331,900,901],{"class":337},"))\n",[331,903,905,907,909,911,913,915,918,920],{"class":333,"line":904},34,[331,906,851],{"class":449},[331,908,465],{"class":337},[331,910,856],{"class":436},[331,912,471],{"class":337},[331,914,474],{"class":337},[331,916,917],{"class":477},"2026 年 4 月 16 日",[331,919,474],{"class":337},[331,921,422],{"class":337},[331,923,925],{"class":333,"line":924},35,[331,926,927],{"class":337},"        })\n",[331,929,931],{"class":333,"line":930},36,[331,932,933],{"class":337},"    })\n",[331,935,937,939,941,943,945,947,949,951,953,955,957],{"class":333,"line":936},37,[331,938,780],{"class":449},[331,940,465],{"class":337},[331,942,785],{"class":436},[331,944,788],{"class":337},[331,946,792],{"class":791},[331,948,795],{"class":337},[331,950,798],{"class":341},[331,952,465],{"class":337},[331,954,803],{"class":341},[331,956,806],{"class":337},[331,958,443],{"class":337},[331,960,962,964,966,968,970,973,975,977,979,981,983,985,987,989],{"class":333,"line":961},38,[331,963,814],{"class":449},[331,965,465],{"class":337},[331,967,819],{"class":436},[331,969,471],{"class":337},[331,971,972],{"class":664},"7",[331,974,453],{"class":337},[331,976,829],{"class":337},[331,978,832],{"class":791},[331,980,795],{"class":337},[331,982,798],{"class":341},[331,984,465],{"class":337},[331,986,841],{"class":341},[331,988,806],{"class":337},[331,990,443],{"class":337},[331,992,994,996,998,1000,1002,1004,1007,1009,1011,1013,1015,1017,1019,1022],{"class":333,"line":993},39,[331,995,851],{"class":449},[331,997,465],{"class":337},[331,999,856],{"class":436},[331,1001,471],{"class":337},[331,1003,474],{"class":337},[331,1005,1006],{"class":477},"株式会社 ABC 御中",[331,1008,474],{"class":337},[331,1010,453],{"class":337},[331,1012,870],{"class":449},[331,1014,465],{"class":337},[331,1016,893],{"class":436},[331,1018,471],{"class":337},[331,1020,1021],{"class":664},"13",[331,1023,901],{"class":337},[331,1025,1027,1029,1031,1033,1035,1037,1040,1042],{"class":333,"line":1026},40,[331,1028,851],{"class":449},[331,1030,465],{"class":337},[331,1032,856],{"class":436},[331,1034,471],{"class":337},[331,1036,474],{"class":337},[331,1038,1039],{"class":477},"〒 100-0001 東京都千代田区千代田 1-1",[331,1041,474],{"class":337},[331,1043,422],{"class":337},[331,1045,1047],{"class":333,"line":1046},41,[331,1048,927],{"class":337},[331,1050,1052,1054,1056,1058,1060,1063,1065,1067,1069,1071,1073,1075,1077,1079],{"class":333,"line":1051},42,[331,1053,814],{"class":449},[331,1055,465],{"class":337},[331,1057,819],{"class":436},[331,1059,471],{"class":337},[331,1061,1062],{"class":664},"5",[331,1064,453],{"class":337},[331,1066,829],{"class":337},[331,1068,832],{"class":791},[331,1070,795],{"class":337},[331,1072,798],{"class":341},[331,1074,465],{"class":337},[331,1076,841],{"class":341},[331,1078,806],{"class":337},[331,1080,443],{"class":337},[331,1082,1084,1086,1088,1090,1092,1094,1097,1099,1101,1103,1105,1107,1109,1111,1113,1115,1117,1119,1121,1124],{"class":333,"line":1083},43,[331,1085,851],{"class":449},[331,1087,465],{"class":337},[331,1089,856],{"class":436},[331,1091,471],{"class":337},[331,1093,474],{"class":337},[331,1095,1096],{"class":477},"合計 ¥ 128,000",[331,1098,474],{"class":337},[331,1100,453],{"class":337},[331,1102,870],{"class":449},[331,1104,465],{"class":337},[331,1106,875],{"class":436},[331,1108,471],{"class":337},[331,1110,474],{"class":337},[331,1112,710],{"class":477},[331,1114,474],{"class":337},[331,1116,886],{"class":337},[331,1118,870],{"class":449},[331,1120,465],{"class":337},[331,1122,1123],{"class":436},"AlignRight",[331,1125,1126],{"class":337},"())\n",[331,1128,1130,1132,1134,1136,1138,1140,1143,1145,1147,1149,1151,1153],{"class":333,"line":1129},44,[331,1131,851],{"class":449},[331,1133,465],{"class":337},[331,1135,856],{"class":436},[331,1137,471],{"class":337},[331,1139,474],{"class":337},[331,1141,1142],{"class":477},"支払期限: 2026-05-31",[331,1144,474],{"class":337},[331,1146,453],{"class":337},[331,1148,870],{"class":449},[331,1150,465],{"class":337},[331,1152,1123],{"class":436},[331,1154,1126],{"class":337},[331,1156,1158],{"class":333,"line":1157},45,[331,1159,927],{"class":337},[331,1161,1163],{"class":333,"line":1162},46,[331,1164,933],{"class":337},[331,1166,1168],{"class":333,"line":1167},47,[331,1169,349],{"emptyLinePlaceholder":348},[331,1171,1173,1176,1178,1180,1182,1184,1186,1189],{"class":333,"line":1172},48,[331,1174,1175],{"class":449},"    data",[331,1177,453],{"class":337},[331,1179,456],{"class":449},[331,1181,459],{"class":337},[331,1183,766],{"class":449},[331,1185,465],{"class":337},[331,1187,1188],{"class":436},"Generate",[331,1190,774],{"class":337},[331,1192,1194,1196,1198,1200,1202],{"class":333,"line":1193},49,[331,1195,488],{"class":355},[331,1197,456],{"class":449},[331,1199,493],{"class":337},[331,1201,496],{"class":337},[331,1203,443],{"class":337},[331,1205,1207,1209,1211,1213,1215,1217],{"class":333,"line":1206},50,[331,1208,504],{"class":449},[331,1210,465],{"class":337},[331,1212,509],{"class":436},[331,1214,471],{"class":337},[331,1216,514],{"class":449},[331,1218,422],{"class":337},[331,1220,1222],{"class":333,"line":1221},51,[331,1223,522],{"class":337},[331,1225,1227,1229,1231,1233,1235,1237,1240,1242,1244,1247,1249,1251,1254,1256,1259,1262,1264,1266,1268],{"class":333,"line":1226},52,[331,1228,488],{"class":355},[331,1230,456],{"class":449},[331,1232,459],{"class":337},[331,1234,462],{"class":449},[331,1236,465],{"class":337},[331,1238,1239],{"class":436},"WriteFile",[331,1241,471],{"class":337},[331,1243,474],{"class":337},[331,1245,1246],{"class":477},"invoice-ja.pdf",[331,1248,474],{"class":337},[331,1250,453],{"class":337},[331,1252,1253],{"class":449}," data",[331,1255,453],{"class":337},[331,1257,1258],{"class":664}," 0o644",[331,1260,1261],{"class":337},");",[331,1263,456],{"class":449},[331,1265,493],{"class":337},[331,1267,496],{"class":337},[331,1269,443],{"class":337},[331,1271,1273,1275,1277,1279,1281,1283],{"class":333,"line":1272},53,[331,1274,504],{"class":449},[331,1276,465],{"class":337},[331,1278,509],{"class":436},[331,1280,471],{"class":337},[331,1282,514],{"class":449},[331,1284,422],{"class":337},[331,1286,1288],{"class":333,"line":1287},54,[331,1289,522],{"class":337},[331,1291,1293],{"class":333,"line":1292},55,[331,1294,1295],{"class":337},"}\n",[18,1297,1298],{},"全部説明するより、目に留まってほしい点だけ:",[1300,1301,1302,1319,1328,1345],"ul",{},[89,1303,1304,42,1312,1314,1315,1318],{},[35,1305,1306,1308,1309,1311],{},[22,1307,54],{}," もなし、UTF-8 フラグもなし、",[22,1310,856],{}," にフォントパス引数もなし",[22,1313,28],{}," で family を登録、",[22,1316,1317],{},"c.Text"," は Unicode を書くだけ。配線は内部で完結。",[89,1320,1321,1324,1325,1327],{},[35,1322,1323],{},"太字は別 family、フラグではない","。これは TTF の流通形態 (Noto Sans JP Regular と Noto Sans JP Bold は ",[22,1326,119],{}," テーブルが別の独立ファイル) に合っている。ゴシックと明朝、Source Han Sans JP Normal と Heavy なども同じパターン。",[89,1329,1330,42,1333,134,1336,1339,1340,42],{},[35,1331,1332],{},"レイアウトはグリッド、カーソルではない",[22,1334,1335],{},"r.Col(7, ...)",[22,1337,1338],{},"r.Col(5, ...)"," は合計 12。幅は宣言的、x 座標は書かない。詳細は ",[1341,1342,1344],"a",{"href":1343},"/ja/blog/12-column-grid","gpdf の 12 カラムグリッドの仕組み",[89,1346,1347,1353],{},[35,1348,1349,1352],{},[22,1350,1351],{},"AlignRight()"," はロケール非依存","。「¥ 128,000」は「$1,280.00」と同じ書き方で右寄せできる。テキストの中身でレイアウトコードが変わらない。",[18,1355,1356,1357,1359,1360,1362],{},"できた ",[22,1358,1246],{}," を任意のビューアで開き、「株式会社 ABC 御中」を選択してテキストエディタに貼る。",[22,1361,1006],{}," と出る — 文字化けしない。これが ToUnicode CMap の仕事で、gpdf は既定で書き出す。",[13,1364,1366],{"id":1365},"フォントサブセット化-隠れたサイズ爆弾","フォントサブセット化 — 隠れたサイズ爆弾",[18,1368,1369,1370,116,1373,42],{},"チュートリアルが飛ばしがちな、CJK in PDF の",[35,1371,1372],{},"最重要性質",[35,1374,1375],{},"サブセット埋込",[18,1377,1378],{},"TTF はグリフアウトラインとメタデータテーブルの集合。Noto Sans JP Regular は約 17,500 グリフを含み 5.1 MB。典型的な請求書が使う日本語ユニーク文字は 60〜200 字。毎文書にフル埋込は桁単位の浪費だ。",[18,1380,1381,1382,1385],{},"サブセット埋込は",[35,1383,1384],{},"使ったグリフだけを残す","。gpdf はこれを自動でやる。上のコード例を動かして確認:",[322,1387,1391],{"className":1388,"code":1389,"language":1390,"meta":327,"style":327},"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,1392,1393,1407],{"__ignoreMap":327},[331,1394,1395,1398,1401,1404],{"class":333,"line":334},[331,1396,1397],{"class":341},"$",[331,1399,1400],{"class":477}," ls",[331,1402,1403],{"class":477}," -l",[331,1405,1406],{"class":477}," invoice-ja.pdf\n",[331,1408,1409,1412,1415,1418,1421,1424,1427,1430,1433],{"class":333,"line":345},[331,1410,1411],{"class":341},"-rw-r--r--",[331,1413,1414],{"class":664},"  1",[331,1416,1417],{"class":477}," dev",[331,1419,1420],{"class":477},"  staff",[331,1422,1423],{"class":664},"  34892",[331,1425,1426],{"class":477}," Apr",[331,1428,1429],{"class":664}," 16",[331,1431,1432],{"class":477}," 10:12",[331,1434,1406],{"class":477},[18,1436,1437,1438,1440,1441,1444,1445,1448],{},"34 KB。比較: 同じ文書を ",[22,1439,137],{}," + ",[22,1442,1443],{},"AddUTF8Font(\"NotoSansJP\", \"NotoSansJP-Regular.ttf\", true)"," (第 3 引数は UTF-8 フラグ) で吐くと ",[35,1446,1447],{},"4.9 MB","。入力も出力文字も同じ、ファイルサイズは 143 倍。原因は fpdf の経路が emit 時点でサブセット化せずフォントテーブル全体を埋め込むため。",[18,1450,1451],{},"実運用への影響を具体的に:",[1300,1453,1454,1464,1470],{},[89,1455,1456,1459,1460,1463],{},[35,1457,1458],{},"秒 10 件の請求書生成"," (SaaS でよくある規模) で、サブセット差は ",[35,1461,1462],{},"0.3 MB/s と 43 MB/s"," の帯域差。ロードバランサはこれに意見を持っている。",[89,1465,1466,1469],{},[35,1467,1468],{},"コールドストレージ費用は PDF サイズに線形","。アーカイブ 500 万件 × 5 MB = 25 TB。× 30 KB = 150 GB。オブジェクトストレージ料金は月額で 4 桁 vs 2 桁のレベルで変わる。",[89,1471,1472,1475],{},[35,1473,1474],{},"メール添付"," は各社 10〜25 MB 上限。5 MB の日本語請求書 + 他の添付 + MIME エンコーディングで、普通にその天井にぶつかる。",[18,1477,1478,1479,1482,1483,1482,1486,1482,1489,1492],{},"gpdf はレンダリング時にサブセット化する。オンにするフラグはない。どのグリフが埋め込まれたかは gpdf の検証ツールで見られるが、要点はこう — ",[22,1480,1481],{},"株","・",[22,1484,1485],{},"式",[22,1487,1488],{},"会",[22,1490,1491],{},"社"," を使ったなら、その 4 グリフだけが出力に乗り、残り 17,496 は乗らない。",[13,1494,1496],{"id":1495},"混植-漢字-かな-ascii-を-1-行に","混植 — 漢字 + かな + ASCII を 1 行に",[18,1498,1499],{},"日本語テキストは単独で現れることは稀だ。実運用の 1 行はこういう形をしている:",[322,1501,1506],{"className":1502,"code":1504,"language":1505},[1503],"language-text","API の P95 レイテンシは 50 ms 未満です。\n","text",[22,1507,1504],{"__ignoreMap":327},[18,1509,1510],{},"5 スクリプトが混在: ローマ字 (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 の Latin グリフで描かれる — Noto はこれを提供している (日本語スーパーファミリーはだいたい持っている)。結果は単一書体に見える、実際単一書体だから。",[18,1527,1528,1529,1532,1533,1535],{},"family を",[35,1530,1531],{},"意図的に混ぜたい","場合 (ASCII は condensed サンセリフ、日本語は Noto Sans JP、など) は、両方登録して ",[22,1534,1317],{}," 単位で上書き:",[322,1537,1539],{"className":324,"code":1538,"language":326,"meta":327,"style":327},"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":327},[331,1542,1543,1545,1547,1549,1551,1553,1556,1558],{"class":333,"line":334},[331,1544,832],{"class":449},[331,1546,465],{"class":337},[331,1548,856],{"class":436},[331,1550,471],{"class":337},[331,1552,474],{"class":337},[331,1554,1555],{"class":477},"API の P95 レイテンシは 50 ms 未満です。",[331,1557,474],{"class":337},[331,1559,1560],{"class":337},",\n",[331,1562,1563,1566,1568,1570,1572,1574,1576,1578],{"class":333,"line":345},[331,1564,1565],{"class":449},"    template",[331,1567,465],{"class":337},[331,1569,875],{"class":436},[331,1571,471],{"class":337},[331,1573,474],{"class":337},[331,1575,685],{"class":477},[331,1577,474],{"class":337},[331,1579,901],{"class":337},[331,1581,1582,1584,1586,1588,1590,1592,1595,1597],{"class":333,"line":352},[331,1583,832],{"class":449},[331,1585,465],{"class":337},[331,1587,856],{"class":436},[331,1589,471],{"class":337},[331,1591,474],{"class":337},[331,1593,1594],{"class":477},"API latency (P95) is under 50 ms.",[331,1596,474],{"class":337},[331,1598,1560],{"class":337},[331,1600,1601,1603,1605,1607,1609,1611,1614,1616],{"class":333,"line":362},[331,1602,1565],{"class":449},[331,1604,465],{"class":337},[331,1606,875],{"class":436},[331,1608,471],{"class":337},[331,1610,474],{"class":337},[331,1612,1613],{"class":477},"InterVariable",[331,1615,474],{"class":337},[331,1617,901],{"class":337},[18,1619,1620,1621,1623],{},"2 回の ",[22,1622,1317],{},"、2 family、スクリプト判定ロジックは自分で書かない。1 行内で両方を混ぜたい (同じ文中で ASCII は Inter、日本語は Noto) なら、それは gpdf v1.2 で対応予定。今の回避策はスクリプト境界で手動分割し、横並びのカラム行でレイアウトする方法。",[13,1625,41],{"id":41},[18,1627,1628],{},"Go で日本語 PDF の話は 95% 解けている。残り 5% を正直に書く。",[18,1630,1631,1634,1635,1638],{},[35,1632,1633],{},"縦書きはまだ未対応","。gpdf v1.x は横書きのみ。伝統的な日本語組版 — 右から左へ列、列は上から下、グリフ回転と句読点配置の特殊処理 — は描画の微調整ではなくレイアウトエンジンの深い変更で、設計案のあるオープン issue になっている。着地したら着地する。今どうしても 縦書き が必要なら (書籍や公式往来)、別ツール (Word、InDesign、pandoc + LuaLaTeX パイプライン) で縦書き PDF を作ってから ",[22,1636,1637],{},"gpdf.Merge"," で連結するのが現実解。",[18,1640,1641,42,1644,1647],{},[35,1642,1643],{},"ルビ (振り仮名) は回避策のみ",[22,1645,1646],{},"c.Ruby(\"漢字\", \"かんじ\")"," のような基本機能はない。児童向けコンテンツや教材で必要なら、上段に小さなかな、下段に通常サイズの漢字を並べた 2 行構造で組む。動きはするが手作業で、カーニングも慎重にやる必要がある。",[18,1649,1650,1653,1654,1482,1657,1482,1660,1663,1664,1666,1667,1671],{},[35,1651,1652],{},"CJK フォント間のフォールバックは自動ではない","。ユーザー入力が JP の漢字と CN 専用字形 (",[22,1655,1656],{},"直",[22,1658,1659],{},"骨",[22,1661,1662],{},"角"," などは JP/CN で字形が微妙に違う) を混ぜるなら、手動で分割して 2 family を使う必要がある。同じ ",[22,1665,1317],{}," 内での自動フォールバックはまだ。実務でここが刺さる文書はかなり少ないが、必要なら ",[1341,1668,1670],{"href":1669},"/ja/blog/","JP/CN/KR/EN 混在 PDF"," (B-070 予定) を参照。",[18,1673,1674,1677,1678,1681,1682,1685],{},[35,1675,1676],{},"PDF/A-2b 厳格モードで日本語","。gpdf は ",[22,1679,1680],{},"gpdf.WithPDFA"," で PDF/A を吐けるが、埋込グリフメタデータ・CJK ラン単位の ",[22,1683,1684],{},"ActualText","・タグ付き構造ツリーなど、厳密適合の要件は CJK ケースでまだ詰めている最中。電子帳簿保存法で長期保存する PDF なら、コミット前に veraPDF (無料) などサードパーティで検証する。",[18,1687,1688],{},"どれも一般的な用途 (請求書・レポート・明細書・領収書・証明書) のブロッカーではない。ただ本番で刺さる人がいずれいるから書いておく — 「ロードマップにあります」より「これが回避策です」のほうが誠実なので。",[13,1690,1692],{"id":1691},"コンプライアンス-日本市場の文脈","コンプライアンス: 日本市場の文脈",[18,1694,1695,1696,1699],{},"もう一つ、普段あまり書かれない話。",[35,1697,1698],{},"2026 年の日本における PDF 生成は、もはや単なるタイポグラフィ問題ではない","。2 つの制度がこれをコンプライアンス会話の中に押し込んでいる。",[18,1701,1702,1705,1706,1709],{},[35,1703,1704],{},"適格請求書 (インボイス制度)"," は、請求書に所定の項目 (登録番号・適用税率・税額内訳) と改ざん耐性のある保存を要求する。PDF が事実上のデフォルト形式であり、改ざん耐性は ",[35,1707,1708],{},"PDF デジタル署名"," — 厳密には PAdES-B-LT — に写像される。",[18,1711,1712,1715,1716,42],{},[35,1713,1714],{},"電子帳簿保存法"," (2024 改正) は、電子で受領した請求書の保存義務を拡張した。アーカイブ PDF は所定の完全性要件を満たす必要がある。デファクト目標形式は ",[35,1717,1718],{},"PDF/A-2b または PDF/A-3b",[18,1720,1721,1722,1725,1726,1729,1730,1732],{},"両方とも ",[35,1723,1724],{},"PDF ネイティブ機能"," に寄っている — 署名、長期検証、PDF/A 埋込メタデータ。ヘッドレスブラウザ経由の HTML→PDF はどちらの要件もきれいには満たさない: Chromium の PDF 出力は PDF/A 適合ではないし、単一ステップでのデジタル署名埋込もできない。ネイティブ Go スタック (gpdf + ",[22,1727,1728],{},"gpdf/signature"," による PAdES + ",[22,1731,1680],{},") はこのチェーン全体をプロセスから出ずに 1 本のパイプラインで通せる。",[18,1734,1735,1736,1739],{},"これは本稿では ",[35,1737,1738],{},"予告にとどめる"," — 署名と PDF/A はそれぞれヒーロー記事 1 本に値する (バックログの B-067 と B-068)。ただ、日本市場で日本語 PDF スタックを今選ぶなら、署名と PDF/A をネイティブで吐けるスタックを選んでおけ。「とりあえず動く」から「監査を通る」への移行税は本物で、後から払うと高い。",[13,1741,1743],{"id":1742},"faq","FAQ",[18,1745,1746,1749,1750,1521,1753,1756,1757,1760,1761,1764,1765,1768],{},[35,1747,1748],{},"サーバーやコンテナにフォントをインストールする必要は?","\nない。gpdf は TTF バイトを読む — システムフォントキャッシュを見ない。",[22,1751,1752],{},"os.ReadFile(\"NotoSansJP-Regular.ttf\")",[22,1754,1755],{},"//go:embed NotoSansJP-Regular.ttf"," は macOS / Linux / Windows、distroless コンテナ、AWS Lambda で等価に動く。",[22,1758,1759],{},"fontconfig"," も ",[22,1762,1763],{},"fc-cache -fv"," も不要。",[22,1766,1767],{},"FROM scratch"," イメージで動くのはこの性質のおかげ。",[18,1770,1771,1774],{},[35,1772,1773],{},"Noto Sans JP と Source Han Sans JP はどっちがいい?","\n同じフォント、2 ブランド。Adobe が Source Han Sans JP として公開したものを Google が Noto Sans JP として再配布している。グリフカバレッジは同一。両方 SIL Open Font License — 法務レビュー結果でどちらの経路が通しやすいかで選ぶ。gpdf のサンプルは覚えやすいという理由で Noto Sans JP を既定にしている。",[18,1776,1777,1780,1781,1784],{},[35,1778,1779],{},"游ゴシック (Yu Gothic) やヒラギノは?","\nOS 同梱の商用フォント。デプロイ先がライセンスを持つ環境なら使える (Windows Server は Yu Gothic 同梱、macOS はヒラギノ同梱) が、TTF ファイル自体の入手と、コンテナビルドでの再配布条件は各自確認が必要。オープンなデプロイには ",[35,1782,1783],{},"Noto Sans JP または IPAex ゴシック"," (どちらも自由再配布可) を勧める。",[18,1786,1787,1794,1795,1798],{},[35,1788,1789,1790,1793],{},"PDF は出るが ",[22,1791,1792],{},"Ctrl+F"," で検索が効かない","\nほぼ確実に ToUnicode CMap 問題。gpdf は既定で書き出すので、gpdf でこれが起きているならビューア名付きで issue を立ててほしい。gofpdf でこれが起きているなら、UTF-8 フラグの有効化 ",[35,1796,1797],{},"+"," ビューアが CID フォントをサポートしている確認が必要 (旧バージョンの macOS Preview.app で既知の問題あり)。Adobe Reader か Chrome を対照実験にする。",[18,1800,1801,1804,1805,1808],{},[35,1802,1803],{},"フォントにない JIS X 0213 の文字を出したい","\n出ない — 描くグリフがない。実用解は「JIS X 0213 をカバーするフォントを使う」。Noto Sans JP は BMP 全域 + JIS X 0213 第 1 水準をカバーしている。稀な異体字には最終フォールバックとして花園明朝 (Hanazono Mincho) がある。どのフォントにも無いコードポイントは、gpdf は Unicode 置換文字 (U+FFFD) を出す — 無言の豆腐ではなく ",[22,1806,1807],{},"�"," が出るので、調べるきっかけになる。",[18,1810,1811,1814,1815,1817],{},[35,1812,1813],{},"CJK は ASCII より遅い?","\nわずかに。gpdf の「complex CJK invoice」ベンチは Apple M1 で 133 µs、ASCII 4×10 テーブルが 108 µs。約 23% の上乗せで、主にグリフ検索とサブセット化のコスト。参考まで、同じ CJK ベンチで ",[22,1816,137],{}," は 254 µs、Maroto v2 は 10.4 ms。日本語描画がサービスのボトルネックになることはまずない。",[13,1819,1821],{"id":1820},"gpdf-を使ってみる","gpdf を使ってみる",[18,1823,1824],{},"gpdf は Go の PDF 生成ライブラリ。MIT、ゼロ依存、CJK ネイティブ。",[322,1826,1828],{"className":1388,"code":1827,"language":1390,"meta":327,"style":327},"go get github.com/gpdf-dev/gpdf\n",[22,1829,1830],{"__ignoreMap":327},[331,1831,1832,1834,1837],{"class":333,"line":334},[331,1833,326],{"class":341},[331,1835,1836],{"class":477}," get",[331,1838,1839],{"class":477}," github.com/gpdf-dev/gpdf\n",[18,1841,1842,1848,1849],{},[1341,1843,1847],{"href":1844,"rel":1845},"https://github.com/gpdf-dev/gpdf",[1846],"nofollow","⭐ Star on GitHub"," · ",[1341,1850,1853],{"href":1851,"rel":1852},"https://gpdf.dev/ja/docs/quickstart",[1846],"ドキュメント",[13,1855,1856],{"id":1856},"次に読む",[1300,1858,1859,1866,1873,1878],{},[89,1860,1861,1865],{},[1341,1862,1864],{"href":1863},"/ja/blog/embed-japanese-font","gpdf で日本語フォントを埋め込むには?"," — 背景抜きの 3 行レシピ",[89,1867,1868,1872],{},[1341,1869,1871],{"href":1870},"/ja/blog/noto-sans-jp-with-gpdf","Noto Sans JP を gpdf で使うには?"," — Regular / Bold / Medium ウェイト設定",[89,1874,1875,1877],{},[1341,1876,1344],{"href":1343}," — カーソル計算を置き換えるレイアウト idiom",[89,1879,1880,1884],{},[1341,1881,1883],{"href":1882},"/ja/blog/go-pdf-fpdf-archived","go-pdf/fpdf もアーカイブ。Go の PDF は gpdf に移る"," — 2026 年の勢力図全体",[1886,1887,1888],"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":327,"searchDepth":345,"depth":345,"links":1890},[1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902],{"id":15,"depth":345,"text":16},{"id":45,"depth":345,"text":45},{"id":72,"depth":345,"text":73},{"id":155,"depth":345,"text":156},{"id":310,"depth":345,"text":310},{"id":1365,"depth":345,"text":1366},{"id":1495,"depth":345,"text":1496},{"id":41,"depth":345,"text":41},{"id":1691,"depth":345,"text":1692},{"id":1742,"depth":345,"text":1743},{"id":1820,"depth":345,"text":1821},{"id":1856,"depth":345,"text":1856},"2026-04-16","Go で日本語 PDF を吐く完全手順。CGO なし、Chromium なし、豆腐文字なし。フォント・サブセット・混植・縦書きの実務まで。",false,"md",{"name":1908,"totalTime":1909,"tools":1910,"steps":1913},"Go で TrueType サブセット埋め込みされた日本語 PDF を生成する","PT20M",[1911,1912],"Go 1.22+","NotoSansJP-Regular.ttf と NotoSansJP-Bold.ttf (または任意の日本語対応 TTF ペア)",[1914,1917,1920,1923,1926,1929],{"name":1915,"text":1916},"gpdf を導入してフォントを用意する","go get github.com/gpdf-dev/gpdf を実行。Google Fonts から Noto Sans JP の Regular と Bold をダウンロードして main.go の隣に置く。CGO 不要、OS のフォント設定も不要。",{"name":1918,"text":1919},"起動時に TTF バイトを読み込む","両方の TTF ファイルを os.ReadFile で []byte に読み込む。バイナリに埋め込みたいなら //go:embed でも可。",{"name":1921,"text":1922},"ドキュメント構築時にフォントを登録する","gpdf.WithFont(\"NotoSansJP\", regular) と gpdf.WithFont(\"NotoSansJP-Bold\", bold) を gpdf.NewDocument に渡す。family 名は任意の識別子 — 後で参照するハンドルにすぎない。",{"name":1924,"text":1925},"日本語フォントを既定に設定する","gpdf.WithDefaultFont(\"NotoSansJP\", 11) を追加。以降の c.Text は明示的な FontFamily オプションなしで日本語フォントを使う。",{"name":1927,"text":1928},"c.Text でドキュメント木を組み立てる","page.AutoRow ブロックの中で r.Col(span, fn) を呼び、c.Text(\"こんにちは、世界。\") と書く。太字やサイズはメソッドではなく template オプション。",{"name":1930,"text":1931},"生成して動作確認する","doc.Generate() で []byte を受け取り os.WriteFile で保存。PDF を開いて文字列を選択しテキストエディタに貼り付ける — ToUnicode CMap が書き出されているのでコピー & ペーストが正しく動く。",null,{},"/ja/blog/japanese-pdf-in-go",{"title":5,"description":1904},"ja/blog/007.japanese-pdf-in-go",[1938,1939,1940],"tutorial","cjk","troubleshooting","FGDEPOzv0AU64mFP2rOIx9Us40iil_t5uRy0Qdm_Bo0",1776529264476]