[{"data":1,"prerenderedAt":1368},["ShallowReactive",2],{"blog-ja-scale-image-fit-column":3},{"id":4,"title":5,"author":6,"body":10,"date":1337,"description":1338,"draft":1339,"extension":1340,"howTo":1341,"image":1359,"meta":1360,"navigation":203,"path":1361,"seo":1362,"stem":1363,"tags":1364,"updated":1359,"__hash__":1367},"blogJa/ja/blog/020.scale-image-fit-column.md","gpdf で画像を等比でカラム幅に収めるには?",{"name":7,"url":8,"avatar":9},"野田大貴","https://nadai.dev/ja/about","https://nadai.dev/og-default.png",{"type":11,"value":12,"toc":1326},"minimark",[13,17,34,37,73,84,95,179,182,185,867,878,882,885,966,981,984,987,1063,1069,1075,1160,1163,1166,1173,1176,1182,1250,1255,1258,1286,1290,1293,1310,1322],[14,15,16],"h2",{"id":16},"質問を言い換えると",[18,19,20,21,28,29,33],"p",{},"ロゴ・グラフ・スクショなど、たとえば 1200×800 の PNG を ",[22,23,27],"a",{"href":24,"rel":25},"https://github.com/gpdf-dev/gpdf",[26],"nofollow","gpdf"," のカラムに入れたい。アスペクト比の計算は ",[30,31,32],"strong",{},"手でやりたくない","。横長に潰したくない。隣のカラムにはみ出させたくない。等比で縮小して綺麗に収める、それだけがしたい。",[14,35,36],{"id":36},"即答",[38,39,44],"pre",{"className":40,"code":41,"language":42,"meta":43,"style":43},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","c.Image(imgBytes)\n","go","",[45,46,47],"code",{"__ignoreMap":43},[48,49,52,56,60,64,67,70],"span",{"class":50,"line":51},"line",1,[48,53,55],{"class":54},"sTEyZ","c",[48,57,59],{"class":58},"sMK4o",".",[48,61,63],{"class":62},"s2Zo4","Image",[48,65,66],{"class":58},"(",[48,68,69],{"class":54},"imgBytes",[48,71,72],{"class":58},")\n",[18,74,75,76,79,80,83],{},"ほとんどのケースはこれで終わり。",[45,77,78],{},"c.Image"," のデフォルトは ",[45,81,82],{},"FitContain"," で、アスペクト比を保ったままカラム幅に縮小される。元画像がカラムより小さければそのままの寸法で描画される。",[18,85,86,87,90,91,94],{},"カラム幅より小さい上限を付けたいなら ",[45,88,89],{},"template.FitWidth"," か ",[45,92,93],{},"template.FitHeight"," を追加する:",[38,96,98],{"className":40,"code":97,"language":42,"meta":43,"style":43},"c.Image(imgBytes, template.FitWidth(document.Mm(40)))\nc.Image(imgBytes, template.FitHeight(document.Mm(20)))\n",[45,99,100,142],{"__ignoreMap":43},[48,101,102,104,106,108,110,112,115,118,120,123,125,128,130,133,135,139],{"class":50,"line":51},[48,103,55],{"class":54},[48,105,59],{"class":58},[48,107,63],{"class":62},[48,109,66],{"class":58},[48,111,69],{"class":54},[48,113,114],{"class":58},",",[48,116,117],{"class":54}," template",[48,119,59],{"class":58},[48,121,122],{"class":62},"FitWidth",[48,124,66],{"class":58},[48,126,127],{"class":54},"document",[48,129,59],{"class":58},[48,131,132],{"class":62},"Mm",[48,134,66],{"class":58},[48,136,138],{"class":137},"sbssI","40",[48,140,141],{"class":58},")))\n",[48,143,145,147,149,151,153,155,157,159,161,164,166,168,170,172,174,177],{"class":50,"line":144},2,[48,146,55],{"class":54},[48,148,59],{"class":58},[48,150,63],{"class":62},[48,152,66],{"class":58},[48,154,69],{"class":54},[48,156,114],{"class":58},[48,158,117],{"class":54},[48,160,59],{"class":58},[48,162,163],{"class":62},"FitHeight",[48,165,66],{"class":58},[48,167,127],{"class":54},[48,169,59],{"class":58},[48,171,132],{"class":62},[48,173,66],{"class":58},[48,175,176],{"class":137},"20",[48,178,141],{"class":58},[18,180,181],{},"どちらもアスペクト比を維持する。指定するのは片方だけで、もう片方は gpdf が計算する。",[14,183,184],{"id":184},"動くサンプル",[38,186,188],{"className":40,"code":187,"language":42,"meta":43,"style":43},"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    logo, err := os.ReadFile(\"logo.png\")\n    if err != nil {\n        log.Fatal(err)\n    }\n    chart, err := os.ReadFile(\"chart.png\")\n    if err != nil {\n        log.Fatal(err)\n    }\n\n    doc := gpdf.NewDocument(\n        gpdf.WithPageSize(gpdf.A4),\n        gpdf.WithMargins(document.UniformEdges(document.Mm(20))),\n    )\n\n    page := doc.AddPage()\n\n    page.AutoRow(func(r *template.RowBuilder) {\n        // ロゴ用の狭いカラム。30mm に固定。\n        r.Col(3, func(c *template.ColBuilder) {\n            c.Image(logo, template.FitWidth(document.Mm(30)))\n        })\n        // グラフ用の広いカラム。デフォルトのまま使えるだけ使う。\n        r.Col(9, func(c *template.ColBuilder) {\n            c.Image(chart)\n        })\n    })\n\n    data, err := doc.Generate()\n    if err != nil {\n        log.Fatal(err)\n    }\n    if err := os.WriteFile(\"report.pdf\", data, 0o644); err != nil {\n        log.Fatal(err)\n    }\n}\n",[45,189,190,199,205,215,227,237,242,252,262,272,277,282,297,332,348,366,372,401,414,429,434,439,458,481,515,521,526,545,550,584,591,627,665,671,677,709,725,730,736,741,762,775,790,795,841,856,861],{"__ignoreMap":43},[48,191,192,195],{"class":50,"line":51},[48,193,194],{"class":58},"package",[48,196,198],{"class":197},"sBMFI"," main\n",[48,200,201],{"class":50,"line":144},[48,202,204],{"emptyLinePlaceholder":203},true,"\n",[48,206,208,212],{"class":50,"line":207},3,[48,209,211],{"class":210},"s7zQu","import",[48,213,214],{"class":58}," (\n",[48,216,218,221,224],{"class":50,"line":217},4,[48,219,220],{"class":58},"    \"",[48,222,223],{"class":197},"log",[48,225,226],{"class":58},"\"\n",[48,228,230,232,235],{"class":50,"line":229},5,[48,231,220],{"class":58},[48,233,234],{"class":197},"os",[48,236,226],{"class":58},[48,238,240],{"class":50,"line":239},6,[48,241,204],{"emptyLinePlaceholder":203},[48,243,245,247,250],{"class":50,"line":244},7,[48,246,220],{"class":58},[48,248,249],{"class":197},"github.com/gpdf-dev/gpdf",[48,251,226],{"class":58},[48,253,255,257,260],{"class":50,"line":254},8,[48,256,220],{"class":58},[48,258,259],{"class":197},"github.com/gpdf-dev/gpdf/document",[48,261,226],{"class":58},[48,263,265,267,270],{"class":50,"line":264},9,[48,266,220],{"class":58},[48,268,269],{"class":197},"github.com/gpdf-dev/gpdf/template",[48,271,226],{"class":58},[48,273,275],{"class":50,"line":274},10,[48,276,72],{"class":58},[48,278,280],{"class":50,"line":279},11,[48,281,204],{"emptyLinePlaceholder":203},[48,283,285,288,291,294],{"class":50,"line":284},12,[48,286,287],{"class":58},"func",[48,289,290],{"class":62}," main",[48,292,293],{"class":58},"()",[48,295,296],{"class":58}," {\n",[48,298,300,303,305,308,311,314,316,319,321,324,328,330],{"class":50,"line":299},13,[48,301,302],{"class":54},"    logo",[48,304,114],{"class":58},[48,306,307],{"class":54}," err ",[48,309,310],{"class":58},":=",[48,312,313],{"class":54}," os",[48,315,59],{"class":58},[48,317,318],{"class":62},"ReadFile",[48,320,66],{"class":58},[48,322,323],{"class":58},"\"",[48,325,327],{"class":326},"sfazB","logo.png",[48,329,323],{"class":58},[48,331,72],{"class":58},[48,333,335,338,340,343,346],{"class":50,"line":334},14,[48,336,337],{"class":210},"    if",[48,339,307],{"class":54},[48,341,342],{"class":58},"!=",[48,344,345],{"class":58}," nil",[48,347,296],{"class":58},[48,349,351,354,356,359,361,364],{"class":50,"line":350},15,[48,352,353],{"class":54},"        log",[48,355,59],{"class":58},[48,357,358],{"class":62},"Fatal",[48,360,66],{"class":58},[48,362,363],{"class":54},"err",[48,365,72],{"class":58},[48,367,369],{"class":50,"line":368},16,[48,370,371],{"class":58},"    }\n",[48,373,375,378,380,382,384,386,388,390,392,394,397,399],{"class":50,"line":374},17,[48,376,377],{"class":54},"    chart",[48,379,114],{"class":58},[48,381,307],{"class":54},[48,383,310],{"class":58},[48,385,313],{"class":54},[48,387,59],{"class":58},[48,389,318],{"class":62},[48,391,66],{"class":58},[48,393,323],{"class":58},[48,395,396],{"class":326},"chart.png",[48,398,323],{"class":58},[48,400,72],{"class":58},[48,402,404,406,408,410,412],{"class":50,"line":403},18,[48,405,337],{"class":210},[48,407,307],{"class":54},[48,409,342],{"class":58},[48,411,345],{"class":58},[48,413,296],{"class":58},[48,415,417,419,421,423,425,427],{"class":50,"line":416},19,[48,418,353],{"class":54},[48,420,59],{"class":58},[48,422,358],{"class":62},[48,424,66],{"class":58},[48,426,363],{"class":54},[48,428,72],{"class":58},[48,430,432],{"class":50,"line":431},20,[48,433,371],{"class":58},[48,435,437],{"class":50,"line":436},21,[48,438,204],{"emptyLinePlaceholder":203},[48,440,442,445,447,450,452,455],{"class":50,"line":441},22,[48,443,444],{"class":54},"    doc ",[48,446,310],{"class":58},[48,448,449],{"class":54}," gpdf",[48,451,59],{"class":58},[48,453,454],{"class":62},"NewDocument",[48,456,457],{"class":58},"(\n",[48,459,461,464,466,469,471,473,475,478],{"class":50,"line":460},23,[48,462,463],{"class":54},"        gpdf",[48,465,59],{"class":58},[48,467,468],{"class":62},"WithPageSize",[48,470,66],{"class":58},[48,472,27],{"class":54},[48,474,59],{"class":58},[48,476,477],{"class":54},"A4",[48,479,480],{"class":58},"),\n",[48,482,484,486,488,491,493,495,497,500,502,504,506,508,510,512],{"class":50,"line":483},24,[48,485,463],{"class":54},[48,487,59],{"class":58},[48,489,490],{"class":62},"WithMargins",[48,492,66],{"class":58},[48,494,127],{"class":54},[48,496,59],{"class":58},[48,498,499],{"class":62},"UniformEdges",[48,501,66],{"class":58},[48,503,127],{"class":54},[48,505,59],{"class":58},[48,507,132],{"class":62},[48,509,66],{"class":58},[48,511,176],{"class":137},[48,513,514],{"class":58},"))),\n",[48,516,518],{"class":50,"line":517},25,[48,519,520],{"class":58},"    )\n",[48,522,524],{"class":50,"line":523},26,[48,525,204],{"emptyLinePlaceholder":203},[48,527,529,532,534,537,539,542],{"class":50,"line":528},27,[48,530,531],{"class":54},"    page ",[48,533,310],{"class":58},[48,535,536],{"class":54}," doc",[48,538,59],{"class":58},[48,540,541],{"class":62},"AddPage",[48,543,544],{"class":58},"()\n",[48,546,548],{"class":50,"line":547},28,[48,549,204],{"emptyLinePlaceholder":203},[48,551,553,556,558,561,564,568,571,574,576,579,582],{"class":50,"line":552},29,[48,554,555],{"class":54},"    page",[48,557,59],{"class":58},[48,559,560],{"class":62},"AutoRow",[48,562,563],{"class":58},"(func(",[48,565,567],{"class":566},"sHdIc","r",[48,569,570],{"class":58}," *",[48,572,573],{"class":197},"template",[48,575,59],{"class":58},[48,577,578],{"class":197},"RowBuilder",[48,580,581],{"class":58},")",[48,583,296],{"class":58},[48,585,587],{"class":50,"line":586},30,[48,588,590],{"class":589},"sHwdD","        // ロゴ用の狭いカラム。30mm に固定。\n",[48,592,594,597,599,602,604,607,609,612,614,616,618,620,623,625],{"class":50,"line":593},31,[48,595,596],{"class":54},"        r",[48,598,59],{"class":58},[48,600,601],{"class":62},"Col",[48,603,66],{"class":58},[48,605,606],{"class":137},"3",[48,608,114],{"class":58},[48,610,611],{"class":58}," func(",[48,613,55],{"class":566},[48,615,570],{"class":58},[48,617,573],{"class":197},[48,619,59],{"class":58},[48,621,622],{"class":197},"ColBuilder",[48,624,581],{"class":58},[48,626,296],{"class":58},[48,628,630,633,635,637,639,642,644,646,648,650,652,654,656,658,660,663],{"class":50,"line":629},32,[48,631,632],{"class":54},"            c",[48,634,59],{"class":58},[48,636,63],{"class":62},[48,638,66],{"class":58},[48,640,641],{"class":54},"logo",[48,643,114],{"class":58},[48,645,117],{"class":54},[48,647,59],{"class":58},[48,649,122],{"class":62},[48,651,66],{"class":58},[48,653,127],{"class":54},[48,655,59],{"class":58},[48,657,132],{"class":62},[48,659,66],{"class":58},[48,661,662],{"class":137},"30",[48,664,141],{"class":58},[48,666,668],{"class":50,"line":667},33,[48,669,670],{"class":58},"        })\n",[48,672,674],{"class":50,"line":673},34,[48,675,676],{"class":589},"        // グラフ用の広いカラム。デフォルトのまま使えるだけ使う。\n",[48,678,680,682,684,686,688,691,693,695,697,699,701,703,705,707],{"class":50,"line":679},35,[48,681,596],{"class":54},[48,683,59],{"class":58},[48,685,601],{"class":62},[48,687,66],{"class":58},[48,689,690],{"class":137},"9",[48,692,114],{"class":58},[48,694,611],{"class":58},[48,696,55],{"class":566},[48,698,570],{"class":58},[48,700,573],{"class":197},[48,702,59],{"class":58},[48,704,622],{"class":197},[48,706,581],{"class":58},[48,708,296],{"class":58},[48,710,712,714,716,718,720,723],{"class":50,"line":711},36,[48,713,632],{"class":54},[48,715,59],{"class":58},[48,717,63],{"class":62},[48,719,66],{"class":58},[48,721,722],{"class":54},"chart",[48,724,72],{"class":58},[48,726,728],{"class":50,"line":727},37,[48,729,670],{"class":58},[48,731,733],{"class":50,"line":732},38,[48,734,735],{"class":58},"    })\n",[48,737,739],{"class":50,"line":738},39,[48,740,204],{"emptyLinePlaceholder":203},[48,742,744,747,749,751,753,755,757,760],{"class":50,"line":743},40,[48,745,746],{"class":54},"    data",[48,748,114],{"class":58},[48,750,307],{"class":54},[48,752,310],{"class":58},[48,754,536],{"class":54},[48,756,59],{"class":58},[48,758,759],{"class":62},"Generate",[48,761,544],{"class":58},[48,763,765,767,769,771,773],{"class":50,"line":764},41,[48,766,337],{"class":210},[48,768,307],{"class":54},[48,770,342],{"class":58},[48,772,345],{"class":58},[48,774,296],{"class":58},[48,776,778,780,782,784,786,788],{"class":50,"line":777},42,[48,779,353],{"class":54},[48,781,59],{"class":58},[48,783,358],{"class":62},[48,785,66],{"class":58},[48,787,363],{"class":54},[48,789,72],{"class":58},[48,791,793],{"class":50,"line":792},43,[48,794,371],{"class":58},[48,796,798,800,802,804,806,808,811,813,815,818,820,822,825,827,830,833,835,837,839],{"class":50,"line":797},44,[48,799,337],{"class":210},[48,801,307],{"class":54},[48,803,310],{"class":58},[48,805,313],{"class":54},[48,807,59],{"class":58},[48,809,810],{"class":62},"WriteFile",[48,812,66],{"class":58},[48,814,323],{"class":58},[48,816,817],{"class":326},"report.pdf",[48,819,323],{"class":58},[48,821,114],{"class":58},[48,823,824],{"class":54}," data",[48,826,114],{"class":58},[48,828,829],{"class":137}," 0o644",[48,831,832],{"class":58},");",[48,834,307],{"class":54},[48,836,342],{"class":58},[48,838,345],{"class":58},[48,840,296],{"class":58},[48,842,844,846,848,850,852,854],{"class":50,"line":843},45,[48,845,353],{"class":54},[48,847,59],{"class":58},[48,849,358],{"class":62},[48,851,66],{"class":58},[48,853,363],{"class":54},[48,855,72],{"class":58},[48,857,859],{"class":50,"line":858},46,[48,860,371],{"class":58},[48,862,864],{"class":50,"line":863},47,[48,865,866],{"class":58},"}\n",[18,868,869,870,873,874,877],{},"3 カラム幅のロゴセルは ",[45,871,872],{},"FitWidth(30mm)"," で固定している。カラム幅がレイアウトでどう変わってもロゴは常に 30mm 幅。9 カラム幅のグラフは ",[45,875,876],{},"c.Image(chart)"," だけで、与えられた幅を全部使う。両方とも等比。元画像のピクセル数をコードで知っている必要はない。",[14,879,881],{"id":880},"gpdf-の等比が指すもの","gpdf の「等比」が指すもの",[18,883,884],{},"fit モードは 4 つある。デフォルト 1 つで実用の 9 割は片付く:",[886,887,888,904],"table",{},[889,890,891],"thead",{},[892,893,894,898,901],"tr",{},[895,896,897],"th",{},"モード",[895,899,900],{},"挙動",[895,902,903],{},"用途",[905,906,907,921,937,953],"tbody",{},[892,908,909,915,918],{},[910,911,912,914],"td",{},[45,913,82],{}," (デフォルト)",[910,916,917],{},"アスペクト比を保ってボックス内に収める。片方の寸法に余白が残ることがある",[910,919,920],{},"ロゴ・グラフ・スクショ — ほぼ全部",[892,922,923,928,934],{},[910,924,925],{},[45,926,927],{},"FitCover",[910,929,930,931],{},"アスペクト比を保ったままボックス全体を覆う。",[30,932,933],{},"はみ出した部分はクリップ",[910,935,936],{},"ヒーローバナー、プロフィール写真の正方クロップ",[892,938,939,944,950],{},[910,940,941],{},[45,942,943],{},"FitStretch",[910,945,946,947],{},"ボックスにぴったり合うように引き伸ばす。",[30,948,949],{},"アスペクト比が崩れる",[910,951,952],{},"ほぼ使わない。使うときは大抵バグ",[892,954,955,960,963],{},[910,956,957],{},[45,958,959],{},"FitOriginal",[910,961,962],{},"元ピクセル寸法を 72 DPI で換算して描画",[910,964,965],{},"印刷解像度で作られた図版で、リサンプリングを避けたいとき",[18,967,968,970,971,973,974,976,977,980],{},[45,969,122],{}," と ",[45,972,163],{}," はどちらも片方の寸法を固定して、もう片方は ",[45,975,82],{}," で算出する。「幅を気にしている」「高さを気にしている」を素直に書けるショートカットなので、",[45,978,979],{},"WithFitMode"," を直接呼ぶ機会はほぼない。",[14,982,983],{"id":983},"ハマりどころ",[18,985,986],{},"一番よく見る失敗は、アスペクト比が合わない width と height を両方指定して「画像が潰れる」と言うパターン:",[38,988,990],{"className":40,"code":989,"language":42,"meta":43,"style":43},"// 本気で意図していなければ書かないほうがいい\nc.Image(img,\n    template.FitWidth(document.Mm(40)),\n    template.FitHeight(document.Mm(40)),\n)\n",[45,991,992,997,1013,1037,1059],{"__ignoreMap":43},[48,993,994],{"class":50,"line":51},[48,995,996],{"class":589},"// 本気で意図していなければ書かないほうがいい\n",[48,998,999,1001,1003,1005,1007,1010],{"class":50,"line":144},[48,1000,55],{"class":54},[48,1002,59],{"class":58},[48,1004,63],{"class":62},[48,1006,66],{"class":58},[48,1008,1009],{"class":54},"img",[48,1011,1012],{"class":58},",\n",[48,1014,1015,1018,1020,1022,1024,1026,1028,1030,1032,1034],{"class":50,"line":207},[48,1016,1017],{"class":54},"    template",[48,1019,59],{"class":58},[48,1021,122],{"class":62},[48,1023,66],{"class":58},[48,1025,127],{"class":54},[48,1027,59],{"class":58},[48,1029,132],{"class":62},[48,1031,66],{"class":58},[48,1033,138],{"class":137},[48,1035,1036],{"class":58},")),\n",[48,1038,1039,1041,1043,1045,1047,1049,1051,1053,1055,1057],{"class":50,"line":217},[48,1040,1017],{"class":54},[48,1042,59],{"class":58},[48,1044,163],{"class":62},[48,1046,66],{"class":58},[48,1048,127],{"class":54},[48,1050,59],{"class":58},[48,1052,132],{"class":62},[48,1054,66],{"class":58},[48,1056,138],{"class":137},[48,1058,1036],{"class":58},[48,1060,1061],{"class":50,"line":229},[48,1062,72],{"class":58},[18,1064,1065,1066,1068],{},"PNG が 1200×800 なのに 40×40 のボックスに無理やり入れるなら、アスペクト比 (FitStretch 挙動) と画像の一部 (FitCover 挙動) のどちらかを犠牲にするしかない。デフォルトは ",[45,1067,82],{}," なので、gpdf はアスペクト比を保ったまま片方を埋め切らない。結果は 40mm 幅・約 26mm 高で、40mm の枠の下半分が空く。",[18,1070,1071,1072,1074],{},"直し方は片方の寸法だけ指定して計算は gpdf に任せる。本当に正方にクロップしたければ、矛盾した 2 寸法ではなく ",[45,1073,927],{}," を使う:",[38,1076,1078],{"className":40,"code":1077,"language":42,"meta":43,"style":43},"c.Image(img,\n    template.FitWidth(document.Mm(40)),\n    template.FitHeight(document.Mm(40)),\n    template.WithFitMode(document.FitCover),\n)\n",[45,1079,1080,1094,1116,1138,1156],{"__ignoreMap":43},[48,1081,1082,1084,1086,1088,1090,1092],{"class":50,"line":51},[48,1083,55],{"class":54},[48,1085,59],{"class":58},[48,1087,63],{"class":62},[48,1089,66],{"class":58},[48,1091,1009],{"class":54},[48,1093,1012],{"class":58},[48,1095,1096,1098,1100,1102,1104,1106,1108,1110,1112,1114],{"class":50,"line":144},[48,1097,1017],{"class":54},[48,1099,59],{"class":58},[48,1101,122],{"class":62},[48,1103,66],{"class":58},[48,1105,127],{"class":54},[48,1107,59],{"class":58},[48,1109,132],{"class":62},[48,1111,66],{"class":58},[48,1113,138],{"class":137},[48,1115,1036],{"class":58},[48,1117,1118,1120,1122,1124,1126,1128,1130,1132,1134,1136],{"class":50,"line":207},[48,1119,1017],{"class":54},[48,1121,59],{"class":58},[48,1123,163],{"class":62},[48,1125,66],{"class":58},[48,1127,127],{"class":54},[48,1129,59],{"class":58},[48,1131,132],{"class":62},[48,1133,66],{"class":58},[48,1135,138],{"class":137},[48,1137,1036],{"class":58},[48,1139,1140,1142,1144,1146,1148,1150,1152,1154],{"class":50,"line":217},[48,1141,1017],{"class":54},[48,1143,59],{"class":58},[48,1145,979],{"class":62},[48,1147,66],{"class":58},[48,1149,127],{"class":54},[48,1151,59],{"class":58},[48,1153,927],{"class":54},[48,1155,480],{"class":58},[48,1157,1158],{"class":50,"line":229},[48,1159,72],{"class":58},[14,1161,1162],{"id":1162},"ピクセル数は嘘をつかない",[18,1164,1165],{},"gpdf はスケール判断の前に PNG / JPEG ヘッダから元ピクセル寸法を読む。だから 4000×3000 の写真を 60mm のカラムに入れても「元画像側で縮小される」わけではない。元バイト列をそのまま PDF に埋め込み、リサンプリングは PDF リーダー側でやる。表示寸法をどう変えても出力 PDF のサイズは同じ。",[18,1167,1168,1169,1172],{},"ファイルサイズが印刷品質より大事なら、",[45,1170,1171],{},"image/draw"," あたりで先にダウンサンプリングしてから gpdf に渡す。ライブラリが勝手にピクセルを捨てることはない。これは呼び出し側の判断。",[14,1174,1175],{"id":1175},"レイアウト崩れに備えるなら",[18,1177,1178,1179,1181],{},"ページ分割や狭いテーブルセルでカラムが想定より細くなったとき、デフォルトの ",[45,1180,82],{}," はロゴを切手サイズまで縮めてくれる。それが嫌なら下限を設定する:",[38,1183,1185],{"className":40,"code":1184,"language":42,"meta":43,"style":43},"c.Image(logo,\n    template.FitWidth(document.Mm(30)),\n    template.MinDisplayWidth(document.Mm(20)),\n)\n",[45,1186,1187,1201,1223,1246],{"__ignoreMap":43},[48,1188,1189,1191,1193,1195,1197,1199],{"class":50,"line":51},[48,1190,55],{"class":54},[48,1192,59],{"class":58},[48,1194,63],{"class":62},[48,1196,66],{"class":58},[48,1198,641],{"class":54},[48,1200,1012],{"class":58},[48,1202,1203,1205,1207,1209,1211,1213,1215,1217,1219,1221],{"class":50,"line":144},[48,1204,1017],{"class":54},[48,1206,59],{"class":58},[48,1208,122],{"class":62},[48,1210,66],{"class":58},[48,1212,127],{"class":54},[48,1214,59],{"class":58},[48,1216,132],{"class":62},[48,1218,66],{"class":58},[48,1220,662],{"class":137},[48,1222,1036],{"class":58},[48,1224,1225,1227,1229,1232,1234,1236,1238,1240,1242,1244],{"class":50,"line":207},[48,1226,1017],{"class":54},[48,1228,59],{"class":58},[48,1230,1231],{"class":62},"MinDisplayWidth",[48,1233,66],{"class":58},[48,1235,127],{"class":54},[48,1237,59],{"class":58},[48,1239,132],{"class":62},[48,1241,66],{"class":58},[48,1243,176],{"class":137},[48,1245,1036],{"class":58},[48,1247,1248],{"class":50,"line":217},[48,1249,72],{"class":58},[18,1251,1252,1254],{},[45,1253,1231],{}," はレイアウトエンジンに「20mm を下回らないと収まらないなら、このページに描かずに次のページへ送れ」と伝える。読める寸法で出るか、出ないか。中途半端に潰れた状態にはならない。",[14,1256,1257],{"id":1257},"関連レシピ",[1259,1260,1261,1272,1279],"ul",{},[1262,1263,1264,1268,1269,1271],"li",{},[22,1265,1267],{"href":1266},"/ja/blog/embed-png-transparency","gpdf で透過 PNG を埋め込む方法"," — 同じ ",[45,1270,78],{}," 入口。アルファチャンネル側の話",[1262,1273,1274,1278],{},[22,1275,1277],{"href":1276},"/ja/blog/12-column-grid","gpdf の 12 カラムグリッドの仕組み"," — 「カラム幅」が実際に何 mm になるかの話",[1262,1280,1281,1285],{},[22,1282,1284],{"href":1283},"/ja/blog/table-column-widths","テーブルのカラム幅を指定する方法"," — 画像の入る箱がカラムでなくテーブルセルの場合",[14,1287,1289],{"id":1288},"gpdf-を試す","gpdf を試す",[18,1291,1292],{},"gpdf は Go の PDF 生成ライブラリ。MIT、外部依存ゼロ、画像とフォントを純 Go で扱う。",[38,1294,1298],{"className":1295,"code":1296,"language":1297,"meta":43,"style":43},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","go get github.com/gpdf-dev/gpdf\n","bash",[45,1299,1300],{"__ignoreMap":43},[48,1301,1302,1304,1307],{"class":50,"line":51},[48,1303,42],{"class":197},[48,1305,1306],{"class":326}," get",[48,1308,1309],{"class":326}," github.com/gpdf-dev/gpdf\n",[18,1311,1312,1316,1317],{},[22,1313,1315],{"href":24,"rel":1314},[26],"⭐ GitHub で Star する"," · ",[22,1318,1321],{"href":1319,"rel":1320},"https://gpdf.dev/docs/quickstart",[26],"ドキュメントを読む",[1323,1324,1325],"style",{},"html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}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 .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":43,"searchDepth":144,"depth":144,"links":1327},[1328,1329,1330,1331,1332,1333,1334,1335,1336],{"id":16,"depth":144,"text":16},{"id":36,"depth":144,"text":36},{"id":184,"depth":144,"text":184},{"id":880,"depth":144,"text":881},{"id":983,"depth":144,"text":983},{"id":1162,"depth":144,"text":1162},{"id":1175,"depth":144,"text":1175},{"id":1257,"depth":144,"text":1257},{"id":1288,"depth":144,"text":1289},"2026-05-05","c.Image にバイト列を渡すだけ。gpdf はデフォルトでカラム幅に等比縮小する。明示したいときだけ FitWidth / FitHeight を使う。",false,"md",{"name":1342,"totalTime":1343,"tools":1344,"steps":1346},"gpdf のカラム内で画像を等比スケールする","PT5M",[1345,249],"Go 1.22+",[1347,1350,1353,1356],{"name":1348,"text":1349},"オプションなしで c.Image にバイト列を渡す","ColBuilder 内で c.Image(imgBytes) を呼ぶ。デフォルトの fit モードは FitContain なので、アスペクト比を保ったままカラム幅に縮小される。手動で width / height を計算する必要はない。",{"name":1351,"text":1352},"カラム幅より小さくしたいときは FitWidth を使う","c.Image(imgBytes, template.FitWidth(document.Mm(40))) で幅 40mm に固定する。高さは元画像のアスペクト比から算出される。",{"name":1354,"text":1355},"縦方向の制約を優先したいときは FitHeight","c.Image(imgBytes, template.FitHeight(document.Mm(20))) で高さ 20mm に固定する。幅はアスペクト比から自動計算。",{"name":1357,"text":1358},"デフォルト以外の挙動が必要なときだけ WithFitMode","template.WithFitMode(document.FitCover) でボックスを満たして溢れた部分はクリップ、FitStretch で歪ませて完全フィット、FitOriginal で 72 DPI 換算の元ピクセルサイズで描画。",null,{},"/ja/blog/scale-image-fit-column",{"title":5,"description":1338},"ja/blog/020.scale-image-fit-column",[1365,1366],"recipe","tutorial","UKQkGNR08Y-qzvE-uAdHUaPybVxGm4Lj9gfWmJwJ8lw",1779199021876]