等比例縮小像素
最近在Wikipedia看到有趣的問題:將原圖等比例縮小圖片至指定像素
那問題來了:如何把圖片的像素以等比例縮小?不想看解題的可以直接去 resluation-ratio.js 看看。
命題說明
一張圖片的像素多少,是該圖的長乘以寬。比方說一張 800×600 的圖片,像素就是 480000。
有關「如何把圖片的像素以等比例縮小」的具體說明為:如果要限定像素的話,除了要出長與寬以外,還要給出限定像素,把比例收斂在該限定像素以下。
具體示例:有一張 800×600 要縮小到 300000 的話,那程式要給出 Ma×Pi×el([800, 600], 300000)
的命題;而由於就要縮為 632×474 (299568 像素), 因此答案要給出 [632, 474]
的陣列。
解題
首先要知道的是圖片的長寬比例。比方說 800×600 的比例就是 4:3. 後來我才知道這比例被稱為「長寬比」(aspect ratio)。
那如何解出長寬比?Stack Overflow 的回答說要用求取長寬的最大公因數後,再將長或寬除以最大公因數後,求取兩者比例。而最大公因數則要透過輾轉相除法取得。
比方說 800×600 的長寬比是什麼?那就要從最大公因數開始求。依照輾轉相除法解題,答案為 200。那麼 800×600 的比呢?那就是 (800/200):(600/200)
,也就是 4:3。恰好就是 SVGA 的比例。
但接下來呢?我們希望長寬比例是 4x * 3x = 300000
的話,那該用什麼求取 x
是什麼?我一直想不通,只好向尋求 ChatGPT 答案。然後 ChatGPT 給了個巧妙的解法:
- 把比例乘上去,並加上平方:也就是把
4x * 3x = 300000
變成12x^2 = 300000
- 把左邊的乘數移動至結果後變成除法:也就是把
12x^2 = 300000
變成x^2 = 300000/12
- 最後把平方根移動到右邊的除法結果後,將其寫成根號。該數字就是答案。也就是
x = sqrt(300000/12)
sqrt(300000/12)
為 158.11。這邊無條件捨去(題目為給定像素以下)後就是 158。
為什麼?
首先,因為 x * x
會等於 x^2
:也就是「x乘以x等於x的二次方」。因此 4x * 3x
就是 12x^2
。接著,把 12 移動到右邊,就會讓算術變成 x^2 = 300000
。最後,x^2
放到算式右邊就會變成平方根。x 就會知道是什麼了。
最後只要把 x 乘上比例就完成了:
158 * 3 = 474
158 * 4 = 632
474 * 632 = 299568
299568 在 300000 以下,所以長 632 寬 474 是 300000 像素以下符合比例的最高長寬了。
程式寫下來就是:resluation-ratio.js
後記
我後來看了一下原本的問題,才發現有更簡單的作法:sqrt( (給定像素 * 原長) / 原寬 )
那就會變成是:sqrt( (300000 * 800) / 600 )
。算式導入後會變成 632.455...。因此 800×600 在 300000 像素下的新等比長為 632。
很神奇,但為什麼呢?