Quel est l'algorithme pour calculer le rapport d'aspect? J'ai besoin d'une sortie comme: 4:3, 16:9

j'ai l'intention de l'utiliser avec javascript pour recadrer une image pour s'adapter à toute la fenêtre.

Edit: je vais utiliser un composant de 3ème partie qui n'accepte que le rapport d'aspect dans le format comme: 4:3, 16:9

62
demandé sur Cœur 2009-07-27 08:20:49

15 réponses

j'ai cru comprendre que vous cherchiez une solution integer:integer comme 16:9 plutôt qu'une solution float:1 comme 1.77778:1 .

si oui, ce que vous devez faire est de trouver le plus grand diviseur commun (GCD) et diviser les deux valeurs par cela. Le GCD est le nombre le plus élevé qui divise également les deux nombres. Donc le GCD pour 6 et 10 est 2, le GCD pour 44 et 99 est 11.

par exemple, un Moniteur 1024x768 a un DCG de 256. Quand vous divisez les deux valeurs par cela vous obtenez 4x3 ou 4:3.

(récursif) algorithme de PGCD:

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 HTML/Javascript complet qui montre une façon de détecter la taille de l'écran et de calculer le rapport d'aspect à partir de cela. Cela fonctionne dans FF3, Je ne suis pas sûr de ce que les autres navigateurs ont pour screen.width et 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>

mon étrange moniteur à écran large):

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

autres que j'ai testé sur:

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'aimerais avoir cette dernière à 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 supporté par votre outil de redimensionnement graphique est une autre question. Je pense que le meilleur pari là serait d'ajouter des lignes de boxe aux lettres (comme ceux que vous obtenez en haut et en bas de votre vieille TV quand vous regardez un film grand écran dessus). Je les ajouterais en haut / en bas ou sur les côtés (selon le nombre le moins élevé de lignes de boxe) jusqu'à ce que l'image réponde aux exigences.

une chose que vous pourriez vouloir considérer est la qualité d'une image qui a été changée de 16:9 à 5:4 - je me souviens encore de l'incroyablement grand, les cow-boys minces que je regardais dans ma jeunesse à la télévision avant la lettre-boxe a été introduit. Vous avez peut-être mieux d'avoir une image par rapport d'aspect et il suffit de redimensionner la bonne pour les dimensions réelles de l'écran avant de l'envoyer vers le bas du fil.

162
répondu paxdiablo 2016-09-19 17:44:31
aspectRatio = width / height

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

widthT = heightT * aspectRatio
heightT = widthT / aspectRatio
35
répondu Gishu 2018-03-26 15:03:44

la réponse de paxdiablo est grande, mais il y a beaucoup de résolutions communes qui ont juste quelques pixels plus ou moins dans une direction donnée, et la plus grande approche de diviseur commun leur donne d'horribles résultats.

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

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

on voudrait arrondir ce rapport 683: 384 au rapport le plus proche, 16:9.

j'ai écrit un script python qui analyse un fichier texte avec des nombres collés de la page Steam Hardware survey, et imprime toutes les résolutions et les rapports les plus proches connus, ainsi que la prévalence de chaque rapport (ce qui était mon but lorsque j'ai commencé cela):

# 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, ce sont la prévalence de l'écran rapports parmi les utilisateurs de vapeur (en date d'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%
12
répondu Petrucio 2012-11-20 03:39:17

je suppose que vous voulez décider qui de 4:3 et 16:9 est le meilleur ajustement.

function getAspectRatio(width, height) {
    var ratio = width / height;
    return ( Math.abs( ratio - 4 / 3 ) < Math.abs( ratio - 16 / 9 ) ) ? '4:3' : '16:9';
}
10
répondu Chetan Sastry 2009-07-27 05:01:00

je pense que cela fait ce que vous demandez:

webdeveloper.com -fraction décimale à fraction

Largeur / Hauteur vous obtient une décimale, convertie en une fraction avec ":" à la place de '/' vous donne un "ratio".

1
répondu Tobias Cohen 2009-07-27 04:43:43

cet algorithme en Python vous permet d'y accéder en partie.


Dites-moi ce qui se passe si le windows est un drôle de taille.

peut-être que ce que vous devriez avoir est une liste de tous les rapports acceptables (à la composante de tiers). Ensuite, trouvez la correspondance la plus proche de votre fenêtre et renvoyez ce ratio de la liste.

1
répondu Nosredna 2009-07-27 04:52:22

comme solution alternative à la recherche GCD, je vous suggère de vérifier par rapport à un ensemble de valeurs standard. Vous pouvez trouver une liste sur Wikipedia .

1
répondu mouviciel 2009-07-27 04:55:27

je suppose que vous parlez de la vidéo ici, dans ce cas, vous pouvez également avoir à vous soucier du rapport d'aspect pixel de la vidéo source. Exemple.

PAL DV a une résolution de 720x576. Qui ressemblerait à son 4:3. Maintenant, selon le rapport d'aspect de Pixel (PAR) le rapport d'écran peut être soit 4:3 ou 16:9.

pour plus d'informations regardez ici http://en.wikipedia.org/wiki/Pixel_aspect_ratio

vous pouvez obtenir le rapport d'Aspect de pixel Carré, et beaucoup de Vidéo web est que, mais vous pouvez vouloir regarder hors des autres cas.

Espérons que cette aide

marque

1
répondu Mark Lakewood 2009-07-27 05:08:22

basé sur les autres réponses, voici comment j'ai obtenu les nombres dont j'avais besoin en 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')}
1
répondu sleepycal 2013-06-04 16:26:04

juste au cas où vous seriez un monstre de performance...

le moyen le plus rapide (en JavaScript) pour calculer un rapport de rectangle il O utiliser un vrai binaire grand commun algorithme diviseur.

(tous les tests de vitesse et de chronométrage ont été effectués par d'autres, vous pouvez vérifier un benchmark ici: https://lemire.me/blog/2013/12/26/fastest-way-to-compute-the-greatest-common-divisor / )

Voici:

/* 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]
*/
1
répondu Arthur da Paz 2018-05-09 18:43:29
Width / Height

?

0
répondu Frank Schwieterman 2009-07-27 04:22:26

je crois que le rapport d'aspect est la largeur divisée par la hauteur.

 r = w/h
0
répondu Sean A.O. Harney 2009-07-27 04:24:17

un peu d'une manière étrange de faire cela, mais utiliser la résolution comme l'aspect. E. G.

1024: 768

ou vous pouvez essayer

var w = screen.width;
var h = screen.height;
for(var i=1,asp=w/h;i<5000;i++){
  if(asp*i % 1==0){
    i=9999;
    document.write(asp*i,":",1*i);
  }
}
0
répondu Aron 2012-04-17 15:18:26

voici ma solution il est assez simple puisque tout ce qui m'importe n'est pas nécessairement GCD ou même rapports précis: parce qu'alors vous obtenez des choses bizarres comme 345/113 qui ne sont pas compréhensibles par l'homme.

j'ai essentiellement fixé le paysage acceptable, ou les rapports de portrait et leur" valeur " comme un flotteur... Je compare alors ma version flottante du rapport à chaque et qui a jamais la plus faible différence de valeur absolue est le rapport le plus proche de l'article. De cette façon, lorsque le l'utilisateur fait 16: 9 mais supprime alors 10 pixels du bas il compte encore comme 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'
        else:
            return find_closest_ratio(divided)
    except TypeError:
        return None
0
répondu Zargold 2017-03-16 20:22:34

Voici une version du meilleur algorithme d'approximation rationnelle de James Farey avec un niveau réglable de flou porté à javascript à partir du aspect ratio calcul code écrit à l'origine en python.

la méthode prend un flotteur ( 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 de 1035x582 (1.77835051546) à traiter comme 16:9 (1.77777777778) plutôt que 345:194 que vous obtenez avec l'algorithme simple gcd énumérés dans d'autres réponses.

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

le résultat:

 4,3  // (1.33333333333) (800 x 600)
 16,9 // (1.77777777778) (2560.0 x 1440)
 16,9 // (1.77835051546) (1035.0 x 582)
0
répondu ccpizza 2017-03-25 15:53:08