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 !

7voto

Arthur da Paz Points 91

Juste au cas où vous seriez un fanatique de la performance...

La manière la plus rapide (en JavaScript) de calculer un rapport de rectangle est d'utiliser un véritable algorithme binaire du Grand Diviseur Commun.

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

Le 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]
*/

4voto

Zargold Points 644

Voici ma solution, elle est assez simple puisque tout ce qui m'intéresse n'est pas nécessairement le GCD ou même des ratios précis : parce qu'alors vous obtenez des choses bizarres comme 345/113 qui ne sont pas compréhensibles pour l'homme.

En gros, je définis des ratios acceptables pour le paysage ou le portrait et leur "valeur" en tant que valeur flottante... Je compare ensuite ma version flottante du ratio à chacun d'eux et celui qui présente la plus petite différence de valeur absolue est le ratio le plus proche de l'article. De cette façon, lorsque l'utilisateur rend l'image 16:9 mais enlève ensuite 10 pixels du bas, l'image est toujours considérée 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'
        return find_closest_ratio(divided)
    except TypeError:
        return None

4voto

Pithikos Points 1227

Vous pouvez toujours commencer par établir une table de correspondance basée sur les rapports d'aspect les plus courants. Vérifier https://en.wikipedia.org/wiki/Display_aspect_ratio Il suffit alors de faire la division

Pour les problèmes réels, vous pouvez faire quelque chose comme ci-dessous

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

Il suffit ensuite d'indiquer les dimensions dans n'importe quel ordre

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

1voto

mouviciel Points 36624

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

1voto

drovnik Points 21

Je suppose que vous parlez ici de vidéo, auquel cas vous devez également vous préoccuper du rapport d'aspect des pixels de la vidéo source. Par exemple.

La résolution du PAL DV est de 720x576. Ce qui donne l'impression d'un format 4:3. Or, selon le rapport d'aspect du pixel (PAR), le rapport d'écran peut être de 4:3 ou de 16:9.

Pour plus d'informations, cliquez ici http://en.wikipedia.org/wiki/Pixel_aspect_ratio

Vous pouvez obtenir un rapport d'aspect en pixels carrés, et c'est le cas d'une grande partie des vidéos sur le web, mais vous voudrez peut-être faire attention aux autres cas.

J'espère que cela vous aidera

Marque

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