我计划将其与JavaScript配合使用以裁剪图像以适合整个窗口。
编辑:我将使用仅接受如下形式的长宽比的第三方组件:4:3
,16:9
。
Answers:
我发现您正在寻找integer:integer
像这样的可用长宽比解决方案,16:9
而不是float:1
像这样的解决方案1.77778:1
。
如果是这样,您需要做的就是找到最大公约数(GCD)并将其除以两个值。GCD是将两个数字均分的最高数字。因此6和10的GCD为2,44和99的GCD为11。
例如,一个1024x768显示器的GCD为256。如果将两个值除以该值,则得到4x3或4:3。
(递归)GCD算法:
function gcd (a,b):
if b == 0:
return a
return gcd (b, a mod b)
在C中:
static int gcd (int a, int b) {
return (b == 0) ? a : gcd (b, a%b);
}
int main(void) {
printf ("gcd(1024,768) = %d\n",gcd(1024,768));
}
这是一些完整的HTML / Javascript,它显示了一种检测屏幕尺寸并从中计算纵横比的方法。这在FF3中有效,我不确定其他浏览器对screen.width
和的支持screen.height
。
<html><body>
<script type="text/javascript">
function gcd (a, b) {
return (b == 0) ? a : gcd (b, a%b);
}
var w = screen.width;
var h = screen.height;
var r = gcd (w, h);
document.write ("<pre>");
document.write ("Dimensions = ", w, " x ", h, "<br>");
document.write ("Gcd = ", r, "<br>");
document.write ("Aspect = ", w/r, ":", h/r);
document.write ("</pre>");
</script>
</body></html>
它输出(在我怪异的宽屏显示器上):
Dimensions = 1680 x 1050
Gcd = 210
Aspect = 8:5
我测试过的其他人:
Dimensions = 1280 x 1024
Gcd = 256
Aspect = 5:4
Dimensions = 1152 x 960
Gcd = 192
Aspect = 6:5
Dimensions = 1280 x 960
Gcd = 320
Aspect = 4:3
Dimensions = 1920 x 1080
Gcd = 120
Aspect = 16:9
我希望我能在家里有最后一个,但不幸的是,这是一台工作机器。
如果您发现图形调整大小工具不支持长宽比,该怎么办是另一回事。我怀疑最好的选择是添加字母装订线(就像您在旧电视上观看宽屏电影时在顶部和底部看到的那样)。我将它们添加到顶部/底部或侧面(以导致信箱装箱数量最少的方式为准),直到图像满足要求为止。
您可能要考虑的一件事是,图像的质量已从16:9更改为5:4-我仍然记得在引入信箱技术之前,我在电视上看过的那年高个子,瘦小的牛仔。您最好在每高宽比上拥有一张不同的图像,而只是将实际尺寸调整为适合实际屏幕尺寸的尺寸,然后再将其发送出去。
728x90
->364:45
不确定结果是否理想
paxdiablo的答案很好,但是有许多常见的分辨率,在给定的方向上或多或少只有几个像素,最大的除数方法给他们带来了可怕的结果。
以表现良好的1360x765分辨率为例,该分辨率使用gcd方法可提供很好的16:9比率。根据Steam的说法,只有0.01%的用户使用此分辨率,而高达18.9%的用户使用1366x768。让我们看看使用gcd方法可以得到什么:
1360x765 - 16:9 (0.01%)
1360x768 - 85:48 (2.41%)
1366x768 - 683:384 (18.9%)
我们想将683:384的比例四舍五入到最接近的16:9比例。
我编写了一个python脚本,该脚本使用Steam硬件调查页面中的粘贴数字来解析文本文件,并打印所有分辨率和最接近的已知比率,以及每个比率的普遍性(这是我开始这样做时的目标):
# Contents pasted from store.steampowered.com/hwsurvey, section 'Primary Display Resolution'
steam_file = './steam.txt'
# Taken from http://upload.wikimedia.org/wikipedia/commons/thumb/f/f0/Vector_Video_Standards4.svg/750px-Vector_Video_Standards4.svg.png
accepted_ratios = ['5:4', '4:3', '3:2', '8:5', '5:3', '16:9', '17:9']
#-------------------------------------------------------
def gcd(a, b):
if b == 0: return a
return gcd (b, a % b)
#-------------------------------------------------------
class ResData:
#-------------------------------------------------------
# Expected format: 1024 x 768 4.37% -0.21% (w x h prevalence% change%)
def __init__(self, steam_line):
tokens = steam_line.split(' ')
self.width = int(tokens[0])
self.height = int(tokens[2])
self.prevalence = float(tokens[3].replace('%', ''))
# This part based on pixdiablo's gcd answer - http://stackoverflow.com/a/1186465/828681
common = gcd(self.width, self.height)
self.ratio = str(self.width / common) + ':' + str(self.height / common)
self.ratio_error = 0
# Special case: ratio is not well behaved
if not self.ratio in accepted_ratios:
lesser_error = 999
lesser_index = -1
my_ratio_normalized = float(self.width) / float(self.height)
# Check how far from each known aspect this resolution is, and take one with the smaller error
for i in range(len(accepted_ratios)):
ratio = accepted_ratios[i].split(':')
w = float(ratio[0])
h = float(ratio[1])
known_ratio_normalized = w / h
distance = abs(my_ratio_normalized - known_ratio_normalized)
if (distance < lesser_error):
lesser_index = i
lesser_error = distance
self.ratio_error = distance
self.ratio = accepted_ratios[lesser_index]
#-------------------------------------------------------
def __str__(self):
descr = str(self.width) + 'x' + str(self.height) + ' - ' + self.ratio + ' - ' + str(self.prevalence) + '%'
if self.ratio_error > 0:
descr += ' error: %.2f' % (self.ratio_error * 100) + '%'
return descr
#-------------------------------------------------------
# Returns a list of ResData
def parse_steam_file(steam_file):
result = []
for line in file(steam_file):
result.append(ResData(line))
return result
#-------------------------------------------------------
ratios_prevalence = {}
data = parse_steam_file(steam_file)
print('Known Steam resolutions:')
for res in data:
print(res)
acc_prevalence = ratios_prevalence[res.ratio] if (res.ratio in ratios_prevalence) else 0
ratios_prevalence[res.ratio] = acc_prevalence + res.prevalence
# Hack to fix 8:5, more known as 16:10
ratios_prevalence['16:10'] = ratios_prevalence['8:5']
del ratios_prevalence['8:5']
print('\nSteam screen ratio prevalences:')
sorted_ratios = sorted(ratios_prevalence.items(), key=lambda x: x[1], reverse=True)
for value in sorted_ratios:
print(value[0] + ' -> ' + str(value[1]) + '%')
出于好奇,以下是Steam用户中屏幕比例的普遍性(截至2012年10月):
16:9 -> 58.9%
16:10 -> 24.0%
5:4 -> 9.57%
4:3 -> 6.38%
5:3 -> 0.84%
17:9 -> 0.11%
我猜您想确定4:3和16:9中的哪一个最合适。
function getAspectRatio(width, height) {
var ratio = width / height;
return ( Math.abs( ratio - 4 / 3 ) < Math.abs( ratio - 16 / 9 ) ) ? '4:3' : '16:9';
}
这是James Farey最佳有理逼近算法的一个版本,具有可调整的模糊度,从宽高比计算代码移植到javascript最初用python编写。
该方法采用浮点数(width/height
)和分数分子/分母的上限。
在下面的示例中,我设置了一个上限,50
因为我需要将1035x582
(1.77835051546)视为16:9
(1.77777777778),而不是345:194
使用gcd
其他答案中列出的普通算法获得的上限。
<html>
<body>
<script type="text/javascript">
function aspect_ratio(val, lim) {
var lower = [0, 1];
var upper = [1, 0];
while (true) {
var mediant = [lower[0] + upper[0], lower[1] + upper[1]];
if (val * mediant[1] > mediant[0]) {
if (lim < mediant[1]) {
return upper;
}
lower = mediant;
} else if (val * mediant[1] == mediant[0]) {
if (lim >= mediant[1]) {
return mediant;
}
if (lower[1] < upper[1]) {
return lower;
}
return upper;
} else {
if (lim < mediant[1]) {
return lower;
}
upper = mediant;
}
}
}
document.write (aspect_ratio(800 / 600, 50) +"<br/>");
document.write (aspect_ratio(1035 / 582, 50) + "<br/>");
document.write (aspect_ratio(2560 / 1440, 50) + "<br/>");
</script>
</body></html>
结果:
4,3 // (1.33333333333) (800 x 600)
16,9 // (1.77777777778) (2560.0 x 1440)
16,9 // (1.77835051546) (1035.0 x 582)
万一你是个表演狂...
计算JavaScript矩形比例的最快方法(使用JavaScript)使用真正的二进制Great Common Divisor算法。
(所有速度和计时测试均由其他人完成,您可以在此处检查一个基准测试:https://lemire.me/blog/2013/12/26/fastest-way-to-compute-the-greatest-common-divisor /)
就这个:
/* the binary Great Common Divisor calculator */
function gcd (u, v) {
if (u === v) return u;
if (u === 0) return v;
if (v === 0) return u;
if (~u & 1)
if (v & 1)
return gcd(u >> 1, v);
else
return gcd(u >> 1, v >> 1) << 1;
if (~v & 1) return gcd(u, v >> 1);
if (u > v) return gcd((u - v) >> 1, v);
return gcd((v - u) >> 1, u);
}
/* returns an array with the ratio */
function ratio (w, h) {
var d = gcd(w,h);
return [w/d, h/d];
}
/* example */
var r1 = ratio(1600, 900);
var r2 = ratio(1440, 900);
var r3 = ratio(1366, 768);
var r4 = ratio(1280, 1024);
var r5 = ratio(1280, 720);
var r6 = ratio(1024, 768);
/* will output this:
r1: [16, 9]
r2: [8, 5]
r3: [683, 384]
r4: [5, 4]
r5: [16, 9]
r6: [4, 3]
*/
这是我的解决方案,非常简单,因为我所关心的不一定是GCD甚至是准确的比率:因为这样,您会得到诸如345/113之类的怪异东西,这是人类无法理解的。
我基本上将可接受的横向或纵向比率及其“值”设置为浮动值,然后将比率的浮动版本与每个比率进行比较,并且绝对值差最低的是最接近该项的比率。这样,当用户将其设为16:9却又从底部移除10个像素时,它仍然算作16:9 ...
accepted_ratios = {
'landscape': (
(u'5:4', 1.25),
(u'4:3', 1.33333333333),
(u'3:2', 1.5),
(u'16:10', 1.6),
(u'5:3', 1.66666666667),
(u'16:9', 1.77777777778),
(u'17:9', 1.88888888889),
(u'21:9', 2.33333333333),
(u'1:1', 1.0)
),
'portrait': (
(u'4:5', 0.8),
(u'3:4', 0.75),
(u'2:3', 0.66666666667),
(u'10:16', 0.625),
(u'3:5', 0.6),
(u'9:16', 0.5625),
(u'9:17', 0.5294117647),
(u'9:21', 0.4285714286),
(u'1:1', 1.0)
),
}
def find_closest_ratio(ratio):
lowest_diff, best_std = 9999999999, '1:1'
layout = 'portrait' if ratio < 1.0 else 'landscape'
for pretty_str, std_ratio in accepted_ratios[layout]:
diff = abs(std_ratio - ratio)
if diff < lowest_diff:
lowest_diff = diff
best_std = pretty_str
return best_std
def extract_ratio(width, height):
try:
divided = float(width)/float(height)
if divided == 1.0: return '1:1'
return find_closest_ratio(divided)
except TypeError:
return None
我假设您在这里谈论视频,在这种情况下,您可能还需要担心源视频的像素长宽比。例如。
PAL DV的分辨率为720x576。看起来像是4:3。现在,根据像素长宽比(PAR),屏幕比例可以为4:3或16:9。
有关更多信息,请参见此处http://en.wikipedia.org/wiki/Pixel_aspect_ratio
您可以获得正方形像素的纵横比,而很多网络视频就是这样,但是您可能需要避免其他情况。
希望这可以帮助
标记
根据其他答案,这是我如何获取Python中所需的数字;
from decimal import Decimal
def gcd(a,b):
if b == 0:
return a
return gcd(b, a%b)
def closest_aspect_ratio(width, height):
g = gcd(width, height)
x = Decimal(str(float(width)/float(g)))
y = Decimal(str(float(height)/float(g)))
dec = Decimal(str(x/y))
return dict(x=x, y=y, dec=dec)
>>> closest_aspect_ratio(1024, 768)
{'y': Decimal('3.0'),
'x': Decimal('4.0'),
'dec': Decimal('1.333333333333333333333333333')}
就我而言,我想要类似
[10,5,15,20,25]-> [2,1,3,4,5]
function ratio(array){
let min = Math.min(...array);
let ratio = array.map((element)=>{
return element/min;
});
return ratio;
}
document.write(ratio([10,5,15,20,25])); // [ 2, 1, 3, 4, 5 ]
您始终可以根据常见的宽高比创建查找表。检查https://en.wikipedia.org/wiki/Display_aspect_ratio然后您可以简单地进行划分
对于现实生活中的问题,您可以执行以下操作
let ERROR_ALLOWED = 0.05
let STANDARD_ASPECT_RATIOS = [
[1, '1:1'],
[4/3, '4:3'],
[5/4, '5:4'],
[3/2, '3:2'],
[16/10, '16:10'],
[16/9, '16:9'],
[21/9, '21:9'],
[32/9, '32:9'],
]
let RATIOS = STANDARD_ASPECT_RATIOS.map(function(tpl){return tpl[0]}).sort()
let LOOKUP = Object()
for (let i=0; i < STANDARD_ASPECT_RATIOS.length; i++){
LOOKUP[STANDARD_ASPECT_RATIOS[i][0]] = STANDARD_ASPECT_RATIOS[i][1]
}
/*
Find the closest value in a sorted array
*/
function findClosest(arrSorted, value){
closest = arrSorted[0]
closestDiff = Math.abs(arrSorted[0] - value)
for (let i=1; i<arrSorted.length; i++){
let diff = Math.abs(arrSorted[i] - value)
if (diff < closestDiff){
closestDiff = diff
closest = arrSorted[i]
} else {
return closest
}
}
return arrSorted[arrSorted.length-1]
}
/*
Estimate the aspect ratio based on width x height (order doesn't matter)
*/
function estimateAspectRatio(dim1, dim2){
let ratio = Math.max(dim1, dim2) / Math.min(dim1, dim2)
if (ratio in LOOKUP){
return LOOKUP[ratio]
}
// Look by approximation
closest = findClosest(RATIOS, ratio)
if (Math.abs(closest - ratio) <= ERROR_ALLOWED){
return '~' + LOOKUP[closest]
}
return 'non standard ratio: ' + Math.round(ratio * 100) / 100 + ':1'
}
然后,您只需按任意顺序给出尺寸
estimateAspectRatio(1920, 1080) // 16:9
estimateAspectRatio(1920, 1085) // ~16:9
estimateAspectRatio(1920, 1150) // non standard ratio: 1.65:1
estimateAspectRatio(1920, 1200) // 16:10
estimateAspectRatio(1920, 1220) // ~16:10