算长宽比的算法是什么?我需要输出如:4:3,16:9

Nat*_*han 74 javascript algorithm crop aspect-ratio

我打算用javascript来裁剪图像以适应整个窗口.

编辑:我将使用仅接受宽高比的第三方组件,格式如:4:3,16:9

pax*_*blo 182

我想你正在寻找一个可用的宽高比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)
Run Code Online (Sandbox Code Playgroud)

在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));
}
Run Code Online (Sandbox Code Playgroud)

这里有一些完整的HTML/Javascript,它显示了一种检测屏幕大小并从中计算宽高比的方法.这适用于FF3,我不确定其他浏览器的支持screen.widthscreen.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>
Run Code Online (Sandbox Code Playgroud)

它输出(在我奇怪的宽屏显示器上):

Dimensions = 1680 x 1050
Gcd        = 210
Aspect     = 8:5
Run Code Online (Sandbox Code Playgroud)

我测试过的其他人:

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
Run Code Online (Sandbox Code Playgroud)

我希望我在家里有最后一个但不,不幸的是,这是一台工作机器.

如果您发现图形调整大小工具不支持纵横比,您所做的就是另一回事.我怀疑最好的选择是添加letter-boxing系列(就像你在观看宽屏电影时在旧电视的顶部和底部获得的那些).我会将它们添加到顶部/底部或两侧(无论哪一个导致最少数量的字母装箱线),直到图像符合要求.

你可能想要考虑的一件事是画面的质量从16:9变为5:4 - 我还记得我曾经在电视拳击介绍之前在电视上看到的那些高大瘦弱的牛仔.您可能最好在每个宽高比下使用一个不同的图像,并在将其发送到电线之前调整实际屏幕尺寸的正确尺寸.

  • 似乎是矫枉过正。它不适用于 Nosredna 提到的情况。我有一个基于近似的解决方案。 (2认同)

Gis*_*shu 42

aspectRatio = width / height
Run Code Online (Sandbox Code Playgroud)

如果这就是你所追求的.然后,您可以将其乘以目标空间的一个维度,以找出另一个(维持比率),例如

widthT = heightT * aspectRatio
heightT = widthT / aspectRatio
Run Code Online (Sandbox Code Playgroud)


Pet*_*cio 12

paxdiablo的答案很棒,但是有很多常见的分辨率在给定方向上只有几个或多或少的像素,并且最常见的除数方法给它们带来了可怕的结果.

以1360x765的良好分辨率为例,使用gcd方法提供了16:9的良好比例.根据Steam的说法,这个分辨率只有0.01%的用户使用,而1366x768则用于18.9%的用户.让我们看一下使用gcd方法得到的东西:

1360x765 - 16:9 (0.01%)
1360x768 - 85:48 (2.41%)
1366x768 - 683:384 (18.9%)
Run Code Online (Sandbox Code Playgroud)

我们希望将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]) + '%')
Run Code Online (Sandbox Code Playgroud)

对于好奇的人来说,这些是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%
Run Code Online (Sandbox Code Playgroud)


Che*_*try 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';
}
Run Code Online (Sandbox Code Playgroud)


ccp*_*zza 8

James Farey 的最佳有理近似算法具有可调整的模糊程度,从最初用 Python 编写的纵横比计算代码移植到 Javascript 。

该方法采用浮点数 ( width/height) 和分数分子/分母的上限。

在下面的示例中,我设置了上限,50因为我需要将1035x582(1.77835051546) 视为16:9(1.77777777778) 而不是345:194您使用gcd其他答案中列出的普通算法获得的上限。

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;
        }
    }
}

console.log(aspect_ratio(801/600, 50));
console.log(aspect_ratio(1035/582, 50));
console.log(aspect_ratio(2560/1441, 50));
Run Code Online (Sandbox Code Playgroud)


小智 7

以防万一你是一个表演狂......

计算矩形比率的最快方法(在 JavaScript 中)是使用真正的二进制大公约数算法。

(所有速度和计时测试均已由其他人完成,您可以在此处查看一个基准测试: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]
*/
Run Code Online (Sandbox Code Playgroud)