108 votes

Quel est l'algorithme de calcul du rapport hauteur/largeur ?

Je prévois de l'utiliser avec JavaScript pour recadrer une image afin qu'elle s'adapte à l'ensemble de la fenêtre.

Editer : J'utiliserai un composant tiers qui n'accepte que le rapport d'aspect dans un format tel que : 4:3 , 16:9 .

~12 ans edit : ce genre de question est plutôt intéressant ! Il y a quelque chose ici, n'est-ce pas ? Absolument !

236voto

paxdiablo Points 341644

J'en déduis que vous recherchez un rapport d'aspect utilisable integer:integer solution comme 16:9 plutôt qu'un float:1 solution comme 1.77778:1 .

Si c'est le cas, vous devez trouver le plus grand diviseur commun (PGCD) et diviser les deux valeurs par ce dernier. Le PGCD est le nombre le plus élevé qui divise également les deux nombres. Ainsi, le PGCD de 6 et 10 est 2, celui de 44 et 99 est 11.

Par exemple, un moniteur 1024x768 a un GCD de 256. En divisant les deux valeurs par ce chiffre, on obtient 4x3 ou 4:3.

Un algorithme GCD (récursif) :

function gcd (a,b):
    if b == 0:
        return a
    return gcd (b, a mod b)

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

Et voici quelques pages HTML/Javascript complètes qui montrent une façon de détecter la taille de l'écran et de calculer le rapport hauteur/largeur à partir de celle-ci. Cela fonctionne avec FF3, je ne sais pas si les autres navigateurs prennent en charge le format screen.width y 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>

Il sort (sur mon moniteur bizarre à écran large) :

Dimensions = 1680 x 1050
Gcd        = 210
Aspect     = 8:5

D'autres personnes sur lesquelles j'ai testé cette méthode :

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

J'aurais aimé avoir ce dernier à la maison, mais non, c'est une machine de travail, malheureusement.

Ce que vous faites si vous découvrez que le rapport d'aspect n'est pas pris en charge par votre outil de redimensionnement graphique est une autre affaire. Je pense que la meilleure solution serait d'ajouter des lignes de letter-boxing (comme celles que vous voyez en haut et en bas de votre vieux téléviseur lorsque vous regardez un film à écran large). Je les ajouterais en haut/en bas ou sur les côtés (selon ce qui produit le moins de lignes de letter-boxing) jusqu'à ce que l'image réponde aux exigences.

Je me souviens encore des cow-boys incroyablement grands et minces que je regardais dans ma jeunesse à la télévision avant l'introduction du letter-boxing. Il est peut-être préférable d'avoir une image différente par format et de redimensionner la bonne image en fonction des dimensions réelles de l'écran avant de l'envoyer sur le câble.

76voto

Gishu Points 59012
aspectRatio = width / height

si c'est ce que vous recherchez. Vous pouvez ensuite le multiplier par l'une des dimensions de l'espace cible pour trouver l'autre (ce qui maintient le rapport). par exemple

widthT = heightT * aspectRatio
heightT = widthT / aspectRatio

16voto

Petrucio Points 1613

La réponse de paxdiablo est excellente, mais il y a beaucoup de résolutions courantes qui n'ont que quelques pixels de plus ou de moins dans une direction donnée, et l'approche du plus grand diviseur commun donne des résultats horribles pour ces résolutions.

Prenons par exemple la résolution de 1360x765 qui donne un beau rapport 16:9 en utilisant l'approche du pgcd. Selon Steam, cette résolution n'est utilisée que par 0,01 % des utilisateurs, tandis que la résolution 1366x768 est utilisée par 18,9 % des utilisateurs. Voyons ce que nous obtenons en utilisant l'approche gcd :

1360x765 - 16:9 (0.01%)
1360x768 - 85:48 (2.41%)
1366x768 - 683:384 (18.9%)

Nous devrions arrondir le rapport 683:384 au rapport 16:9 le plus proche.

J'ai écrit un script en python qui analyse un fichier texte avec des chiffres collés depuis la page d'enquête Steam Hardware, et qui imprime toutes les résolutions et les ratios connus les plus proches, ainsi que la prévalence de chaque ratio (ce qui était mon objectif quand j'ai commencé) :

# 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]) + '%')

Pour les curieux, il s'agit de la prévalence des ratios d'écran parmi les utilisateurs de Steam (en octobre 2012) :

16:9 -> 58.9%
16:10 -> 24.0%
5:4 -> 9.57%
4:3 -> 6.38%
5:3 -> 0.84%
17:9 -> 0.11%

12voto

Chetan Sastry Points 14742

Je suppose que vous voulez décider lequel des formats 4:3 et 16:9 est le mieux adapté.

function getAspectRatio(width, height) {
    var ratio = width / height;
    return ( Math.abs( ratio - 4 / 3 ) < Math.abs( ratio - 16 / 9 ) ) ? '4:3' : '16:9';
}

11voto

ccpizza Points 2653

L'algorithme de meilleure approximation rationnelle de James Farey avec un niveau de flou ajustable, porté en Javascript depuis l'application code de calcul du rapport d'aspect écrit à l'origine en python.

La méthode prend un nombre flottant ( width/height ) et une limite supérieure pour la fraction numérateur/dénominateur.

Dans l'exemple ci-dessous, je fixe une limite supérieure de 50 parce que j'ai besoin 1035x582 (1,77835051546) à traiter comme 16:9 (1,77777777778) au lieu de 345:194 que l'on obtient avec le simple gcd algorithme énuméré dans d'autres réponses.

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('801x600:', aspect_ratio(801/600, 50));
console.log('1035x582:', aspect_ratio(1035/582, 50));
console.log('2560x1441:', aspect_ratio(2560/1441, 50));

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X