我正在尝试获取照片的宽高比,但下面的代码显示了宽度为3776,高度为2520(472:315)的照片上的宽高比错误,但它在3968的照片上显示正确的宽高比宽度和高度2232(16:9)。
function gcd($a, $b) {
if($a == 0 || $b == 0) {
return abs(max(abs($a), abs($b)));
}
$r = $a % $b;
return ($r != 0) ? gcd($b, $r) : abs($b);
}
$gcd = gcd($widtho, $heighto);
echo ($widtho / $gcd).':'.($heighto / $gcd);
如何解决我的问题?
提前致谢。
答案 0 :(得分:4)
实际上,3780x2520的宽高比为3:2;因为你使用3776作为宽度,472:315是正确的比例。如果你进行划分,它会达到1.498,这非常接近1.5,考虑四舍五入到3:2。
如果您只想要“标准”比率(例如“3:2”或“16:9”),您可以将检测到的比率传递给另一个对其进行舍入的函数,以找到最近/最佳匹配。
这是一个可以为您进行舍入的抛出函数(仅根据示例中的维度进行测试,因此我无法保证100%成功):
function findBestMatch($ratio) {
$commonRatios = array(
array(1, '1:1'), array((4 / 3), '4:3'), array((3 / 2), '3:2'),
array((5 / 3), '5:3'), array((16 / 9), '16:9'), array(3, '3')
);
list($numerator, $denominator) = explode(':', $ratio);
$value = $numerator / $denominator;
$end = (count($commonRatios) - 1);
for ($i = 0; $i < $end; $i++) {
if ($value == $commonRatios[$i][0]) {
// we have an equal-ratio; no need to check anything else!
return $commonRatios[$i][1];
} else if ($value < $commonRatios[$i][0]) {
// this can only happen if the ratio is `< 1`
return $commonRatios[$i][1];
} else if (($value > $commonRatios[$i][0]) && ($value < $commonRatios[$i + 1][0])) {
// the ratio is in-between the current common-ratio and the next in the list
// find whichever one it's closer-to and return that one.
return (($value - $commonRatios[$i][0]) < ($commonRatios[$i + 1][0] - $value)) ? $commonRatios[$i][1] : $commonRatios[$i + 1][1];
}
}
// we didn't find a match; that means we have a ratio higher than our biggest common one
// return the original value
return $ratio;
}
要使用此功能,请将比率字符串(不是数字值)传递给它,它将尝试在常用比率列表中“找到最佳匹配”。
使用示例:
$widtho = 3968;
$heighto = 2232;
$gcd = gcd($widtho, $heighto);
$ratio = ($widtho / $gcd).':'.($heighto / $gcd);
echo 'found: ' . $ratio . "\n";
echo 'match: ' . findBestMatch($ratio) . "\n";
$widtho = 3776;
$heighto = 2520;
$gcd = gcd($widtho, $heighto);
$ratio = ($widtho / $gcd).':'.($heighto / $gcd);
echo 'found: ' . $ratio . "\n";
echo 'match: ' . findBestMatch($ratio) . "\n";
$widtho = 3780;
$heighto = 2520;
$gcd = gcd($widtho, $heighto);
$ratio = ($widtho / $gcd).':'.($heighto / $gcd);
echo 'found: ' . $ratio . "\n";
echo 'match: ' . findBestMatch($ratio) . "\n";
以上测试将输出以下内容:
found: 16:9
match: 16:9
found: 472:315
match: 3:2
found: 3:2
match: 3:2
*如果您想要参考,我从wikipedia获取了“标准”宽高比列表。
答案 1 :(得分:1)
我发现this gist在Javascript中效果很好。所以我将其移植到PHP。
/**
* Returns the nearest aspect ratio of a width and height within a limited range of possible aspect ratios.
* In other words, while 649x360 technically has an aspect ratio of 649:360,
* it’s often useful to know that the nearest normal aspect ratio is actually 9:5 (648x360).
* @param $width
* @param $height
* @param int $side The nearest ratio to side with. A number higher than zero
* tells the function to always return the nearest ratio that is equal or higher
* than the actual ratio, whereas a smaller number returns the nearest ratio higher
* that is equal or smaller than the actual ratio. Defaults to 0.
* @param int $maxW The maximum width in the nearest normal aspect ratio. Defaults to 16.
* @param int $maxH The maximum height in the nearest normal aspect ratio. Defaults to 16.
* @return string|null
*/
function closestAspectRatio($width, $height, $side = 0, $maxW = 16, $maxH = 16) {
$ratiosT = [];
$ratios = [];
$ratio = ($width * 100) / ($height * 100);
$maxW++;
$maxH++;
for ($w = 1; $w < $maxW; $w++) {
for ($h = 1; $h < $maxH; $h++) {
$ratioX = strval(($w * 100) / ($h * 100));
if (!array_key_exists($ratioX, $ratiosT)) {
$ratiosT[$ratioX] = TRUE;
$ratios[$w . ':' . $h] = $ratioX;
}
}
}
$match = NULL;
foreach ($ratios as $key => $value) {
if (!$match || (!$side && abs($ratio - $value) < abs($ratio - $ratios[$match])
) || (
$side < 0 && $value <= $ratio && abs($ratio - $value) < abs($ratio - $ratios[$match])
) || (
$side > 0 && $value >= $ratio && abs($ratio - $value) < abs($ratio - $ratios[$match])
)) {
$match = $key;
}
}
return $match;
}
以这种方式使用(带有所有参数):
print closestAspectRatio(3776, 2520, 0, 16, 16); // prints 3:2
print closestAspectRatio(2520, 3776, 0, 16, 16); // prints 2:3
以下是JS演示供参考:
console.log('3776 x 2520 = ' + nearestNormalAspectRatio(3776, 2520, 0));
console.log('2520 x 3776 = ' + nearestNormalAspectRatio(2520, 3776, 0));
function nearestNormalAspectRatio(width, height, side) {
var
ratio = (width * 100) / (height * 100),
maxW = 3 in arguments ? arguments[2] : 16,
maxH = 4 in arguments ? arguments[3] : 16,
ratiosW = new Array(maxW).join(',').split(','),
ratiosH = new Array(maxH).join(',').split(','),
ratiosT = {},
ratios = {},
match,
key;
ratiosW.forEach(function(empty, ratioW) {
++ratioW;
ratiosH.forEach(function(empty, ratioH) {
++ratioH;
ratioX = (ratioW * 100) / (ratioH * 100);
if (!ratiosT[ratioX]) {
ratiosT[ratioX] = true;
ratios[ratioW + ':' + ratioH] = ratioX;
}
});
});
for (key in ratios) {
if (!match || (!side && Math.abs(ratio - ratios[key]) < Math.abs(ratio - ratios[match])) || (
side < 0 && ratios[key] <= ratio && Math.abs(ratio - ratios[key]) < Math.abs(ratio - ratios[match])
) || (
side > 0 && ratios[key] >= ratio && Math.abs(ratio - ratios[key]) < Math.abs(ratio - ratios[match])
)) {
match = key;
}
}
return match;
}