[{"data":1,"prerenderedAt":1378},["ShallowReactive",2],{"blog-en-scale-image-fit-column":3},{"id":4,"title":5,"author":6,"body":10,"date":1347,"description":1348,"draft":1349,"extension":1350,"howTo":1351,"image":1369,"meta":1370,"navigation":209,"path":1371,"seo":1372,"stem":1373,"tags":1374,"updated":1369,"__hash__":1377},"blog/blog/020.scale-image-fit-column.md","How do I scale an image proportionally to fit a column?",{"name":7,"url":8,"avatar":9},"Taiki Noda","https://nadai.dev/en/about","https://nadai.dev/og-default.png",{"type":11,"value":12,"toc":1336},"minimark",[13,18,38,42,78,89,100,184,187,191,873,884,888,891,972,987,991,994,1070,1076,1082,1167,1171,1174,1181,1185,1191,1259,1264,1268,1296,1300,1303,1320,1332],[14,15,17],"h2",{"id":16},"the-question-in-other-words","The question, in other words",[19,20,21,22,29,30,34,35,37],"p",{},"I have a logo, a chart, or a screenshot — say a 1200×800 PNG — and I want it inside one of my ",[23,24,28],"a",{"href":25,"rel":26},"https://github.com/gpdf-dev/gpdf",[27],"nofollow","gpdf"," columns. I do ",[31,32,33],"strong",{},"not"," want to do the aspect-ratio math by hand. I do ",[31,36,33],{}," want it stretched into an oval. I do not want it overflowing into the next column. Just shrink it to fit, keep it proportional, done.",[14,39,41],{"id":40},"tldr","TL;DR",[43,44,49],"pre",{"className":45,"code":46,"language":47,"meta":48,"style":48},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","c.Image(imgBytes)\n","go","",[50,51,52],"code",{"__ignoreMap":48},[53,54,57,61,65,69,72,75],"span",{"class":55,"line":56},"line",1,[53,58,60],{"class":59},"sTEyZ","c",[53,62,64],{"class":63},"sMK4o",".",[53,66,68],{"class":67},"s2Zo4","Image",[53,70,71],{"class":63},"(",[53,73,74],{"class":59},"imgBytes",[53,76,77],{"class":63},")\n",[19,79,80,81,84,85,88],{},"That is the whole recipe in the most common case. ",[50,82,83],{},"c.Image"," defaults to ",[50,86,87],{},"FitContain",", which scales the image down to the column width while keeping the original aspect ratio. If the image is already smaller than the column, gpdf draws it at its natural size.",[19,90,91,92,95,96,99],{},"Need a smaller bound than the full column? Add ",[50,93,94],{},"template.FitWidth"," or ",[50,97,98],{},"template.FitHeight",":",[43,101,103],{"className":45,"code":102,"language":47,"meta":48,"style":48},"c.Image(imgBytes, template.FitWidth(document.Mm(40)))\nc.Image(imgBytes, template.FitHeight(document.Mm(20)))\n",[50,104,105,147],{"__ignoreMap":48},[53,106,107,109,111,113,115,117,120,123,125,128,130,133,135,138,140,144],{"class":55,"line":56},[53,108,60],{"class":59},[53,110,64],{"class":63},[53,112,68],{"class":67},[53,114,71],{"class":63},[53,116,74],{"class":59},[53,118,119],{"class":63},",",[53,121,122],{"class":59}," template",[53,124,64],{"class":63},[53,126,127],{"class":67},"FitWidth",[53,129,71],{"class":63},[53,131,132],{"class":59},"document",[53,134,64],{"class":63},[53,136,137],{"class":67},"Mm",[53,139,71],{"class":63},[53,141,143],{"class":142},"sbssI","40",[53,145,146],{"class":63},")))\n",[53,148,150,152,154,156,158,160,162,164,166,169,171,173,175,177,179,182],{"class":55,"line":149},2,[53,151,60],{"class":59},[53,153,64],{"class":63},[53,155,68],{"class":67},[53,157,71],{"class":63},[53,159,74],{"class":59},[53,161,119],{"class":63},[53,163,122],{"class":59},[53,165,64],{"class":63},[53,167,168],{"class":67},"FitHeight",[53,170,71],{"class":63},[53,172,132],{"class":59},[53,174,64],{"class":63},[53,176,137],{"class":67},[53,178,71],{"class":63},[53,180,181],{"class":142},"20",[53,183,146],{"class":63},[19,185,186],{},"Both options preserve the source aspect ratio. You only specify one dimension; gpdf computes the other.",[14,188,190],{"id":189},"a-complete-example","A complete example",[43,192,194],{"className":45,"code":193,"language":47,"meta":48,"style":48},"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        // Narrow column for the logo, bounded to 30mm wide.\n        r.Col(3, func(c *template.ColBuilder) {\n            c.Image(logo, template.FitWidth(document.Mm(30)))\n        })\n        // Wide column for the chart, default fit fills the available width.\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",[50,195,196,205,211,221,233,243,248,258,268,278,283,288,303,338,354,372,378,407,420,435,440,445,464,487,521,527,532,551,556,590,597,633,671,677,683,715,731,736,742,747,768,781,796,801,847,862,867],{"__ignoreMap":48},[53,197,198,201],{"class":55,"line":56},[53,199,200],{"class":63},"package",[53,202,204],{"class":203},"sBMFI"," main\n",[53,206,207],{"class":55,"line":149},[53,208,210],{"emptyLinePlaceholder":209},true,"\n",[53,212,214,218],{"class":55,"line":213},3,[53,215,217],{"class":216},"s7zQu","import",[53,219,220],{"class":63}," (\n",[53,222,224,227,230],{"class":55,"line":223},4,[53,225,226],{"class":63},"    \"",[53,228,229],{"class":203},"log",[53,231,232],{"class":63},"\"\n",[53,234,236,238,241],{"class":55,"line":235},5,[53,237,226],{"class":63},[53,239,240],{"class":203},"os",[53,242,232],{"class":63},[53,244,246],{"class":55,"line":245},6,[53,247,210],{"emptyLinePlaceholder":209},[53,249,251,253,256],{"class":55,"line":250},7,[53,252,226],{"class":63},[53,254,255],{"class":203},"github.com/gpdf-dev/gpdf",[53,257,232],{"class":63},[53,259,261,263,266],{"class":55,"line":260},8,[53,262,226],{"class":63},[53,264,265],{"class":203},"github.com/gpdf-dev/gpdf/document",[53,267,232],{"class":63},[53,269,271,273,276],{"class":55,"line":270},9,[53,272,226],{"class":63},[53,274,275],{"class":203},"github.com/gpdf-dev/gpdf/template",[53,277,232],{"class":63},[53,279,281],{"class":55,"line":280},10,[53,282,77],{"class":63},[53,284,286],{"class":55,"line":285},11,[53,287,210],{"emptyLinePlaceholder":209},[53,289,291,294,297,300],{"class":55,"line":290},12,[53,292,293],{"class":63},"func",[53,295,296],{"class":67}," main",[53,298,299],{"class":63},"()",[53,301,302],{"class":63}," {\n",[53,304,306,309,311,314,317,320,322,325,327,330,334,336],{"class":55,"line":305},13,[53,307,308],{"class":59},"    logo",[53,310,119],{"class":63},[53,312,313],{"class":59}," err ",[53,315,316],{"class":63},":=",[53,318,319],{"class":59}," os",[53,321,64],{"class":63},[53,323,324],{"class":67},"ReadFile",[53,326,71],{"class":63},[53,328,329],{"class":63},"\"",[53,331,333],{"class":332},"sfazB","logo.png",[53,335,329],{"class":63},[53,337,77],{"class":63},[53,339,341,344,346,349,352],{"class":55,"line":340},14,[53,342,343],{"class":216},"    if",[53,345,313],{"class":59},[53,347,348],{"class":63},"!=",[53,350,351],{"class":63}," nil",[53,353,302],{"class":63},[53,355,357,360,362,365,367,370],{"class":55,"line":356},15,[53,358,359],{"class":59},"        log",[53,361,64],{"class":63},[53,363,364],{"class":67},"Fatal",[53,366,71],{"class":63},[53,368,369],{"class":59},"err",[53,371,77],{"class":63},[53,373,375],{"class":55,"line":374},16,[53,376,377],{"class":63},"    }\n",[53,379,381,384,386,388,390,392,394,396,398,400,403,405],{"class":55,"line":380},17,[53,382,383],{"class":59},"    chart",[53,385,119],{"class":63},[53,387,313],{"class":59},[53,389,316],{"class":63},[53,391,319],{"class":59},[53,393,64],{"class":63},[53,395,324],{"class":67},[53,397,71],{"class":63},[53,399,329],{"class":63},[53,401,402],{"class":332},"chart.png",[53,404,329],{"class":63},[53,406,77],{"class":63},[53,408,410,412,414,416,418],{"class":55,"line":409},18,[53,411,343],{"class":216},[53,413,313],{"class":59},[53,415,348],{"class":63},[53,417,351],{"class":63},[53,419,302],{"class":63},[53,421,423,425,427,429,431,433],{"class":55,"line":422},19,[53,424,359],{"class":59},[53,426,64],{"class":63},[53,428,364],{"class":67},[53,430,71],{"class":63},[53,432,369],{"class":59},[53,434,77],{"class":63},[53,436,438],{"class":55,"line":437},20,[53,439,377],{"class":63},[53,441,443],{"class":55,"line":442},21,[53,444,210],{"emptyLinePlaceholder":209},[53,446,448,451,453,456,458,461],{"class":55,"line":447},22,[53,449,450],{"class":59},"    doc ",[53,452,316],{"class":63},[53,454,455],{"class":59}," gpdf",[53,457,64],{"class":63},[53,459,460],{"class":67},"NewDocument",[53,462,463],{"class":63},"(\n",[53,465,467,470,472,475,477,479,481,484],{"class":55,"line":466},23,[53,468,469],{"class":59},"        gpdf",[53,471,64],{"class":63},[53,473,474],{"class":67},"WithPageSize",[53,476,71],{"class":63},[53,478,28],{"class":59},[53,480,64],{"class":63},[53,482,483],{"class":59},"A4",[53,485,486],{"class":63},"),\n",[53,488,490,492,494,497,499,501,503,506,508,510,512,514,516,518],{"class":55,"line":489},24,[53,491,469],{"class":59},[53,493,64],{"class":63},[53,495,496],{"class":67},"WithMargins",[53,498,71],{"class":63},[53,500,132],{"class":59},[53,502,64],{"class":63},[53,504,505],{"class":67},"UniformEdges",[53,507,71],{"class":63},[53,509,132],{"class":59},[53,511,64],{"class":63},[53,513,137],{"class":67},[53,515,71],{"class":63},[53,517,181],{"class":142},[53,519,520],{"class":63},"))),\n",[53,522,524],{"class":55,"line":523},25,[53,525,526],{"class":63},"    )\n",[53,528,530],{"class":55,"line":529},26,[53,531,210],{"emptyLinePlaceholder":209},[53,533,535,538,540,543,545,548],{"class":55,"line":534},27,[53,536,537],{"class":59},"    page ",[53,539,316],{"class":63},[53,541,542],{"class":59}," doc",[53,544,64],{"class":63},[53,546,547],{"class":67},"AddPage",[53,549,550],{"class":63},"()\n",[53,552,554],{"class":55,"line":553},28,[53,555,210],{"emptyLinePlaceholder":209},[53,557,559,562,564,567,570,574,577,580,582,585,588],{"class":55,"line":558},29,[53,560,561],{"class":59},"    page",[53,563,64],{"class":63},[53,565,566],{"class":67},"AutoRow",[53,568,569],{"class":63},"(func(",[53,571,573],{"class":572},"sHdIc","r",[53,575,576],{"class":63}," *",[53,578,579],{"class":203},"template",[53,581,64],{"class":63},[53,583,584],{"class":203},"RowBuilder",[53,586,587],{"class":63},")",[53,589,302],{"class":63},[53,591,593],{"class":55,"line":592},30,[53,594,596],{"class":595},"sHwdD","        // Narrow column for the logo, bounded to 30mm wide.\n",[53,598,600,603,605,608,610,613,615,618,620,622,624,626,629,631],{"class":55,"line":599},31,[53,601,602],{"class":59},"        r",[53,604,64],{"class":63},[53,606,607],{"class":67},"Col",[53,609,71],{"class":63},[53,611,612],{"class":142},"3",[53,614,119],{"class":63},[53,616,617],{"class":63}," func(",[53,619,60],{"class":572},[53,621,576],{"class":63},[53,623,579],{"class":203},[53,625,64],{"class":63},[53,627,628],{"class":203},"ColBuilder",[53,630,587],{"class":63},[53,632,302],{"class":63},[53,634,636,639,641,643,645,648,650,652,654,656,658,660,662,664,666,669],{"class":55,"line":635},32,[53,637,638],{"class":59},"            c",[53,640,64],{"class":63},[53,642,68],{"class":67},[53,644,71],{"class":63},[53,646,647],{"class":59},"logo",[53,649,119],{"class":63},[53,651,122],{"class":59},[53,653,64],{"class":63},[53,655,127],{"class":67},[53,657,71],{"class":63},[53,659,132],{"class":59},[53,661,64],{"class":63},[53,663,137],{"class":67},[53,665,71],{"class":63},[53,667,668],{"class":142},"30",[53,670,146],{"class":63},[53,672,674],{"class":55,"line":673},33,[53,675,676],{"class":63},"        })\n",[53,678,680],{"class":55,"line":679},34,[53,681,682],{"class":595},"        // Wide column for the chart, default fit fills the available width.\n",[53,684,686,688,690,692,694,697,699,701,703,705,707,709,711,713],{"class":55,"line":685},35,[53,687,602],{"class":59},[53,689,64],{"class":63},[53,691,607],{"class":67},[53,693,71],{"class":63},[53,695,696],{"class":142},"9",[53,698,119],{"class":63},[53,700,617],{"class":63},[53,702,60],{"class":572},[53,704,576],{"class":63},[53,706,579],{"class":203},[53,708,64],{"class":63},[53,710,628],{"class":203},[53,712,587],{"class":63},[53,714,302],{"class":63},[53,716,718,720,722,724,726,729],{"class":55,"line":717},36,[53,719,638],{"class":59},[53,721,64],{"class":63},[53,723,68],{"class":67},[53,725,71],{"class":63},[53,727,728],{"class":59},"chart",[53,730,77],{"class":63},[53,732,734],{"class":55,"line":733},37,[53,735,676],{"class":63},[53,737,739],{"class":55,"line":738},38,[53,740,741],{"class":63},"    })\n",[53,743,745],{"class":55,"line":744},39,[53,746,210],{"emptyLinePlaceholder":209},[53,748,750,753,755,757,759,761,763,766],{"class":55,"line":749},40,[53,751,752],{"class":59},"    data",[53,754,119],{"class":63},[53,756,313],{"class":59},[53,758,316],{"class":63},[53,760,542],{"class":59},[53,762,64],{"class":63},[53,764,765],{"class":67},"Generate",[53,767,550],{"class":63},[53,769,771,773,775,777,779],{"class":55,"line":770},41,[53,772,343],{"class":216},[53,774,313],{"class":59},[53,776,348],{"class":63},[53,778,351],{"class":63},[53,780,302],{"class":63},[53,782,784,786,788,790,792,794],{"class":55,"line":783},42,[53,785,359],{"class":59},[53,787,64],{"class":63},[53,789,364],{"class":67},[53,791,71],{"class":63},[53,793,369],{"class":59},[53,795,77],{"class":63},[53,797,799],{"class":55,"line":798},43,[53,800,377],{"class":63},[53,802,804,806,808,810,812,814,817,819,821,824,826,828,831,833,836,839,841,843,845],{"class":55,"line":803},44,[53,805,343],{"class":216},[53,807,313],{"class":59},[53,809,316],{"class":63},[53,811,319],{"class":59},[53,813,64],{"class":63},[53,815,816],{"class":67},"WriteFile",[53,818,71],{"class":63},[53,820,329],{"class":63},[53,822,823],{"class":332},"report.pdf",[53,825,329],{"class":63},[53,827,119],{"class":63},[53,829,830],{"class":59}," data",[53,832,119],{"class":63},[53,834,835],{"class":142}," 0o644",[53,837,838],{"class":63},");",[53,840,313],{"class":59},[53,842,348],{"class":63},[53,844,351],{"class":63},[53,846,302],{"class":63},[53,848,850,852,854,856,858,860],{"class":55,"line":849},45,[53,851,359],{"class":59},[53,853,64],{"class":63},[53,855,364],{"class":67},[53,857,71],{"class":63},[53,859,369],{"class":59},[53,861,77],{"class":63},[53,863,865],{"class":55,"line":864},46,[53,866,377],{"class":63},[53,868,870],{"class":55,"line":869},47,[53,871,872],{"class":63},"}\n",[19,874,875,876,879,880,883],{},"Two things are happening here. The 3-column logo cell uses ",[50,877,878],{},"FitWidth(30mm)"," because we want the logo small and consistent regardless of how much room the column has. The 9-column chart cell takes a bare ",[50,881,882],{},"c.Image(chart)"," because we want the chart to use everything the column will give it. Both stay proportional. Neither needs the source pixel dimensions to be known in code.",[14,885,887],{"id":886},"what-proportional-actually-means-in-gpdf","What \"proportional\" actually means in gpdf",[19,889,890],{},"Four fit modes exist; one of them is the default and covers maybe 90% of real use:",[892,893,894,910],"table",{},[895,896,897],"thead",{},[898,899,900,904,907],"tr",{},[901,902,903],"th",{},"Mode",[901,905,906],{},"What it does",[901,908,909],{},"When to use it",[911,912,913,927,943,959],"tbody",{},[898,914,915,921,924],{},[916,917,918,920],"td",{},[50,919,87],{}," (default)",[916,922,923],{},"Scales down to fit inside the box, preserves aspect, may leave empty space",[916,925,926],{},"Logos, charts, screenshots — almost everything",[898,928,929,934,940],{},[916,930,931],{},[50,932,933],{},"FitCover",[916,935,936,937],{},"Scales up or down to cover the entire box, preserves aspect, ",[31,938,939],{},"clips overflow",[916,941,942],{},"Hero banners, profile photo crops",[898,944,945,950,956],{},[916,946,947],{},[50,948,949],{},"FitStretch",[916,951,952,953],{},"Scales to exactly fill the box, ",[31,954,955],{},"distorts aspect",[916,957,958],{},"Almost never — usually a bug if you reach for this",[898,960,961,966,969],{},[916,962,963],{},[50,964,965],{},"FitOriginal",[916,967,968],{},"Renders at the source pixel dimensions converted at 72 DPI",[916,970,971],{},"Diagrams that were authored at print resolution and must not be resampled",[19,973,974,976,977,979,980,982,983,986],{},[50,975,127],{}," and ",[50,978,168],{}," both pin one dimension and use ",[50,981,87],{}," for the other. They are the ergonomic shortcut for \"I care about width\" or \"I care about height\" — you almost never need to call ",[50,984,985],{},"WithFitMode"," directly.",[14,988,990],{"id":989},"the-trap-people-fall-into","The trap people fall into",[19,992,993],{},"The mistake we see most often is supplying both a width and a height that don't match the source aspect ratio, then complaining the image looks squished. That happens when you do something like this:",[43,995,997],{"className":45,"code":996,"language":47,"meta":48,"style":48},"// Don't do this unless you really mean it.\nc.Image(img,\n    template.FitWidth(document.Mm(40)),\n    template.FitHeight(document.Mm(40)),\n)\n",[50,998,999,1004,1020,1044,1066],{"__ignoreMap":48},[53,1000,1001],{"class":55,"line":56},[53,1002,1003],{"class":595},"// Don't do this unless you really mean it.\n",[53,1005,1006,1008,1010,1012,1014,1017],{"class":55,"line":149},[53,1007,60],{"class":59},[53,1009,64],{"class":63},[53,1011,68],{"class":67},[53,1013,71],{"class":63},[53,1015,1016],{"class":59},"img",[53,1018,1019],{"class":63},",\n",[53,1021,1022,1025,1027,1029,1031,1033,1035,1037,1039,1041],{"class":55,"line":213},[53,1023,1024],{"class":59},"    template",[53,1026,64],{"class":63},[53,1028,127],{"class":67},[53,1030,71],{"class":63},[53,1032,132],{"class":59},[53,1034,64],{"class":63},[53,1036,137],{"class":67},[53,1038,71],{"class":63},[53,1040,143],{"class":142},[53,1042,1043],{"class":63},")),\n",[53,1045,1046,1048,1050,1052,1054,1056,1058,1060,1062,1064],{"class":55,"line":223},[53,1047,1024],{"class":59},[53,1049,64],{"class":63},[53,1051,168],{"class":67},[53,1053,71],{"class":63},[53,1055,132],{"class":59},[53,1057,64],{"class":63},[53,1059,137],{"class":67},[53,1061,71],{"class":63},[53,1063,143],{"class":142},[53,1065,1043],{"class":63},[53,1067,1068],{"class":55,"line":235},[53,1069,77],{"class":63},[19,1071,1072,1073,1075],{},"If your PNG is 1200×800, forcing it into a 40×40 box means one of two things has to give: the aspect ratio (FitStretch behavior) or part of the image (FitCover behavior). The default fit mode is ",[50,1074,87],{},", so gpdf will keep the aspect and leave one dimension under-filled — the image will be 40mm wide and ~26mm tall, sitting in a 40mm tall slot with empty space below.",[19,1077,1078,1079,1081],{},"The fix is to pick one dimension and trust the math. If you really do need a square crop of a non-square image, you want ",[50,1080,933],{},", not two competing dimensions:",[43,1083,1085],{"className":45,"code":1084,"language":47,"meta":48,"style":48},"c.Image(img,\n    template.FitWidth(document.Mm(40)),\n    template.FitHeight(document.Mm(40)),\n    template.WithFitMode(document.FitCover),\n)\n",[50,1086,1087,1101,1123,1145,1163],{"__ignoreMap":48},[53,1088,1089,1091,1093,1095,1097,1099],{"class":55,"line":56},[53,1090,60],{"class":59},[53,1092,64],{"class":63},[53,1094,68],{"class":67},[53,1096,71],{"class":63},[53,1098,1016],{"class":59},[53,1100,1019],{"class":63},[53,1102,1103,1105,1107,1109,1111,1113,1115,1117,1119,1121],{"class":55,"line":149},[53,1104,1024],{"class":59},[53,1106,64],{"class":63},[53,1108,127],{"class":67},[53,1110,71],{"class":63},[53,1112,132],{"class":59},[53,1114,64],{"class":63},[53,1116,137],{"class":67},[53,1118,71],{"class":63},[53,1120,143],{"class":142},[53,1122,1043],{"class":63},[53,1124,1125,1127,1129,1131,1133,1135,1137,1139,1141,1143],{"class":55,"line":213},[53,1126,1024],{"class":59},[53,1128,64],{"class":63},[53,1130,168],{"class":67},[53,1132,71],{"class":63},[53,1134,132],{"class":59},[53,1136,64],{"class":63},[53,1138,137],{"class":67},[53,1140,71],{"class":63},[53,1142,143],{"class":142},[53,1144,1043],{"class":63},[53,1146,1147,1149,1151,1153,1155,1157,1159,1161],{"class":55,"line":223},[53,1148,1024],{"class":59},[53,1150,64],{"class":63},[53,1152,985],{"class":67},[53,1154,71],{"class":63},[53,1156,132],{"class":59},[53,1158,64],{"class":63},[53,1160,933],{"class":59},[53,1162,486],{"class":63},[53,1164,1165],{"class":55,"line":235},[53,1166,77],{"class":63},[14,1168,1170],{"id":1169},"pixel-size-doesnt-lie","Pixel size doesn't lie",[19,1172,1173],{},"gpdf reads the intrinsic pixel dimensions out of the PNG or JPEG header before any scaling decision. So a 4000×3000 photo dropped into a 60mm column is not \"scaled at the source\" — gpdf embeds the full image bytes, and the PDF reader does the resampling at render time. The output PDF will be the same file size as if you had embedded the photo at any other display dimension.",[19,1175,1176,1177,1180],{},"If file size matters more than maximum print quality, downscale the source image with something like ",[50,1178,1179],{},"image/draw"," before handing it to gpdf. The library will not silently throw away pixels for you. That choice belongs to you.",[14,1182,1184],{"id":1183},"what-about-the-layout-overflow-case","What about the layout overflow case?",[19,1186,1187,1188,1190],{},"If a column ends up too narrow at render time — because the page broke unexpectedly, or a table cell shrank to fit content — the default ",[50,1189,87],{}," will gladly scale your logo down to a postage stamp. If that bothers you, set a floor:",[43,1192,1194],{"className":45,"code":1193,"language":47,"meta":48,"style":48},"c.Image(logo,\n    template.FitWidth(document.Mm(30)),\n    template.MinDisplayWidth(document.Mm(20)),\n)\n",[50,1195,1196,1210,1232,1255],{"__ignoreMap":48},[53,1197,1198,1200,1202,1204,1206,1208],{"class":55,"line":56},[53,1199,60],{"class":59},[53,1201,64],{"class":63},[53,1203,68],{"class":67},[53,1205,71],{"class":63},[53,1207,647],{"class":59},[53,1209,1019],{"class":63},[53,1211,1212,1214,1216,1218,1220,1222,1224,1226,1228,1230],{"class":55,"line":149},[53,1213,1024],{"class":59},[53,1215,64],{"class":63},[53,1217,127],{"class":67},[53,1219,71],{"class":63},[53,1221,132],{"class":59},[53,1223,64],{"class":63},[53,1225,137],{"class":67},[53,1227,71],{"class":63},[53,1229,668],{"class":142},[53,1231,1043],{"class":63},[53,1233,1234,1236,1238,1241,1243,1245,1247,1249,1251,1253],{"class":55,"line":213},[53,1235,1024],{"class":59},[53,1237,64],{"class":63},[53,1239,1240],{"class":67},"MinDisplayWidth",[53,1242,71],{"class":63},[53,1244,132],{"class":59},[53,1246,64],{"class":63},[53,1248,137],{"class":67},[53,1250,71],{"class":63},[53,1252,181],{"class":142},[53,1254,1043],{"class":63},[53,1256,1257],{"class":55,"line":223},[53,1258,77],{"class":63},[19,1260,1261,1263],{},[50,1262,1240],{}," tells the layout engine: if you would have to shrink this image below 20mm to make it fit, push it to the next page instead. The image stays legible or it doesn't get drawn — never the worst-of-both middle ground.",[14,1265,1267],{"id":1266},"related-recipes","Related recipes",[1269,1270,1271,1282,1289],"ul",{},[1272,1273,1274,1278,1279,1281],"li",{},[23,1275,1277],{"href":1276},"/blog/embed-png-transparency","How do I embed a PNG with transparency in gpdf?"," — same ",[50,1280,83],{}," entry point, but with the alpha-channel details",[1272,1283,1284,1288],{},[23,1285,1287],{"href":1286},"/blog/12-column-grid","How does the 12-column grid work in gpdf?"," — what \"the column width\" actually resolves to",[1272,1290,1291,1295],{},[23,1292,1294],{"href":1293},"/blog/table-column-widths","How do I set column widths in a table?"," — when the box around your image is a table cell, not a row column",[14,1297,1299],{"id":1298},"try-gpdf","Try gpdf",[19,1301,1302],{},"gpdf is a Go library for generating PDFs. MIT, zero external dependencies, pure-Go image and font handling.",[43,1304,1308],{"className":1305,"code":1306,"language":1307,"meta":48,"style":48},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","go get github.com/gpdf-dev/gpdf\n","bash",[50,1309,1310],{"__ignoreMap":48},[53,1311,1312,1314,1317],{"class":55,"line":56},[53,1313,47],{"class":203},[53,1315,1316],{"class":332}," get",[53,1318,1319],{"class":332}," github.com/gpdf-dev/gpdf\n",[19,1321,1322,1326,1327],{},[23,1323,1325],{"href":25,"rel":1324},[27],"⭐ Star on GitHub"," · ",[23,1328,1331],{"href":1329,"rel":1330},"https://gpdf.dev/docs/quickstart",[27],"Read the docs",[1333,1334,1335],"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":48,"searchDepth":149,"depth":149,"links":1337},[1338,1339,1340,1341,1342,1343,1344,1345,1346],{"id":16,"depth":149,"text":17},{"id":40,"depth":149,"text":41},{"id":189,"depth":149,"text":190},{"id":886,"depth":149,"text":887},{"id":989,"depth":149,"text":990},{"id":1169,"depth":149,"text":1170},{"id":1183,"depth":149,"text":1184},{"id":1266,"depth":149,"text":1267},{"id":1298,"depth":149,"text":1299},"2026-05-05","gpdf already does it. c.Image(bytes) fills the column width and preserves aspect ratio. Use FitWidth or FitHeight for explicit bounds, WithFitMode for the non-default behaviors.",false,"md",{"name":1352,"totalTime":1353,"tools":1354,"steps":1356},"Scale an image proportionally inside a gpdf column","PT5M",[1355,255],"Go 1.22+",[1357,1360,1363,1366],{"name":1358,"text":1359},"Pass the image bytes to c.Image with no fit options","Inside a column, call c.Image(imgBytes). The default fit mode is FitContain, so gpdf scales the image to the column width while preserving the aspect ratio. No manual width or height calculation needed.",{"name":1361,"text":1362},"Use FitWidth when you want a specific width smaller than the column","Call c.Image(imgBytes, template.FitWidth(document.Mm(40))) to bound the image to 40mm wide. Height is derived from the source aspect ratio.",{"name":1364,"text":1365},"Use FitHeight when the vertical bound matters more","Call c.Image(imgBytes, template.FitHeight(document.Mm(20))) to lock the image to 20mm tall, with width derived from aspect.",{"name":1367,"text":1368},"Reach for WithFitMode only when you need a non-default behavior","Pass template.WithFitMode(document.FitCover) to fill the box and clip overflow, FitStretch to distort to exact bounds, or FitOriginal to render at the source pixel size converted at 72 DPI.",null,{},"/blog/scale-image-fit-column",{"title":5,"description":1348},"blog/020.scale-image-fit-column",[1375,1376],"recipe","tutorial","FRCVgtzUV9n25OrxSN6D1a4ts2M7MbN1W3iGbbkvS-k",1779199010174]